rcu: Reverse rcu_dereference_check() conditions
The rcu_dereference_check() family of primitives evaluates the RCU lockdep expression first, and only then evaluates the expression passed in. This works fine normally, but can potentially fail in environments (such as NMI handlers) where lockdep cannot be invoked. The problem is that even if the expression passed in is "1", the compiler would need to prove that the RCU lockdep expression (rcu_read_lock_held(), for example) is free of side effects in order to be able to elide it. Given that rcu_read_lock_held() is sometimes separately compiled, the compiler cannot always use this optimization. This commit therefore reverse the order of evaluation, so that the expression passed in is evaluated first, and the RCU lockdep expression is evaluated only if the passed-in expression evaluated to false, courtesy of the C-language short-circuit boolean evaluation rules. This compells the compiler to forego executing the RCU lockdep expression in cases where the passed-in expression evaluates to "1" at compile time, so that (for example) rcu_dereference_raw() can be guaranteed to execute safely within an NMI handler. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
This commit is contained in:
parent
a3bd2c09ad
commit
b826565aaf
|
@ -729,7 +729,7 @@ static inline void rcu_preempt_sleep_check(void)
|
|||
* annotated as __rcu.
|
||||
*/
|
||||
#define rcu_dereference_check(p, c) \
|
||||
__rcu_dereference_check((p), rcu_read_lock_held() || (c), __rcu)
|
||||
__rcu_dereference_check((p), (c) || rcu_read_lock_held(), __rcu)
|
||||
|
||||
/**
|
||||
* rcu_dereference_bh_check() - rcu_dereference_bh with debug checking
|
||||
|
@ -739,7 +739,7 @@ static inline void rcu_preempt_sleep_check(void)
|
|||
* This is the RCU-bh counterpart to rcu_dereference_check().
|
||||
*/
|
||||
#define rcu_dereference_bh_check(p, c) \
|
||||
__rcu_dereference_check((p), rcu_read_lock_bh_held() || (c), __rcu)
|
||||
__rcu_dereference_check((p), (c) || rcu_read_lock_bh_held(), __rcu)
|
||||
|
||||
/**
|
||||
* rcu_dereference_sched_check() - rcu_dereference_sched with debug checking
|
||||
|
@ -749,7 +749,7 @@ static inline void rcu_preempt_sleep_check(void)
|
|||
* This is the RCU-sched counterpart to rcu_dereference_check().
|
||||
*/
|
||||
#define rcu_dereference_sched_check(p, c) \
|
||||
__rcu_dereference_check((p), rcu_read_lock_sched_held() || (c), \
|
||||
__rcu_dereference_check((p), (c) || rcu_read_lock_sched_held(), \
|
||||
__rcu)
|
||||
|
||||
#define rcu_dereference_raw(p) rcu_dereference_check(p, 1) /*@@@ needed? @@@*/
|
||||
|
|
|
@ -182,7 +182,7 @@ static inline int srcu_read_lock_held(struct srcu_struct *sp)
|
|||
* lockdep_is_held() calls.
|
||||
*/
|
||||
#define srcu_dereference_check(p, sp, c) \
|
||||
__rcu_dereference_check((p), srcu_read_lock_held(sp) || (c), __rcu)
|
||||
__rcu_dereference_check((p), (c) || srcu_read_lock_held(sp), __rcu)
|
||||
|
||||
/**
|
||||
* srcu_dereference - fetch SRCU-protected pointer for later dereferencing
|
||||
|
|
Loading…
Reference in New Issue