aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/hardirq.h
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2013-01-15 22:11:19 -0500
committerSteven Rostedt <rostedt@goodmis.org>2013-01-21 13:22:34 -0500
commit0f1ac8fd254b6c3e77950a1c4ee67be5dc88f7e0 (patch)
tree694bd2973e8146c6a598adaa086f3af7a5515bf1 /include/linux/hardirq.h
parent84c6cf0db6a00601eb43cfc08244a398ffb0894c (diff)
tracing/lockdep: Disable lockdep first in entering NMI
When function tracing with either debug locks enabled or tracing preempt disabled, the add_preempt_count() is traced. This is an issue with lockdep and function tracing. As function tracing can disable interrupts, and lockdep records that change, lockdep may not be able to handle this recursion if it happens from an NMI context. The first thing that an NMI does is: #define nmi_enter() \ do { \ ftrace_nmi_enter(); \ BUG_ON(in_nmi()); \ add_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \ lockdep_off(); \ rcu_nmi_enter(); \ trace_hardirq_enter(); \ } while (0) When the add_preempt_count() is traced, and the tracing callback disables interrupts, it will jump into the lockdep code. There's some places in lockdep that can't handle this re-entrance, and causes lockdep to fail. As the lockdep_off() (and lockdep_on) is a simple: void lockdep_off(void) { current->lockdep_recursion++; } and is never traced, it can be called first in nmi_enter() and lockdep_on() last in nmi_exit(). Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'include/linux/hardirq.h')
-rw-r--r--include/linux/hardirq.h4
1 files changed, 2 insertions, 2 deletions
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 624ef3f45c8e..57bfdce8fb90 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -180,10 +180,10 @@ extern void irq_exit(void);
180 180
181#define nmi_enter() \ 181#define nmi_enter() \
182 do { \ 182 do { \
183 lockdep_off(); \
183 ftrace_nmi_enter(); \ 184 ftrace_nmi_enter(); \
184 BUG_ON(in_nmi()); \ 185 BUG_ON(in_nmi()); \
185 add_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \ 186 add_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \
186 lockdep_off(); \
187 rcu_nmi_enter(); \ 187 rcu_nmi_enter(); \
188 trace_hardirq_enter(); \ 188 trace_hardirq_enter(); \
189 } while (0) 189 } while (0)
@@ -192,10 +192,10 @@ extern void irq_exit(void);
192 do { \ 192 do { \
193 trace_hardirq_exit(); \ 193 trace_hardirq_exit(); \
194 rcu_nmi_exit(); \ 194 rcu_nmi_exit(); \
195 lockdep_on(); \
196 BUG_ON(!in_nmi()); \ 195 BUG_ON(!in_nmi()); \
197 sub_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \ 196 sub_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \
198 ftrace_nmi_exit(); \ 197 ftrace_nmi_exit(); \
198 lockdep_on(); \
199 } while (0) 199 } while (0)
200 200
201#endif /* LINUX_HARDIRQ_H */ 201#endif /* LINUX_HARDIRQ_H */