cputime: Remove irqsave from seqlock readers
[pandora-kernel.git] / kernel / context_tracking.c
1 #include <linux/context_tracking.h>
2 #include <linux/kvm_host.h>
3 #include <linux/rcupdate.h>
4 #include <linux/sched.h>
5 #include <linux/hardirq.h>
6 #include <linux/export.h>
7
8 DEFINE_PER_CPU(struct context_tracking, context_tracking) = {
9 #ifdef CONFIG_CONTEXT_TRACKING_FORCE
10         .active = true,
11 #endif
12 };
13
14 void user_enter(void)
15 {
16         unsigned long flags;
17
18         /*
19          * Some contexts may involve an exception occuring in an irq,
20          * leading to that nesting:
21          * rcu_irq_enter() rcu_user_exit() rcu_user_exit() rcu_irq_exit()
22          * This would mess up the dyntick_nesting count though. And rcu_irq_*()
23          * helpers are enough to protect RCU uses inside the exception. So
24          * just return immediately if we detect we are in an IRQ.
25          */
26         if (in_interrupt())
27                 return;
28
29         WARN_ON_ONCE(!current->mm);
30
31         local_irq_save(flags);
32         if (__this_cpu_read(context_tracking.active) &&
33             __this_cpu_read(context_tracking.state) != IN_USER) {
34                 vtime_user_enter(current);
35                 rcu_user_enter();
36                 __this_cpu_write(context_tracking.state, IN_USER);
37         }
38         local_irq_restore(flags);
39 }
40
41 void user_exit(void)
42 {
43         unsigned long flags;
44
45         /*
46          * Some contexts may involve an exception occuring in an irq,
47          * leading to that nesting:
48          * rcu_irq_enter() rcu_user_exit() rcu_user_exit() rcu_irq_exit()
49          * This would mess up the dyntick_nesting count though. And rcu_irq_*()
50          * helpers are enough to protect RCU uses inside the exception. So
51          * just return immediately if we detect we are in an IRQ.
52          */
53         if (in_interrupt())
54                 return;
55
56         local_irq_save(flags);
57         if (__this_cpu_read(context_tracking.state) == IN_USER) {
58                 rcu_user_exit();
59                 vtime_user_exit(current);
60                 __this_cpu_write(context_tracking.state, IN_KERNEL);
61         }
62         local_irq_restore(flags);
63 }
64
65 void guest_enter(void)
66 {
67         if (vtime_accounting_enabled())
68                 vtime_guest_enter(current);
69         else
70                 __guest_enter();
71 }
72 EXPORT_SYMBOL_GPL(guest_enter);
73
74 void guest_exit(void)
75 {
76         if (vtime_accounting_enabled())
77                 vtime_guest_exit(current);
78         else
79                 __guest_exit();
80 }
81 EXPORT_SYMBOL_GPL(guest_exit);
82
83 void context_tracking_task_switch(struct task_struct *prev,
84                              struct task_struct *next)
85 {
86         if (__this_cpu_read(context_tracking.active)) {
87                 clear_tsk_thread_flag(prev, TIF_NOHZ);
88                 set_tsk_thread_flag(next, TIF_NOHZ);
89         }
90 }