Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4e3da467 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branch 'sched/cputime' of...

Merge branch 'sched/cputime' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/linux-dynticks

 into sched/core

Pull cputime changes from Frederic Weisbecker:

  * Generalize exception handling

  * Fix race in context tracking state restore on return from exception
    and irq exit kernel preemption

  * Fix cputime scaling in full dynticks accounting dynamic off-case

  * Fix default Kconfig value

Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 27b4b931 8b438766
Loading
Loading
Loading
Loading
+0 −21
Original line number Original line Diff line number Diff line
#ifndef _ASM_X86_CONTEXT_TRACKING_H
#ifndef _ASM_X86_CONTEXT_TRACKING_H
#define _ASM_X86_CONTEXT_TRACKING_H
#define _ASM_X86_CONTEXT_TRACKING_H


#ifndef __ASSEMBLY__
#include <linux/context_tracking.h>
#include <asm/ptrace.h>

static inline void exception_enter(struct pt_regs *regs)
{
	user_exit();
}

static inline void exception_exit(struct pt_regs *regs)
{
#ifdef CONFIG_CONTEXT_TRACKING
	if (user_mode(regs))
		user_enter();
#endif
}

#else /* __ASSEMBLY__ */

#ifdef CONFIG_CONTEXT_TRACKING
#ifdef CONFIG_CONTEXT_TRACKING
# define SCHEDULE_USER call schedule_user
# define SCHEDULE_USER call schedule_user
#else
#else
# define SCHEDULE_USER call schedule
# define SCHEDULE_USER call schedule
#endif
#endif


#endif /* !__ASSEMBLY__ */

#endif
#endif
+5 −3
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@
 *   Authors: Anthony Liguori <aliguori@us.ibm.com>
 *   Authors: Anthony Liguori <aliguori@us.ibm.com>
 */
 */


#include <linux/context_tracking.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/kvm_para.h>
#include <linux/kvm_para.h>
@@ -43,7 +44,6 @@
#include <asm/apicdef.h>
#include <asm/apicdef.h>
#include <asm/hypervisor.h>
#include <asm/hypervisor.h>
#include <asm/kvm_guest.h>
#include <asm/kvm_guest.h>
#include <asm/context_tracking.h>


static int kvmapf = 1;
static int kvmapf = 1;


@@ -254,16 +254,18 @@ EXPORT_SYMBOL_GPL(kvm_read_and_reset_pf_reason);
dotraplinkage void __kprobes
dotraplinkage void __kprobes
do_async_page_fault(struct pt_regs *regs, unsigned long error_code)
do_async_page_fault(struct pt_regs *regs, unsigned long error_code)
{
{
	enum ctx_state prev_state;

	switch (kvm_read_and_reset_pf_reason()) {
	switch (kvm_read_and_reset_pf_reason()) {
	default:
	default:
		do_page_fault(regs, error_code);
		do_page_fault(regs, error_code);
		break;
		break;
	case KVM_PV_REASON_PAGE_NOT_PRESENT:
	case KVM_PV_REASON_PAGE_NOT_PRESENT:
		/* page is swapped out by the host. */
		/* page is swapped out by the host. */
		exception_enter(regs);
		prev_state = exception_enter();
		exit_idle();
		exit_idle();
		kvm_async_pf_task_wait((u32)read_cr2());
		kvm_async_pf_task_wait((u32)read_cr2());
		exception_exit(regs);
		exception_exit(prev_state);
		break;
		break;
	case KVM_PV_REASON_PAGE_READY:
	case KVM_PV_REASON_PAGE_READY:
		rcu_irq_enter();
		rcu_irq_enter();
+42 −26
Original line number Original line Diff line number Diff line
@@ -12,6 +12,7 @@


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt


#include <linux/context_tracking.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/kallsyms.h>
#include <linux/kallsyms.h>
#include <linux/spinlock.h>
#include <linux/spinlock.h>
@@ -55,8 +56,6 @@
#include <asm/i387.h>
#include <asm/i387.h>
#include <asm/fpu-internal.h>
#include <asm/fpu-internal.h>
#include <asm/mce.h>
#include <asm/mce.h>
#include <asm/context_tracking.h>

#include <asm/mach_traps.h>
#include <asm/mach_traps.h>


#ifdef CONFIG_X86_64
#ifdef CONFIG_X86_64
@@ -176,34 +175,38 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
#define DO_ERROR(trapnr, signr, str, name)				\
#define DO_ERROR(trapnr, signr, str, name)				\
dotraplinkage void do_##name(struct pt_regs *regs, long error_code)	\
dotraplinkage void do_##name(struct pt_regs *regs, long error_code)	\
{									\
{									\
	exception_enter(regs);						\
	enum ctx_state prev_state;					\
									\
	prev_state = exception_enter();					\
	if (notify_die(DIE_TRAP, str, regs, error_code,			\
	if (notify_die(DIE_TRAP, str, regs, error_code,			\
			trapnr, signr) == NOTIFY_STOP) {		\
			trapnr, signr) == NOTIFY_STOP) {		\
		exception_exit(regs);					\
		exception_exit(prev_state);				\
		return;							\
		return;							\
	}								\
	}								\
	conditional_sti(regs);						\
	conditional_sti(regs);						\
	do_trap(trapnr, signr, str, regs, error_code, NULL);		\
	do_trap(trapnr, signr, str, regs, error_code, NULL);		\
	exception_exit(regs);						\
	exception_exit(prev_state);					\
}
}


#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)		\
#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)		\
dotraplinkage void do_##name(struct pt_regs *regs, long error_code)	\
dotraplinkage void do_##name(struct pt_regs *regs, long error_code)	\
{									\
{									\
	siginfo_t info;							\
	siginfo_t info;							\
	enum ctx_state prev_state;					\
									\
	info.si_signo = signr;						\
	info.si_signo = signr;						\
	info.si_errno = 0;						\
	info.si_errno = 0;						\
	info.si_code = sicode;						\
	info.si_code = sicode;						\
	info.si_addr = (void __user *)siaddr;				\
	info.si_addr = (void __user *)siaddr;				\
	exception_enter(regs);						\
	prev_state = exception_enter();					\
	if (notify_die(DIE_TRAP, str, regs, error_code,			\
	if (notify_die(DIE_TRAP, str, regs, error_code,			\
			trapnr, signr) == NOTIFY_STOP) {		\
			trapnr, signr) == NOTIFY_STOP) {		\
		exception_exit(regs);					\
		exception_exit(prev_state);				\
		return;							\
		return;							\
	}								\
	}								\
	conditional_sti(regs);						\
	conditional_sti(regs);						\
	do_trap(trapnr, signr, str, regs, error_code, &info);		\
	do_trap(trapnr, signr, str, regs, error_code, &info);		\
	exception_exit(regs);						\
	exception_exit(prev_state);					\
}
}


DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV,
DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV,
@@ -226,14 +229,16 @@ DO_ERROR_INFO(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check,
/* Runs on IST stack */
/* Runs on IST stack */
dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
{
{
	exception_enter(regs);
	enum ctx_state prev_state;

	prev_state = exception_enter();
	if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
	if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
		       X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) {
		       X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) {
		preempt_conditional_sti(regs);
		preempt_conditional_sti(regs);
		do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
		do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
		preempt_conditional_cli(regs);
		preempt_conditional_cli(regs);
	}
	}
	exception_exit(regs);
	exception_exit(prev_state);
}
}


dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
@@ -241,7 +246,7 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
	static const char str[] = "double fault";
	static const char str[] = "double fault";
	struct task_struct *tsk = current;
	struct task_struct *tsk = current;


	exception_enter(regs);
	exception_enter();
	/* Return not checked because double check cannot be ignored */
	/* Return not checked because double check cannot be ignored */
	notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
	notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);


@@ -261,8 +266,9 @@ dotraplinkage void __kprobes
do_general_protection(struct pt_regs *regs, long error_code)
do_general_protection(struct pt_regs *regs, long error_code)
{
{
	struct task_struct *tsk;
	struct task_struct *tsk;
	enum ctx_state prev_state;


	exception_enter(regs);
	prev_state = exception_enter();
	conditional_sti(regs);
	conditional_sti(regs);


#ifdef CONFIG_X86_32
#ifdef CONFIG_X86_32
@@ -300,12 +306,14 @@ do_general_protection(struct pt_regs *regs, long error_code)


	force_sig(SIGSEGV, tsk);
	force_sig(SIGSEGV, tsk);
exit:
exit:
	exception_exit(regs);
	exception_exit(prev_state);
}
}


/* May run on IST stack. */
/* May run on IST stack. */
dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_code)
dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_code)
{
{
	enum ctx_state prev_state;

#ifdef CONFIG_DYNAMIC_FTRACE
#ifdef CONFIG_DYNAMIC_FTRACE
	/*
	/*
	 * ftrace must be first, everything else may cause a recursive crash.
	 * ftrace must be first, everything else may cause a recursive crash.
@@ -315,7 +323,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
	    ftrace_int3_handler(regs))
	    ftrace_int3_handler(regs))
		return;
		return;
#endif
#endif
	exception_enter(regs);
	prev_state = exception_enter();
#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
	if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
	if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
				SIGTRAP) == NOTIFY_STOP)
				SIGTRAP) == NOTIFY_STOP)
@@ -336,7 +344,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
	preempt_conditional_cli(regs);
	preempt_conditional_cli(regs);
	debug_stack_usage_dec();
	debug_stack_usage_dec();
exit:
exit:
	exception_exit(regs);
	exception_exit(prev_state);
}
}


#ifdef CONFIG_X86_64
#ifdef CONFIG_X86_64
@@ -393,11 +401,12 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
{
{
	struct task_struct *tsk = current;
	struct task_struct *tsk = current;
	enum ctx_state prev_state;
	int user_icebp = 0;
	int user_icebp = 0;
	unsigned long dr6;
	unsigned long dr6;
	int si_code;
	int si_code;


	exception_enter(regs);
	prev_state = exception_enter();


	get_debugreg(dr6, 6);
	get_debugreg(dr6, 6);


@@ -467,7 +476,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
	debug_stack_usage_dec();
	debug_stack_usage_dec();


exit:
exit:
	exception_exit(regs);
	exception_exit(prev_state);
}
}


/*
/*
@@ -561,17 +570,21 @@ void math_error(struct pt_regs *regs, int error_code, int trapnr)


dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
{
{
	exception_enter(regs);
	enum ctx_state prev_state;

	prev_state = exception_enter();
	math_error(regs, error_code, X86_TRAP_MF);
	math_error(regs, error_code, X86_TRAP_MF);
	exception_exit(regs);
	exception_exit(prev_state);
}
}


dotraplinkage void
dotraplinkage void
do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
{
{
	exception_enter(regs);
	enum ctx_state prev_state;

	prev_state = exception_enter();
	math_error(regs, error_code, X86_TRAP_XF);
	math_error(regs, error_code, X86_TRAP_XF);
	exception_exit(regs);
	exception_exit(prev_state);
}
}


dotraplinkage void
dotraplinkage void
@@ -639,7 +652,9 @@ EXPORT_SYMBOL_GPL(math_state_restore);
dotraplinkage void __kprobes
dotraplinkage void __kprobes
do_device_not_available(struct pt_regs *regs, long error_code)
do_device_not_available(struct pt_regs *regs, long error_code)
{
{
	exception_enter(regs);
	enum ctx_state prev_state;

	prev_state = exception_enter();
	BUG_ON(use_eager_fpu());
	BUG_ON(use_eager_fpu());


#ifdef CONFIG_MATH_EMULATION
#ifdef CONFIG_MATH_EMULATION
@@ -650,7 +665,7 @@ do_device_not_available(struct pt_regs *regs, long error_code)


		info.regs = regs;
		info.regs = regs;
		math_emulate(&info);
		math_emulate(&info);
		exception_exit(regs);
		exception_exit(prev_state);
		return;
		return;
	}
	}
#endif
#endif
@@ -658,15 +673,16 @@ do_device_not_available(struct pt_regs *regs, long error_code)
#ifdef CONFIG_X86_32
#ifdef CONFIG_X86_32
	conditional_sti(regs);
	conditional_sti(regs);
#endif
#endif
	exception_exit(regs);
	exception_exit(prev_state);
}
}


#ifdef CONFIG_X86_32
#ifdef CONFIG_X86_32
dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
{
{
	siginfo_t info;
	siginfo_t info;
	enum ctx_state prev_state;


	exception_enter(regs);
	prev_state = exception_enter();
	local_irq_enable();
	local_irq_enable();


	info.si_signo = SIGILL;
	info.si_signo = SIGILL;
@@ -678,7 +694,7 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
		do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
		do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
			&info);
			&info);
	}
	}
	exception_exit(regs);
	exception_exit(prev_state);
}
}
#endif
#endif


+5 −3
Original line number Original line Diff line number Diff line
@@ -13,12 +13,12 @@
#include <linux/perf_event.h>		/* perf_sw_event		*/
#include <linux/perf_event.h>		/* perf_sw_event		*/
#include <linux/hugetlb.h>		/* hstate_index_to_shift	*/
#include <linux/hugetlb.h>		/* hstate_index_to_shift	*/
#include <linux/prefetch.h>		/* prefetchw			*/
#include <linux/prefetch.h>		/* prefetchw			*/
#include <linux/context_tracking.h>	/* exception_enter(), ...	*/


#include <asm/traps.h>			/* dotraplinkage, ...		*/
#include <asm/traps.h>			/* dotraplinkage, ...		*/
#include <asm/pgalloc.h>		/* pgd_*(), ...			*/
#include <asm/pgalloc.h>		/* pgd_*(), ...			*/
#include <asm/kmemcheck.h>		/* kmemcheck_*(), ...		*/
#include <asm/kmemcheck.h>		/* kmemcheck_*(), ...		*/
#include <asm/fixmap.h>			/* VSYSCALL_START		*/
#include <asm/fixmap.h>			/* VSYSCALL_START		*/
#include <asm/context_tracking.h>	/* exception_enter(), ...	*/


/*
/*
 * Page fault error code bits:
 * Page fault error code bits:
@@ -1222,7 +1222,9 @@ good_area:
dotraplinkage void __kprobes
dotraplinkage void __kprobes
do_page_fault(struct pt_regs *regs, unsigned long error_code)
do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
{
	exception_enter(regs);
	enum ctx_state prev_state;

	prev_state = exception_enter();
	__do_page_fault(regs, error_code);
	__do_page_fault(regs, error_code);
	exception_exit(regs);
	exception_exit(prev_state);
}
}
+22 −2
Original line number Original line Diff line number Diff line
#ifndef _LINUX_CONTEXT_TRACKING_H
#ifndef _LINUX_CONTEXT_TRACKING_H
#define _LINUX_CONTEXT_TRACKING_H
#define _LINUX_CONTEXT_TRACKING_H


#ifdef CONFIG_CONTEXT_TRACKING
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/percpu.h>
#include <linux/percpu.h>
#include <asm/ptrace.h>


struct context_tracking {
struct context_tracking {
	/*
	/*
@@ -13,12 +13,13 @@ struct context_tracking {
	 * may be further optimized using static keys.
	 * may be further optimized using static keys.
	 */
	 */
	bool active;
	bool active;
	enum {
	enum ctx_state {
		IN_KERNEL = 0,
		IN_KERNEL = 0,
		IN_USER,
		IN_USER,
	} state;
	} state;
};
};


#ifdef CONFIG_CONTEXT_TRACKING
DECLARE_PER_CPU(struct context_tracking, context_tracking);
DECLARE_PER_CPU(struct context_tracking, context_tracking);


static inline bool context_tracking_in_user(void)
static inline bool context_tracking_in_user(void)
@@ -33,12 +34,31 @@ static inline bool context_tracking_active(void)


extern void user_enter(void);
extern void user_enter(void);
extern void user_exit(void);
extern void user_exit(void);

static inline enum ctx_state exception_enter(void)
{
	enum ctx_state prev_ctx;

	prev_ctx = this_cpu_read(context_tracking.state);
	user_exit();

	return prev_ctx;
}

static inline void exception_exit(enum ctx_state prev_ctx)
{
	if (prev_ctx == IN_USER)
		user_enter();
}

extern void context_tracking_task_switch(struct task_struct *prev,
extern void context_tracking_task_switch(struct task_struct *prev,
					 struct task_struct *next);
					 struct task_struct *next);
#else
#else
static inline bool context_tracking_in_user(void) { return false; }
static inline bool context_tracking_in_user(void) { return false; }
static inline void user_enter(void) { }
static inline void user_enter(void) { }
static inline void user_exit(void) { }
static inline void user_exit(void) { }
static inline enum ctx_state exception_enter(void) { return 0; }
static inline void exception_exit(enum ctx_state prev_ctx) { }
static inline void context_tracking_task_switch(struct task_struct *prev,
static inline void context_tracking_task_switch(struct task_struct *prev,
						struct task_struct *next) { }
						struct task_struct *next) { }
#endif /* !CONFIG_CONTEXT_TRACKING */
#endif /* !CONFIG_CONTEXT_TRACKING */
Loading