blob: 9002e92e6372c830fdbc9f801318bba0f873990d [file] [log] [blame]
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +01001#include <linux/context_tracking.h>
2#include <linux/rcupdate.h>
3#include <linux/sched.h>
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +01004#include <linux/hardirq.h>
5
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +01006
Frederic Weisbecker95a79fd2013-01-07 18:12:14 +01007DEFINE_PER_CPU(struct context_tracking, context_tracking) = {
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +01008#ifdef CONFIG_CONTEXT_TRACKING_FORCE
9 .active = true,
10#endif
11};
12
13void user_enter(void)
14{
15 unsigned long flags;
16
17 /*
18 * Some contexts may involve an exception occuring in an irq,
19 * leading to that nesting:
20 * rcu_irq_enter() rcu_user_exit() rcu_user_exit() rcu_irq_exit()
21 * This would mess up the dyntick_nesting count though. And rcu_irq_*()
22 * helpers are enough to protect RCU uses inside the exception. So
23 * just return immediately if we detect we are in an IRQ.
24 */
25 if (in_interrupt())
26 return;
27
28 WARN_ON_ONCE(!current->mm);
29
30 local_irq_save(flags);
31 if (__this_cpu_read(context_tracking.active) &&
32 __this_cpu_read(context_tracking.state) != IN_USER) {
Frederic Weisbeckerabf917c2012-07-25 07:56:04 +020033 vtime_user_enter(current);
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +010034 rcu_user_enter();
Frederic Weisbeckerabf917c2012-07-25 07:56:04 +020035 __this_cpu_write(context_tracking.state, IN_USER);
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +010036 }
37 local_irq_restore(flags);
38}
39
40void user_exit(void)
41{
42 unsigned long flags;
43
44 /*
45 * Some contexts may involve an exception occuring in an irq,
46 * leading to that nesting:
47 * rcu_irq_enter() rcu_user_exit() rcu_user_exit() rcu_irq_exit()
48 * This would mess up the dyntick_nesting count though. And rcu_irq_*()
49 * helpers are enough to protect RCU uses inside the exception. So
50 * just return immediately if we detect we are in an IRQ.
51 */
52 if (in_interrupt())
53 return;
54
55 local_irq_save(flags);
56 if (__this_cpu_read(context_tracking.state) == IN_USER) {
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +010057 rcu_user_exit();
Frederic Weisbeckerabf917c2012-07-25 07:56:04 +020058 vtime_user_exit(current);
59 __this_cpu_write(context_tracking.state, IN_KERNEL);
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +010060 }
61 local_irq_restore(flags);
62}
63
64void context_tracking_task_switch(struct task_struct *prev,
65 struct task_struct *next)
66{
67 if (__this_cpu_read(context_tracking.active)) {
68 clear_tsk_thread_flag(prev, TIF_NOHZ);
69 set_tsk_thread_flag(next, TIF_NOHZ);
70 }
71}