Skip to content

Commit e918188

Browse files
fbqPeter Zijlstra
authored andcommitted
locking: More accurate annotations for read_lock()
On the archs using QUEUED_RWLOCKS, read_lock() is not always a recursive read lock, actually it's only recursive if in_interrupt() is true. So change the annotation accordingly to catch more deadlocks. Note we used to treat read_lock() as pure recursive read locks in lib/locking-seftest.c, and this is useful, especially for the lockdep development selftest, so we keep this via a variable to force switching lock annotation for read_lock(). 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 92b4e9f commit e918188

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

include/linux/lockdep.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,20 @@ static inline void print_irqtrace_events(struct task_struct *curr)
469469
}
470470
#endif
471471

472+
/* Variable used to make lockdep treat read_lock() as recursive in selftests */
473+
#ifdef CONFIG_DEBUG_LOCKING_API_SELFTESTS
474+
extern unsigned int force_read_lock_recursive;
475+
#else /* CONFIG_DEBUG_LOCKING_API_SELFTESTS */
476+
#define force_read_lock_recursive 0
477+
#endif /* CONFIG_DEBUG_LOCKING_API_SELFTESTS */
478+
479+
#ifdef CONFIG_LOCKDEP
480+
extern bool read_lock_is_recursive(void);
481+
#else /* CONFIG_LOCKDEP */
482+
/* If !LOCKDEP, the value is meaningless */
483+
#define read_lock_is_recursive() 0
484+
#endif
485+
472486
/*
473487
* For trivial one-depth nesting of a lock-class, the following
474488
* global define can be used. (Subsystems with multiple levels
@@ -490,7 +504,14 @@ static inline void print_irqtrace_events(struct task_struct *curr)
490504
#define spin_release(l, i) lock_release(l, i)
491505

492506
#define rwlock_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i)
493-
#define rwlock_acquire_read(l, s, t, i) lock_acquire_shared_recursive(l, s, t, NULL, i)
507+
#define rwlock_acquire_read(l, s, t, i) \
508+
do { \
509+
if (read_lock_is_recursive()) \
510+
lock_acquire_shared_recursive(l, s, t, NULL, i); \
511+
else \
512+
lock_acquire_shared(l, s, t, NULL, i); \
513+
} while (0)
514+
494515
#define rwlock_release(l, i) lock_release(l, i)
495516

496517
#define seqcount_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i)

kernel/locking/lockdep.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4967,6 +4967,20 @@ static bool lockdep_nmi(void)
49674967
return true;
49684968
}
49694969

4970+
/*
4971+
* read_lock() is recursive if:
4972+
* 1. We force lockdep think this way in selftests or
4973+
* 2. The implementation is not queued read/write lock or
4974+
* 3. The locker is at an in_interrupt() context.
4975+
*/
4976+
bool read_lock_is_recursive(void)
4977+
{
4978+
return force_read_lock_recursive ||
4979+
!IS_ENABLED(CONFIG_QUEUED_RWLOCKS) ||
4980+
in_interrupt();
4981+
}
4982+
EXPORT_SYMBOL_GPL(read_lock_is_recursive);
4983+
49704984
/*
49714985
* We are not always called with irqs disabled - do that here,
49724986
* and also avoid lockdep recursion:

lib/locking-selftest.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* Change this to 1 if you want to see the failure printouts:
2929
*/
3030
static unsigned int debug_locks_verbose;
31+
unsigned int force_read_lock_recursive;
3132

3233
static DEFINE_WD_CLASS(ww_lockdep);
3334

@@ -1978,6 +1979,11 @@ void locking_selftest(void)
19781979
return;
19791980
}
19801981

1982+
/*
1983+
* treats read_lock() as recursive read locks for testing purpose
1984+
*/
1985+
force_read_lock_recursive = 1;
1986+
19811987
/*
19821988
* Run the testsuite:
19831989
*/
@@ -2073,6 +2079,11 @@ void locking_selftest(void)
20732079

20742080
ww_tests();
20752081

2082+
force_read_lock_recursive = 0;
2083+
/*
2084+
* queued_read_lock() specific test cases can be put here
2085+
*/
2086+
20762087
if (unexpected_testcase_failures) {
20772088
printk("-----------------------------------------------------------------\n");
20782089
debug_locks = 0;

0 commit comments

Comments
 (0)