From: Uladzislau Rezki (Sony) Date: Wed, 14 Feb 2024 22:45:53 +0000 (-0800) Subject: rcu: Update lockdep while in RCU read-side critical section X-Git-Tag: v6.10-rc1~234^2~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=058e87782c91696020bdb0aa28ddf77d89aed266;p=thirdparty%2Fkernel%2Flinux.git rcu: Update lockdep while in RCU read-side critical section With Ankur's lazy-/auto-preemption patches applied and with a lazy-preemptible kernel in combination with a non-preemptible RCU, lockdep sometimes complains about context switches within RCU read-side critical sections. This is a false positive due to rcu_read_unlock() updating lockdep state too late: __release(RCU); __rcu_read_unlock(); // Context switch here results in lockdep false positive!!! rcu_lock_release(&rcu_lock_map); /* Keep acq info for rls diags. */ Although this complaint could also happen with preemptible RCU in a preemptible kernel, the odds of that happening aer quite low. In constrast, with non-preemptible RCU, a long critical section has a high probability of performing a context switch from the preempt_enable() in __rcu_read_unlock(). The fix is straightforward, just move the rcu_lock_release() within rcu_read_unlock() to obtain the reverse order from that of rcu_read_lock(): rcu_lock_release(&rcu_lock_map); /* Keep acq info for rls diags. */ __release(RCU); __rcu_read_unlock(); This commit makes this change. Co-developed-by: Frederic Weisbecker Signed-off-by: Frederic Weisbecker Co-developed-by: Joel Fernandes (Google) Signed-off-by: Joel Fernandes (Google) Co-developed-by: Boqun Feng Signed-off-by: Boqun Feng Signed-off-by: Uladzislau Rezki (Sony) Reviewed-by: Paul E. McKenney Cc: Ankur Arora Cc: Thomas Gleixner --- diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 17d7ed5f3ae6e..2c54750e36a06 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -809,9 +809,9 @@ static inline void rcu_read_unlock(void) { RCU_LOCKDEP_WARN(!rcu_is_watching(), "rcu_read_unlock() used illegally while idle"); + rcu_lock_release(&rcu_lock_map); /* Keep acq info for rls diags. */ __release(RCU); __rcu_read_unlock(); - rcu_lock_release(&rcu_lock_map); /* Keep acq info for rls diags. */ } /**