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.homeAcked-by: default avatarMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Acked-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
parent 03ecd3f4
...@@ -128,7 +128,7 @@ extern void syscall_unregfunc(void); ...@@ -128,7 +128,7 @@ extern void syscall_unregfunc(void);
* as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just
* "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto". * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto".
*/ */
#define __DO_TRACE(tp, proto, args, cond, prercu, postrcu) \ #define __DO_TRACE(tp, proto, args, cond, rcucheck) \
do { \ do { \
struct tracepoint_func *it_func_ptr; \ struct tracepoint_func *it_func_ptr; \
void *it_func; \ void *it_func; \
...@@ -136,7 +136,11 @@ extern void syscall_unregfunc(void); ...@@ -136,7 +136,11 @@ extern void syscall_unregfunc(void);
\ \
if (!(cond)) \ if (!(cond)) \
return; \ return; \
prercu; \ if (rcucheck) { \
if (WARN_ON_ONCE(rcu_irq_enter_disabled())) \
return; \
rcu_irq_enter_irqson(); \
} \
rcu_read_lock_sched_notrace(); \ rcu_read_lock_sched_notrace(); \
it_func_ptr = rcu_dereference_sched((tp)->funcs); \ it_func_ptr = rcu_dereference_sched((tp)->funcs); \
if (it_func_ptr) { \ if (it_func_ptr) { \
...@@ -147,20 +151,19 @@ extern void syscall_unregfunc(void); ...@@ -147,20 +151,19 @@ extern void syscall_unregfunc(void);
} while ((++it_func_ptr)->func); \ } while ((++it_func_ptr)->func); \
} \ } \
rcu_read_unlock_sched_notrace(); \ rcu_read_unlock_sched_notrace(); \
postrcu; \ if (rcucheck) \
rcu_irq_exit_irqson(); \
} while (0) } while (0)
#ifndef MODULE #ifndef MODULE
#define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args) \ #define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args) \
static inline void trace_##name##_rcuidle(proto) \ static inline void trace_##name##_rcuidle(proto) \
{ \ { \
if (static_key_false(&__tracepoint_##name.key)) \ if (static_key_false(&__tracepoint_##name.key)) \
__DO_TRACE(&__tracepoint_##name, \ __DO_TRACE(&__tracepoint_##name, \
TP_PROTO(data_proto), \ TP_PROTO(data_proto), \
TP_ARGS(data_args), \ TP_ARGS(data_args), \
TP_CONDITION(cond), \ TP_CONDITION(cond), 1); \
rcu_irq_enter_irqson(), \
rcu_irq_exit_irqson()); \
} }
#else #else
#define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args) #define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args)
...@@ -186,7 +189,7 @@ extern void syscall_unregfunc(void); ...@@ -186,7 +189,7 @@ extern void syscall_unregfunc(void);
__DO_TRACE(&__tracepoint_##name, \ __DO_TRACE(&__tracepoint_##name, \
TP_PROTO(data_proto), \ TP_PROTO(data_proto), \
TP_ARGS(data_args), \ TP_ARGS(data_args), \
TP_CONDITION(cond),,); \ TP_CONDITION(cond), 0); \
if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) { \ if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) { \
rcu_read_lock_sched_notrace(); \ rcu_read_lock_sched_notrace(); \
rcu_dereference_sched(__tracepoint_##name.funcs);\ rcu_dereference_sched(__tracepoint_##name.funcs);\
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment