diff options
author | Steven Rostedt (VMware) <rostedt@goodmis.org> | 2017-04-07 12:40:49 -0400 |
---|---|---|
committer | Steven Rostedt (VMware) <rostedt@goodmis.org> | 2017-04-10 15:22:17 -0400 |
commit | d54b6eeb553c89ed8d4c5a2ed73df374a45b9562 (patch) | |
tree | 26ee9aadd39cb4f25fbd7f41e1adab23a51ccd35 /include/linux/tracepoint.h | |
parent | 03ecd3f48e57f2e6154584e0ee7450d7a05e2d3b (diff) |
tracing: Make sure rcu_irq_enter() can work for trace_*_rcuidle() trace events
Stack tracing discovered that there's a small location inside the RCU
infrastructure where calling rcu_irq_enter() does not work. As trace events
use rcu_irq_enter() it must make sure that it is functionable. A check
against rcu_irq_enter_disabled() is added with a WARN_ON_ONCE() as no trace
event should ever be used in that part of RCU. If the warning is triggered,
then the trace event is ignored.
Restructure the __DO_TRACE() a bit to get rid of the prercu and postrcu,
and just have an rcucheck that does the work from within the _DO_TRACE()
macro. gcc optimization will compile out the rcucheck=0 case.
Link: http://lkml.kernel.org/r/20170405093207.404f8deb@gandalf.local.home
Acked-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Diffstat (limited to 'include/linux/tracepoint.h')
-rw-r--r-- | include/linux/tracepoint.h | 19 |
1 files changed, 11 insertions, 8 deletions
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index f72fcfe0e66a..cc48cb2ce209 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
@@ -128,7 +128,7 @@ extern void syscall_unregfunc(void); | |||
128 | * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just | 128 | * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just |
129 | * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto". | 129 | * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto". |
130 | */ | 130 | */ |
131 | #define __DO_TRACE(tp, proto, args, cond, prercu, postrcu) \ | 131 | #define __DO_TRACE(tp, proto, args, cond, rcucheck) \ |
132 | do { \ | 132 | do { \ |
133 | struct tracepoint_func *it_func_ptr; \ | 133 | struct tracepoint_func *it_func_ptr; \ |
134 | void *it_func; \ | 134 | void *it_func; \ |
@@ -136,7 +136,11 @@ extern void syscall_unregfunc(void); | |||
136 | \ | 136 | \ |
137 | if (!(cond)) \ | 137 | if (!(cond)) \ |
138 | return; \ | 138 | return; \ |
139 | prercu; \ | 139 | if (rcucheck) { \ |
140 | if (WARN_ON_ONCE(rcu_irq_enter_disabled())) \ | ||
141 | return; \ | ||
142 | rcu_irq_enter_irqson(); \ | ||
143 | } \ | ||
140 | rcu_read_lock_sched_notrace(); \ | 144 | rcu_read_lock_sched_notrace(); \ |
141 | it_func_ptr = rcu_dereference_sched((tp)->funcs); \ | 145 | it_func_ptr = rcu_dereference_sched((tp)->funcs); \ |
142 | if (it_func_ptr) { \ | 146 | if (it_func_ptr) { \ |
@@ -147,20 +151,19 @@ extern void syscall_unregfunc(void); | |||
147 | } while ((++it_func_ptr)->func); \ | 151 | } while ((++it_func_ptr)->func); \ |
148 | } \ | 152 | } \ |
149 | rcu_read_unlock_sched_notrace(); \ | 153 | rcu_read_unlock_sched_notrace(); \ |
150 | postrcu; \ | 154 | if (rcucheck) \ |
155 | rcu_irq_exit_irqson(); \ | ||
151 | } while (0) | 156 | } while (0) |
152 | 157 | ||
153 | #ifndef MODULE | 158 | #ifndef MODULE |
154 | #define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args) \ | 159 | #define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args) \ |
155 | static inline void trace_##name##_rcuidle(proto) \ | 160 | static inline void trace_##name##_rcuidle(proto) \ |
156 | { \ | 161 | { \ |
157 | if (static_key_false(&__tracepoint_##name.key)) \ | 162 | if (static_key_false(&__tracepoint_##name.key)) \ |
158 | __DO_TRACE(&__tracepoint_##name, \ | 163 | __DO_TRACE(&__tracepoint_##name, \ |
159 | TP_PROTO(data_proto), \ | 164 | TP_PROTO(data_proto), \ |
160 | TP_ARGS(data_args), \ | 165 | TP_ARGS(data_args), \ |
161 | TP_CONDITION(cond), \ | 166 | TP_CONDITION(cond), 1); \ |
162 | rcu_irq_enter_irqson(), \ | ||
163 | rcu_irq_exit_irqson()); \ | ||
164 | } | 167 | } |
165 | #else | 168 | #else |
166 | #define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args) | 169 | #define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args) |
@@ -186,7 +189,7 @@ extern void syscall_unregfunc(void); | |||
186 | __DO_TRACE(&__tracepoint_##name, \ | 189 | __DO_TRACE(&__tracepoint_##name, \ |
187 | TP_PROTO(data_proto), \ | 190 | TP_PROTO(data_proto), \ |
188 | TP_ARGS(data_args), \ | 191 | TP_ARGS(data_args), \ |
189 | TP_CONDITION(cond),,); \ | 192 | TP_CONDITION(cond), 0); \ |
190 | if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) { \ | 193 | if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) { \ |
191 | rcu_read_lock_sched_notrace(); \ | 194 | rcu_read_lock_sched_notrace(); \ |
192 | rcu_dereference_sched(__tracepoint_##name.funcs);\ | 195 | rcu_dereference_sched(__tracepoint_##name.funcs);\ |