Skip to content

Commit d61fc96

Browse files
fbqPeter Zijlstra
authored andcommitted
lockdep: Avoid to modify chain keys in validate_chain()
Chris Wilson reported a problem spotted by check_chain_key(): a chain key got changed in validate_chain() because we modify the ->read in validate_chain() to skip checks for dependency adding, and ->read is taken into calculation for chain key since commit f611e8c ("lockdep: Take read/write status in consideration when generate chainkey"). Fix this by avoiding to modify ->read in validate_chain() based on two facts: a) since we now support recursive read lock detection, there is no need to skip checks for dependency adding for recursive readers, b) since we have a), there is only one case left (nest_lock) where we want to skip checks in validate_chain(), we simply remove the modification for ->read and rely on the return value of check_deadlock() to skip the dependency adding. Reported-by: Chris Wilson <[email protected]> Signed-off-by: Boqun Feng <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 1e106aa commit d61fc96

File tree

1 file changed

+9
-10
lines changed

1 file changed

+9
-10
lines changed

kernel/locking/lockdep.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2765,7 +2765,9 @@ print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
27652765
* (Note that this has to be done separately, because the graph cannot
27662766
* detect such classes of deadlocks.)
27672767
*
2768-
* Returns: 0 on deadlock detected, 1 on OK, 2 on recursive read
2768+
* Returns: 0 on deadlock detected, 1 on OK, 2 if another lock with the same
2769+
* lock class is held but nest_lock is also held, i.e. we rely on the
2770+
* nest_lock to avoid the deadlock.
27692771
*/
27702772
static int
27712773
check_deadlock(struct task_struct *curr, struct held_lock *next)
@@ -2788,7 +2790,7 @@ check_deadlock(struct task_struct *curr, struct held_lock *next)
27882790
* lock class (i.e. read_lock(lock)+read_lock(lock)):
27892791
*/
27902792
if ((next->read == 2) && prev->read)
2791-
return 2;
2793+
continue;
27922794

27932795
/*
27942796
* We're holding the nest_lock, which serializes this lock's
@@ -3592,16 +3594,13 @@ static int validate_chain(struct task_struct *curr,
35923594

35933595
if (!ret)
35943596
return 0;
3595-
/*
3596-
* Mark recursive read, as we jump over it when
3597-
* building dependencies (just like we jump over
3598-
* trylock entries):
3599-
*/
3600-
if (ret == 2)
3601-
hlock->read = 2;
36023597
/*
36033598
* Add dependency only if this lock is not the head
3604-
* of the chain, and if it's not a secondary read-lock:
3599+
* of the chain, and if the new lock introduces no more
3600+
* lock dependency (because we already hold a lock with the
3601+
* same lock class) nor deadlock (because the nest_lock
3602+
* serializes nesting locks), see the comments for
3603+
* check_deadlock().
36053604
*/
36063605
if (!chain_head && ret != 2) {
36073606
if (!check_prevs_add(curr, hlock))

0 commit comments

Comments
 (0)