On Thu, Jan 12, 2023 at 10:59:54PM -0800, Boqun Feng wrote: > Although all flavors of RCU are annotated correctly with lockdep as > recursive read locks, their 'check' parameter of lock_acquire() is > unset. It means that RCU read locks are not added into the lockdep > dependency graph therefore deadlock detection based on dependency graph > won't catch deadlock caused by RCU. This is fine for "non-sleepable" RCU > flavors since wait-context detection and other context based detection > can catch these deadlocks. However for sleepable RCU, this is limited. > > Actually we can detect the deadlocks caused by SRCU by 1) making > srcu_read_lock() a 'check'ed recursive read lock and 2) making > synchronize_srcu() a empty write lock critical section. Even better, > with the newly introduced lock_sync(), we can avoid false positives > about irq-unsafe/safe. So do it. > > Note that NMI safe SRCU read side critical sections are currently not > annonated, since step-by-step approach can help us deal with > false-positives. These may be annotated in the future. > > Signed-off-by: Boqun Feng <boqun.feng@xxxxxxxxx> Nice, thank you!!! Acked-by: Paul E. McKenney <paulmck@xxxxxxxxxx> Or if you would prefer that I take the series through -rcu, please just let me know. Thanx, Paul > --- > include/linux/srcu.h | 23 +++++++++++++++++++++-- > kernel/rcu/srcutiny.c | 2 ++ > kernel/rcu/srcutree.c | 2 ++ > 3 files changed, 25 insertions(+), 2 deletions(-) > > diff --git a/include/linux/srcu.h b/include/linux/srcu.h > index 9b9d0bbf1d3c..a1595f8c5155 100644 > --- a/include/linux/srcu.h > +++ b/include/linux/srcu.h > @@ -102,6 +102,21 @@ static inline int srcu_read_lock_held(const struct srcu_struct *ssp) > return lock_is_held(&ssp->dep_map); > } > > +static inline void srcu_lock_acquire(struct lockdep_map *map) > +{ > + lock_map_acquire_read(map); > +} > + > +static inline void srcu_lock_release(struct lockdep_map *map) > +{ > + lock_map_release(map); > +} > + > +static inline void srcu_lock_sync(struct lockdep_map *map) > +{ > + lock_map_sync(map); > +} > + > #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ > > static inline int srcu_read_lock_held(const struct srcu_struct *ssp) > @@ -109,6 +124,10 @@ static inline int srcu_read_lock_held(const struct srcu_struct *ssp) > return 1; > } > > +#define srcu_lock_acquire(m) do { } while (0) > +#define srcu_lock_release(m) do { } while (0) > +#define srcu_lock_sync(m) do { } while (0) > + > #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ > > #define SRCU_NMI_UNKNOWN 0x0 > @@ -182,7 +201,7 @@ static inline int srcu_read_lock(struct srcu_struct *ssp) __acquires(ssp) > > srcu_check_nmi_safety(ssp, false); > retval = __srcu_read_lock(ssp); > - rcu_lock_acquire(&(ssp)->dep_map); > + srcu_lock_acquire(&(ssp)->dep_map); > return retval; > } > > @@ -226,7 +245,7 @@ static inline void srcu_read_unlock(struct srcu_struct *ssp, int idx) > { > WARN_ON_ONCE(idx & ~0x1); > srcu_check_nmi_safety(ssp, false); > - rcu_lock_release(&(ssp)->dep_map); > + srcu_lock_release(&(ssp)->dep_map); > __srcu_read_unlock(ssp, idx); > } > > diff --git a/kernel/rcu/srcutiny.c b/kernel/rcu/srcutiny.c > index b12fb0cec44d..336af24e0fe3 100644 > --- a/kernel/rcu/srcutiny.c > +++ b/kernel/rcu/srcutiny.c > @@ -197,6 +197,8 @@ void synchronize_srcu(struct srcu_struct *ssp) > { > struct rcu_synchronize rs; > > + srcu_lock_sync(&ssp->dep_map); > + > RCU_LOCKDEP_WARN(lockdep_is_held(ssp) || > lock_is_held(&rcu_bh_lock_map) || > lock_is_held(&rcu_lock_map) || > diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c > index ca4b5dcec675..408088c73e0e 100644 > --- a/kernel/rcu/srcutree.c > +++ b/kernel/rcu/srcutree.c > @@ -1267,6 +1267,8 @@ static void __synchronize_srcu(struct srcu_struct *ssp, bool do_norm) > { > struct rcu_synchronize rcu; > > + srcu_lock_sync(&ssp->dep_map); > + > RCU_LOCKDEP_WARN(lockdep_is_held(ssp) || > lock_is_held(&rcu_bh_lock_map) || > lock_is_held(&rcu_lock_map) || > -- > 2.38.1 >