Passing a complex lockdep condition to __list_check_rcu results in false positive lockdep splat due to incorrect expression evaluation. For example, a lockdep check condition `cond1 || cond2` is evaluated as `!cond1 || cond2 && !rcu_read_lock_any_held()` which, according to operator precedence, evaluates to `!cond1 || (cond2 && !rcu_read_lock_any_held())`. This would result in a lockdep splat when cond1 is false and cond2 is true which is logically incorrect.
Showing the changes to include/linux (1 of 1 file). Show all
Unified · Split
| @@ -60,9 +60,9 @@ static inline void INIT_LIST_HEAD_RCU(struct list_head *list) · 59 unmodified lines | |||
| 60 | #define __list_check_rcu(dummy, cond, extra...) \ | 60 | #define __list_check_rcu(dummy, cond, extra...) \ |
| 61 | ({ \ | 61 | ({ \ |
| 62 | check_arg_count_one(extra); \ | 62 | check_arg_count_one(extra); \ |
| 63 | RCU_LOCKDEP_WARN(!cond && !rcu_read_lock_any_held(), \ | 63 | RCU_LOCKDEP_WARN(!(cond) && !rcu_read_lock_any_held(), \ |
| 64 | "RCU-list traversed in non-reader section!"); \ | 64 | "RCU-list traversed in non-reader section!"); \ |
| 65 | }) | 65 | }) |
| 66 | #else | 66 | #else |
| 67 | #define __list_check_rcu(dummy, cond, extra...) \ | 67 | #define __list_check_rcu(dummy, cond, extra...) \ |
| 68 | ({ check_arg_count_one(extra); }) | 68 | ({ check_arg_count_one(extra); }) |