diff options
-rw-r--r-- | arch/x86/include/asm/preempt.h | 1 | ||||
-rw-r--r-- | kernel/context_tracking.c | 40 | ||||
-rw-r--r-- | kernel/sched/core.c | 41 |
3 files changed, 42 insertions, 40 deletions
diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h index 7024c12f7bfe..400873450e33 100644 --- a/arch/x86/include/asm/preempt.h +++ b/arch/x86/include/asm/preempt.h | |||
@@ -105,6 +105,7 @@ static __always_inline bool should_resched(void) | |||
105 | # ifdef CONFIG_CONTEXT_TRACKING | 105 | # ifdef CONFIG_CONTEXT_TRACKING |
106 | extern asmlinkage void ___preempt_schedule_context(void); | 106 | extern asmlinkage void ___preempt_schedule_context(void); |
107 | # define __preempt_schedule_context() asm ("call ___preempt_schedule_context") | 107 | # define __preempt_schedule_context() asm ("call ___preempt_schedule_context") |
108 | extern asmlinkage void preempt_schedule_context(void); | ||
108 | # endif | 109 | # endif |
109 | #endif | 110 | #endif |
110 | 111 | ||
diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c index 5664985c46a0..937ecdfdf258 100644 --- a/kernel/context_tracking.c +++ b/kernel/context_tracking.c | |||
@@ -107,46 +107,6 @@ void context_tracking_user_enter(void) | |||
107 | } | 107 | } |
108 | NOKPROBE_SYMBOL(context_tracking_user_enter); | 108 | NOKPROBE_SYMBOL(context_tracking_user_enter); |
109 | 109 | ||
110 | #ifdef CONFIG_PREEMPT | ||
111 | /** | ||
112 | * preempt_schedule_context - preempt_schedule called by tracing | ||
113 | * | ||
114 | * The tracing infrastructure uses preempt_enable_notrace to prevent | ||
115 | * recursion and tracing preempt enabling caused by the tracing | ||
116 | * infrastructure itself. But as tracing can happen in areas coming | ||
117 | * from userspace or just about to enter userspace, a preempt enable | ||
118 | * can occur before user_exit() is called. This will cause the scheduler | ||
119 | * to be called when the system is still in usermode. | ||
120 | * | ||
121 | * To prevent this, the preempt_enable_notrace will use this function | ||
122 | * instead of preempt_schedule() to exit user context if needed before | ||
123 | * calling the scheduler. | ||
124 | */ | ||
125 | asmlinkage __visible void __sched notrace preempt_schedule_context(void) | ||
126 | { | ||
127 | enum ctx_state prev_ctx; | ||
128 | |||
129 | if (likely(!preemptible())) | ||
130 | return; | ||
131 | |||
132 | /* | ||
133 | * Need to disable preemption in case user_exit() is traced | ||
134 | * and the tracer calls preempt_enable_notrace() causing | ||
135 | * an infinite recursion. | ||
136 | */ | ||
137 | preempt_disable_notrace(); | ||
138 | prev_ctx = exception_enter(); | ||
139 | preempt_enable_no_resched_notrace(); | ||
140 | |||
141 | preempt_schedule(); | ||
142 | |||
143 | preempt_disable_notrace(); | ||
144 | exception_exit(prev_ctx); | ||
145 | preempt_enable_notrace(); | ||
146 | } | ||
147 | EXPORT_SYMBOL_GPL(preempt_schedule_context); | ||
148 | #endif /* CONFIG_PREEMPT */ | ||
149 | |||
150 | /** | 110 | /** |
151 | * context_tracking_user_exit - Inform the context tracking that the CPU is | 111 | * context_tracking_user_exit - Inform the context tracking that the CPU is |
152 | * exiting userspace mode and entering the kernel. | 112 | * exiting userspace mode and entering the kernel. |
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index dde8adb7d0c0..240157c13ddc 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -2951,6 +2951,47 @@ asmlinkage __visible void __sched notrace preempt_schedule(void) | |||
2951 | } | 2951 | } |
2952 | NOKPROBE_SYMBOL(preempt_schedule); | 2952 | NOKPROBE_SYMBOL(preempt_schedule); |
2953 | EXPORT_SYMBOL(preempt_schedule); | 2953 | EXPORT_SYMBOL(preempt_schedule); |
2954 | |||
2955 | #ifdef CONFIG_CONTEXT_TRACKING | ||
2956 | /** | ||
2957 | * preempt_schedule_context - preempt_schedule called by tracing | ||
2958 | * | ||
2959 | * The tracing infrastructure uses preempt_enable_notrace to prevent | ||
2960 | * recursion and tracing preempt enabling caused by the tracing | ||
2961 | * infrastructure itself. But as tracing can happen in areas coming | ||
2962 | * from userspace or just about to enter userspace, a preempt enable | ||
2963 | * can occur before user_exit() is called. This will cause the scheduler | ||
2964 | * to be called when the system is still in usermode. | ||
2965 | * | ||
2966 | * To prevent this, the preempt_enable_notrace will use this function | ||
2967 | * instead of preempt_schedule() to exit user context if needed before | ||
2968 | * calling the scheduler. | ||
2969 | */ | ||
2970 | asmlinkage __visible void __sched notrace preempt_schedule_context(void) | ||
2971 | { | ||
2972 | enum ctx_state prev_ctx; | ||
2973 | |||
2974 | if (likely(!preemptible())) | ||
2975 | return; | ||
2976 | |||
2977 | do { | ||
2978 | __preempt_count_add(PREEMPT_ACTIVE); | ||
2979 | /* | ||
2980 | * Needs preempt disabled in case user_exit() is traced | ||
2981 | * and the tracer calls preempt_enable_notrace() causing | ||
2982 | * an infinite recursion. | ||
2983 | */ | ||
2984 | prev_ctx = exception_enter(); | ||
2985 | __schedule(); | ||
2986 | exception_exit(prev_ctx); | ||
2987 | |||
2988 | __preempt_count_sub(PREEMPT_ACTIVE); | ||
2989 | barrier(); | ||
2990 | } while (need_resched()); | ||
2991 | } | ||
2992 | EXPORT_SYMBOL_GPL(preempt_schedule_context); | ||
2993 | #endif /* CONFIG_CONTEXT_TRACKING */ | ||
2994 | |||
2954 | #endif /* CONFIG_PREEMPT */ | 2995 | #endif /* CONFIG_PREEMPT */ |
2955 | 2996 | ||
2956 | /* | 2997 | /* |