summaryrefslogtreecommitdiffstats
path: root/include/linux/tracepoint.h
diff options
context:
space:
mode:
authorSteven Rostedt (VMware) <rostedt@goodmis.org>2017-04-07 12:40:49 -0400
committerSteven Rostedt (VMware) <rostedt@goodmis.org>2017-04-10 15:22:17 -0400
commitd54b6eeb553c89ed8d4c5a2ed73df374a45b9562 (patch)
tree26ee9aadd39cb4f25fbd7f41e1adab23a51ccd35 /include/linux/tracepoint.h
parent03ecd3f48e57f2e6154584e0ee7450d7a05e2d3b (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.h19
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);\