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>
This commit is contained in:
Родитель
03ecd3f48e
Коммит
d54b6eeb55
|
@ -128,7 +128,7 @@ extern void syscall_unregfunc(void);
|
|||
* as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just
|
||||
* "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 { \
|
||||
struct tracepoint_func *it_func_ptr; \
|
||||
void *it_func; \
|
||||
|
@ -136,7 +136,11 @@ extern void syscall_unregfunc(void);
|
|||
\
|
||||
if (!(cond)) \
|
||||
return; \
|
||||
prercu; \
|
||||
if (rcucheck) { \
|
||||
if (WARN_ON_ONCE(rcu_irq_enter_disabled())) \
|
||||
return; \
|
||||
rcu_irq_enter_irqson(); \
|
||||
} \
|
||||
rcu_read_lock_sched_notrace(); \
|
||||
it_func_ptr = rcu_dereference_sched((tp)->funcs); \
|
||||
if (it_func_ptr) { \
|
||||
|
@ -147,20 +151,19 @@ extern void syscall_unregfunc(void);
|
|||
} while ((++it_func_ptr)->func); \
|
||||
} \
|
||||
rcu_read_unlock_sched_notrace(); \
|
||||
postrcu; \
|
||||
if (rcucheck) \
|
||||
rcu_irq_exit_irqson(); \
|
||||
} while (0)
|
||||
|
||||
#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) \
|
||||
{ \
|
||||
if (static_key_false(&__tracepoint_##name.key)) \
|
||||
__DO_TRACE(&__tracepoint_##name, \
|
||||
TP_PROTO(data_proto), \
|
||||
TP_ARGS(data_args), \
|
||||
TP_CONDITION(cond), \
|
||||
rcu_irq_enter_irqson(), \
|
||||
rcu_irq_exit_irqson()); \
|
||||
TP_CONDITION(cond), 1); \
|
||||
}
|
||||
#else
|
||||
#define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args)
|
||||
|
@ -186,7 +189,7 @@ extern void syscall_unregfunc(void);
|
|||
__DO_TRACE(&__tracepoint_##name, \
|
||||
TP_PROTO(data_proto), \
|
||||
TP_ARGS(data_args), \
|
||||
TP_CONDITION(cond),,); \
|
||||
TP_CONDITION(cond), 0); \
|
||||
if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) { \
|
||||
rcu_read_lock_sched_notrace(); \
|
||||
rcu_dereference_sched(__tracepoint_##name.funcs);\
|
||||
|
|
Загрузка…
Ссылка в новой задаче