aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/context_tracking.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/context_tracking.c')
-rw-r--r--kernel/context_tracking.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c
index 65349f07b878..66677003e223 100644
--- a/kernel/context_tracking.c
+++ b/kernel/context_tracking.c
@@ -71,6 +71,46 @@ void user_enter(void)
71 local_irq_restore(flags); 71 local_irq_restore(flags);
72} 72}
73 73
74#ifdef CONFIG_PREEMPT
75/**
76 * preempt_schedule_context - preempt_schedule called by tracing
77 *
78 * The tracing infrastructure uses preempt_enable_notrace to prevent
79 * recursion and tracing preempt enabling caused by the tracing
80 * infrastructure itself. But as tracing can happen in areas coming
81 * from userspace or just about to enter userspace, a preempt enable
82 * can occur before user_exit() is called. This will cause the scheduler
83 * to be called when the system is still in usermode.
84 *
85 * To prevent this, the preempt_enable_notrace will use this function
86 * instead of preempt_schedule() to exit user context if needed before
87 * calling the scheduler.
88 */
89void __sched notrace preempt_schedule_context(void)
90{
91 struct thread_info *ti = current_thread_info();
92 enum ctx_state prev_ctx;
93
94 if (likely(ti->preempt_count || irqs_disabled()))
95 return;
96
97 /*
98 * Need to disable preemption in case user_exit() is traced
99 * and the tracer calls preempt_enable_notrace() causing
100 * an infinite recursion.
101 */
102 preempt_disable_notrace();
103 prev_ctx = exception_enter();
104 preempt_enable_no_resched_notrace();
105
106 preempt_schedule();
107
108 preempt_disable_notrace();
109 exception_exit(prev_ctx);
110 preempt_enable_notrace();
111}
112EXPORT_SYMBOL_GPL(preempt_schedule_context);
113#endif /* CONFIG_PREEMPT */
74 114
75/** 115/**
76 * user_exit - Inform the context tracking that the CPU is 116 * user_exit - Inform the context tracking that the CPU is