[RFC v4 1/4] tracepoint: Add API to not do lockdep checks during RCU ops

From: Joel Fernandes
Date: Tue Apr 17 2018 - 00:08:37 EST


This series makes lockdeps use the trace irqs on/off tracepoints. Lets
introduce an API where lockdep checks are not done so that we don't get
false lockdep splats. This API introduction will not affect any of the
existing users of the tracepoint API and the new call will only be used
by the IRQs on/off tracepoints.

Cc: Steven Rostedt <rostedt@xxxxxxxxxxx>
Cc: Peter Zilstra <peterz@xxxxxxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: Mathieu Desnoyers <mathieu.desnoyers@xxxxxxxxxxxx>
Cc: Tom Zanussi <tom.zanussi@xxxxxxxxxxxxxxx>
Cc: Namhyung Kim <namhyung@xxxxxxxxxx>
Cc: Thomas Glexiner <tglx@xxxxxxxxxxxxx>
Cc: Boqun Feng <boqun.feng@xxxxxxxxx>
Cc: Paul McKenney <paulmck@xxxxxxxxxxxxxxxxxx>
Cc: Frederic Weisbecker <fweisbec@xxxxxxxxx>
Cc: Randy Dunlap <rdunlap@xxxxxxxxxxxxx>
Cc: Masami Hiramatsu <mhiramat@xxxxxxxxxx>
Cc: Fenguang Wu <fengguang.wu@xxxxxxxxx>
Cc: Baohong Liu <baohong.liu@xxxxxxxxx>
Cc: Vedang Patel <vedang.patel@xxxxxxxxx>
Signed-off-by: Joel Fernandes <joelaf@xxxxxxxxxx>
---
include/linux/tracepoint.h | 32 +++++++++++++++++++++++++++++---
1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index c94f466d57ef..0b6d7d1a16e2 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -119,6 +119,14 @@ extern void syscall_unregfunc(void);

#ifdef TRACEPOINTS_ENABLED

+#define LOCKDEP_CHECKS_ON(lockdep) \
+ if (IS_ENABLED(CONFIG_LOCKDEP) && !lockdep) \
+ lockdep_on();
+
+#define LOCKDEP_CHECKS_OFF(lockdep) \
+ if (IS_ENABLED(CONFIG_LOCKDEP) && !lockdep) \
+ lockdep_off();
+
/*
* it_func[0] is never NULL because there is at least one element in the array
* when the array itself is non NULL.
@@ -129,7 +137,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, rcucheck) \
+#define __DO_TRACE(tp, proto, args, cond, rcucheck, lockdep) \
do { \
struct tracepoint_func *it_func_ptr; \
void *it_func; \
@@ -137,10 +145,14 @@ extern void syscall_unregfunc(void);
\
if (!(cond)) \
return; \
+ \
+ LOCKDEP_CHECKS_OFF(lockdep) \
if (rcucheck) \
rcu_irq_enter_irqson(); \
rcu_read_lock_sched_notrace(); \
it_func_ptr = rcu_dereference_sched((tp)->funcs); \
+ LOCKDEP_CHECKS_ON(lockdep) \
+ \
if (it_func_ptr) { \
do { \
it_func = (it_func_ptr)->func; \
@@ -148,9 +160,12 @@ extern void syscall_unregfunc(void);
((void(*)(proto))(it_func))(args); \
} while ((++it_func_ptr)->func); \
} \
+ \
+ LOCKDEP_CHECKS_OFF(lockdep) \
rcu_read_unlock_sched_notrace(); \
if (rcucheck) \
rcu_irq_exit_irqson(); \
+ LOCKDEP_CHECKS_ON(lockdep) \
} while (0)

#ifndef MODULE
@@ -161,7 +176,16 @@ extern void syscall_unregfunc(void);
__DO_TRACE(&__tracepoint_##name, \
TP_PROTO(data_proto), \
TP_ARGS(data_args), \
- TP_CONDITION(cond), 1); \
+ TP_CONDITION(cond), 1, 1); \
+ } \
+ \
+ static inline void trace_##name##_rcuidle_nolockdep(proto) \
+ { \
+ if (static_key_false(&__tracepoint_##name.key)) \
+ __DO_TRACE(&__tracepoint_##name, \
+ TP_PROTO(data_proto), \
+ TP_ARGS(data_args), \
+ TP_CONDITION(cond), 1, 0); \
}
#else
#define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args)
@@ -187,7 +211,7 @@ extern void syscall_unregfunc(void);
__DO_TRACE(&__tracepoint_##name, \
TP_PROTO(data_proto), \
TP_ARGS(data_args), \
- TP_CONDITION(cond), 0); \
+ TP_CONDITION(cond), 0, 1); \
if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) { \
rcu_read_lock_sched_notrace(); \
rcu_dereference_sched(__tracepoint_##name.funcs);\
@@ -254,6 +278,8 @@ extern void syscall_unregfunc(void);
{ } \
static inline void trace_##name##_rcuidle(proto) \
{ } \
+ static inline void trace_##name##_rcuidle_nolockdep(proto) \
+ { } \
static inline int \
register_trace_##name(void (*probe)(data_proto), \
void *data) \
--
2.17.0.484.g0c8726318c-goog