locking/selftest: Add test cases for queued_read_lock()
Add two self test cases for the following case: P0: P1: P2: <in irq handler> spin_lock_irq(&slock) read_lock(&rwlock) write_lock_irq(&rwlock) read_lock(&rwlock) spin_lock(&slock) , which is a deadlock, as the read_lock() on P0 cannot get the lock because of the fairness. P0: P1: P2: <in irq handler> spin_lock(&slock) read_lock(&rwlock) write_lock(&rwlock) read_lock(&rwlock) spin_lock_irq(&slock) , which is not a deadlock, as the read_lock() on P0 can get the lock because it could use the unfair fastpass. Signed-off-by: Boqun Feng <boqun.feng@gmail.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lkml.kernel.org/r/20200807074238.1632519-19-boqun.feng@gmail.com
This commit is contained in:
parent
108dc42ed3
commit
ad56450db8
@ -2201,6 +2201,108 @@ static void ww_tests(void)
|
|||||||
pr_cont("\n");
|
pr_cont("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* <in hardirq handler>
|
||||||
|
* read_lock(&A);
|
||||||
|
* <hardirq disable>
|
||||||
|
* spin_lock(&B);
|
||||||
|
* spin_lock(&B);
|
||||||
|
* read_lock(&A);
|
||||||
|
*
|
||||||
|
* is a deadlock.
|
||||||
|
*/
|
||||||
|
static void queued_read_lock_hardirq_RE_Er(void)
|
||||||
|
{
|
||||||
|
HARDIRQ_ENTER();
|
||||||
|
read_lock(&rwlock_A);
|
||||||
|
LOCK(B);
|
||||||
|
UNLOCK(B);
|
||||||
|
read_unlock(&rwlock_A);
|
||||||
|
HARDIRQ_EXIT();
|
||||||
|
|
||||||
|
HARDIRQ_DISABLE();
|
||||||
|
LOCK(B);
|
||||||
|
read_lock(&rwlock_A);
|
||||||
|
read_unlock(&rwlock_A);
|
||||||
|
UNLOCK(B);
|
||||||
|
HARDIRQ_ENABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* <in hardirq handler>
|
||||||
|
* spin_lock(&B);
|
||||||
|
* <hardirq disable>
|
||||||
|
* read_lock(&A);
|
||||||
|
* read_lock(&A);
|
||||||
|
* spin_lock(&B);
|
||||||
|
*
|
||||||
|
* is not a deadlock.
|
||||||
|
*/
|
||||||
|
static void queued_read_lock_hardirq_ER_rE(void)
|
||||||
|
{
|
||||||
|
HARDIRQ_ENTER();
|
||||||
|
LOCK(B);
|
||||||
|
read_lock(&rwlock_A);
|
||||||
|
read_unlock(&rwlock_A);
|
||||||
|
UNLOCK(B);
|
||||||
|
HARDIRQ_EXIT();
|
||||||
|
|
||||||
|
HARDIRQ_DISABLE();
|
||||||
|
read_lock(&rwlock_A);
|
||||||
|
LOCK(B);
|
||||||
|
UNLOCK(B);
|
||||||
|
read_unlock(&rwlock_A);
|
||||||
|
HARDIRQ_ENABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* <hardirq disable>
|
||||||
|
* spin_lock(&B);
|
||||||
|
* read_lock(&A);
|
||||||
|
* <in hardirq handler>
|
||||||
|
* spin_lock(&B);
|
||||||
|
* read_lock(&A);
|
||||||
|
*
|
||||||
|
* is a deadlock. Because the two read_lock()s are both non-recursive readers.
|
||||||
|
*/
|
||||||
|
static void queued_read_lock_hardirq_inversion(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
HARDIRQ_ENTER();
|
||||||
|
LOCK(B);
|
||||||
|
UNLOCK(B);
|
||||||
|
HARDIRQ_EXIT();
|
||||||
|
|
||||||
|
HARDIRQ_DISABLE();
|
||||||
|
LOCK(B);
|
||||||
|
read_lock(&rwlock_A);
|
||||||
|
read_unlock(&rwlock_A);
|
||||||
|
UNLOCK(B);
|
||||||
|
HARDIRQ_ENABLE();
|
||||||
|
|
||||||
|
read_lock(&rwlock_A);
|
||||||
|
read_unlock(&rwlock_A);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void queued_read_lock_tests(void)
|
||||||
|
{
|
||||||
|
printk(" --------------------------------------------------------------------------\n");
|
||||||
|
printk(" | queued read lock tests |\n");
|
||||||
|
printk(" ---------------------------\n");
|
||||||
|
print_testname("hardirq read-lock/lock-read");
|
||||||
|
dotest(queued_read_lock_hardirq_RE_Er, FAILURE, LOCKTYPE_RWLOCK);
|
||||||
|
pr_cont("\n");
|
||||||
|
|
||||||
|
print_testname("hardirq lock-read/read-lock");
|
||||||
|
dotest(queued_read_lock_hardirq_ER_rE, SUCCESS, LOCKTYPE_RWLOCK);
|
||||||
|
pr_cont("\n");
|
||||||
|
|
||||||
|
print_testname("hardirq inversion");
|
||||||
|
dotest(queued_read_lock_hardirq_inversion, FAILURE, LOCKTYPE_RWLOCK);
|
||||||
|
pr_cont("\n");
|
||||||
|
}
|
||||||
|
|
||||||
void locking_selftest(void)
|
void locking_selftest(void)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -2318,6 +2420,8 @@ void locking_selftest(void)
|
|||||||
/*
|
/*
|
||||||
* queued_read_lock() specific test cases can be put here
|
* queued_read_lock() specific test cases can be put here
|
||||||
*/
|
*/
|
||||||
|
if (IS_ENABLED(CONFIG_QUEUED_RWLOCKS))
|
||||||
|
queued_read_lock_tests();
|
||||||
|
|
||||||
if (unexpected_testcase_failures) {
|
if (unexpected_testcase_failures) {
|
||||||
printk("-----------------------------------------------------------------\n");
|
printk("-----------------------------------------------------------------\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user