mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-18 18:23:53 +08:00
rcu: Annotate SRCU's update-side lockdep dependencies
Although all flavors of RCU readers are annotated correctly with lockdep as recursive read locks, they do not set the lock_acquire 'check' parameter. This means that RCU read locks are not added to the lockdep dependency graph, which in turn means that lockdep cannot detect RCU-based deadlocks. This is not a problem for RCU flavors having atomic read-side critical sections because context-based annotations can catch these deadlocks, see for example the RCU_LOCKDEP_WARN() statement in synchronize_rcu(). But context-based annotations are not helpful for sleepable RCU, especially given that it is perfectly legal to do synchronize_srcu(&srcu1) within an srcu_read_lock(&srcu2). However, we can detect SRCU-based 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. This commit therefore makes it so. Note that NMI-safe SRCU read side critical sections are currently not annotated, but might be annotated in the future. Signed-off-by: Boqun Feng <boqun.feng@gmail.com> Signed-off-by: Paul E. McKenney <paulmck@kernel.org> [ boqun: Add comments for annotation per Waiman's suggestion ] [ boqun: Fix comment warning reported by Stephen Rothwell ] Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
This commit is contained in:
parent
2f1f043e7b
commit
f0f44752f5
@ -102,6 +102,32 @@ static inline int srcu_read_lock_held(const struct srcu_struct *ssp)
|
||||
return lock_is_held(&ssp->dep_map);
|
||||
}
|
||||
|
||||
/*
|
||||
* Annotations provide deadlock detection for SRCU.
|
||||
*
|
||||
* Similar to other lockdep annotations, except there is an additional
|
||||
* srcu_lock_sync(), which is basically an empty *write*-side critical section,
|
||||
* see lock_sync() for more information.
|
||||
*/
|
||||
|
||||
/* Annotates a srcu_read_lock() */
|
||||
static inline void srcu_lock_acquire(struct lockdep_map *map)
|
||||
{
|
||||
lock_map_acquire_read(map);
|
||||
}
|
||||
|
||||
/* Annotates a srcu_read_lock() */
|
||||
static inline void srcu_lock_release(struct lockdep_map *map)
|
||||
{
|
||||
lock_map_release(map);
|
||||
}
|
||||
|
||||
/* Annotates a synchronize_srcu() */
|
||||
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 +135,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 +212,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;
|
||||
}
|
||||
|
||||
@ -254,7 +284,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);
|
||||
}
|
||||
|
||||
|
@ -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) ||
|
||||
|
@ -1307,6 +1307,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) ||
|
||||
|
Loading…
Reference in New Issue
Block a user