aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2013-07-11 17:59:33 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2013-08-12 18:40:44 -0400
commitd65ec12127a5b6c6d7f5331c78157dab98a20ff0 (patch)
tree5a37039fe137571d0ddc8fd5cf3bc040f0fbb809 /kernel
parent5b206d48e58204e84d249c4eb18651a1ff7a1274 (diff)
context_tracking: Fix runtime CPU off-case
As long as the context tracking is enabled on any CPU, even a single one, all other CPUs need to keep track of their user <-> kernel boundaries cross as well. This is because a task can sleep while servicing an exception that happened in the kernel or in userspace. Then when the task eventually wakes up and return from the exception, the CPU needs to know if we resume in userspace or in the kernel. exception_exit() get this information from exception_enter() that saved the previous state. If the CPU where the exception happened didn't keep track of these informations, exception_exit() doesn't know which state tracking to restore on the CPU where the task got migrated and we may return to userspace with the context tracking subsystem thinking that we are in kernel mode. This can be fixed in the long term if we move our context tracking probes on very low level arch fast path user <-> kernel boundary, although even that is worrisome as an exception can still happen in the few instructions between the probe and the actual iret. Also we are not yet ready to set these probes in the fast path given the potential overhead problem it induces. So let's fix this by always enable context tracking even on CPUs that are not in the full dynticks range. OTOH we can spare the rcu_user_*() and vtime_user_*() calls there because the tick runs on these CPUs and we can handle RCU state machine and cputime accounting through it. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Li Zhong <zhong@linux.vnet.ibm.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Kevin Hilman <khilman@linaro.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/context_tracking.c52
1 files changed, 33 insertions, 19 deletions
diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c
index 1f47119c5b09..7b095de356c5 100644
--- a/kernel/context_tracking.c
+++ b/kernel/context_tracking.c
@@ -54,17 +54,31 @@ void user_enter(void)
54 WARN_ON_ONCE(!current->mm); 54 WARN_ON_ONCE(!current->mm);
55 55
56 local_irq_save(flags); 56 local_irq_save(flags);
57 if (__this_cpu_read(context_tracking.active) && 57 if ( __this_cpu_read(context_tracking.state) != IN_USER) {
58 __this_cpu_read(context_tracking.state) != IN_USER) { 58 if (__this_cpu_read(context_tracking.active)) {
59 /*
60 * At this stage, only low level arch entry code remains and
61 * then we'll run in userspace. We can assume there won't be
62 * any RCU read-side critical section until the next call to
63 * user_exit() or rcu_irq_enter(). Let's remove RCU's dependency
64 * on the tick.
65 */
66 vtime_user_enter(current);
67 rcu_user_enter();
68 }
59 /* 69 /*
60 * At this stage, only low level arch entry code remains and 70 * Even if context tracking is disabled on this CPU, because it's outside
61 * then we'll run in userspace. We can assume there won't be 71 * the full dynticks mask for example, we still have to keep track of the
62 * any RCU read-side critical section until the next call to 72 * context transitions and states to prevent inconsistency on those of
63 * user_exit() or rcu_irq_enter(). Let's remove RCU's dependency 73 * other CPUs.
64 * on the tick. 74 * If a task triggers an exception in userspace, sleep on the exception
75 * handler and then migrate to another CPU, that new CPU must know where
76 * the exception returns by the time we call exception_exit().
77 * This information can only be provided by the previous CPU when it called
78 * exception_enter().
79 * OTOH we can spare the calls to vtime and RCU when context_tracking.active
80 * is false because we know that CPU is not tickless.
65 */ 81 */
66 vtime_user_enter(current);
67 rcu_user_enter();
68 __this_cpu_write(context_tracking.state, IN_USER); 82 __this_cpu_write(context_tracking.state, IN_USER);
69 } 83 }
70 local_irq_restore(flags); 84 local_irq_restore(flags);
@@ -130,12 +144,14 @@ void user_exit(void)
130 144
131 local_irq_save(flags); 145 local_irq_save(flags);
132 if (__this_cpu_read(context_tracking.state) == IN_USER) { 146 if (__this_cpu_read(context_tracking.state) == IN_USER) {
133 /* 147 if (__this_cpu_read(context_tracking.active)) {
134 * We are going to run code that may use RCU. Inform 148 /*
135 * RCU core about that (ie: we may need the tick again). 149 * We are going to run code that may use RCU. Inform
136 */ 150 * RCU core about that (ie: we may need the tick again).
137 rcu_user_exit(); 151 */
138 vtime_user_exit(current); 152 rcu_user_exit();
153 vtime_user_exit(current);
154 }
139 __this_cpu_write(context_tracking.state, IN_KERNEL); 155 __this_cpu_write(context_tracking.state, IN_KERNEL);
140 } 156 }
141 local_irq_restore(flags); 157 local_irq_restore(flags);
@@ -178,8 +194,6 @@ EXPORT_SYMBOL_GPL(guest_exit);
178void context_tracking_task_switch(struct task_struct *prev, 194void context_tracking_task_switch(struct task_struct *prev,
179 struct task_struct *next) 195 struct task_struct *next)
180{ 196{
181 if (__this_cpu_read(context_tracking.active)) { 197 clear_tsk_thread_flag(prev, TIF_NOHZ);
182 clear_tsk_thread_flag(prev, TIF_NOHZ); 198 set_tsk_thread_flag(next, TIF_NOHZ);
183 set_tsk_thread_flag(next, TIF_NOHZ);
184 }
185} 199}