Tracepoints require that RCU is watching. To prevent them from being used in places that RCU is not watching, the trace_##event() macro always calls rcu_is_watching() even when the event is not enabled and warns if RCU is not watching. This is to make sure a warning is triggered even if the tracepoint is never enabled (as it is only a bug when it is). It was noticed that tracepoints could be hidden within trace_#event#_enabled() calls, which are used to do extra work for the tracepoint only if the tracepoint is enabled. But this also can hide the fact that a tracepoint is placed in a location that can be called when RCU is not watching. Commit 9764e731ef6ab ("tracepoint: Add lockdep rcu_is_watching() check to trace_##name##_enabled()") added a check to the trace_##event##_enabled() macro to make sure RCU is watching when it is called to make sure not to hide the bug of a tracepoint being called when RCU is not watching. There is one case in the irq_disable tracepoint where it is within a trace_irq_disable_enabled() block, but it checks if RCU is watching, and if it isn't, it makes a call to ct_irq_enter() that makes RCU watch again. But because trace_irq_disable_enabled() now checks if RCU is watching and will trigger if it isn't. This is a false warning as the code within the block handles this case. Add a new internal macro __trace_##event##_enabled() that doesn't check if RCU is watching, and convert the irq_enable/disable tracepoints over to it.
Unified · Split
| @@ -292,13 +292,18 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) · 291 unmodified lines | |||
| 292 | { \ | 292 | { \ |
| 293 | } \ | 293 | } \ |
| 294 | static inline bool \ | 294 | static inline bool \ |
| 295 | __trace_##name##_enabled(void) \ | ||
| 296 | { \ | ||
| 297 | return static_branch_unlikely(&__tracepoint_##name.key);\ | ||
| 298 | } \ | ||
| 299 | static inline bool \ | ||
| 295 | trace_##name##_enabled(void) \ | 300 | trace_##name##_enabled(void) \ |
| 296 | { \ | 301 | { \ |
| 297 | if (IS_ENABLED(CONFIG_LOCKDEP)) { \ | 302 | if (IS_ENABLED(CONFIG_LOCKDEP)) { \ |
| 298 | WARN_ONCE(!rcu_is_watching(), \ | 303 | WARN_ONCE(!rcu_is_watching(), \ |
| 299 | "RCU not watching for tracepoint"); \ | 304 | "RCU not watching for tracepoint"); \ |
| 300 | } \ | 305 | } \ |
| 301 | return static_branch_unlikely(&__tracepoint_##name.key);\ | 306 | return __trace_##name##_enabled(); \ |
| 302 | } | 307 | } |
| 303 | 308 | ||
| 304 | #define __DECLARE_TRACE(name, proto, args, cond, data_proto) \ | 309 | #define __DECLARE_TRACE(name, proto, args, cond, data_proto) \ |
| @@ -457,6 +462,11 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) · 152 unmodified lines | |||
| 457 | { \ | 462 | { \ |
| 458 | } \ | 463 | } \ |
| 459 | static inline bool \ | 464 | static inline bool \ |
| 465 | __trace_##name##_enabled(void) \ | ||
| 466 | { \ | ||
| 467 | return false; \ | ||
| 468 | } \ | ||
| 469 | static inline bool \ | ||
| 460 | trace_##name##_enabled(void) \ | 470 | trace_##name##_enabled(void) \ |
| 461 | { \ | 471 | { \ |
| 462 | return false; \ | 472 | return false; \ |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | |||
| 30 | #else | 30 | #else |
| 31 | #define trace(point, args) \ | 31 | #define trace(point, args) \ |
| 32 | do { \ | 32 | do { \ |
| 33 | if (trace_##point##_enabled()) { \ | 33 | if (__trace_##point##_enabled()) { \ |
| 34 | bool exit_rcu = false; \ | 34 | bool exit_rcu = false; \ |
| 35 | if (in_nmi()) \ | 35 | if (in_nmi()) \ |
| 36 | break; \ | 36 | break; \ |