[RFC][PATCH 1/7] lockdep: Implement extra recursive-read lock tests

From: Peter Zijlstra
Date: Sun Apr 17 2011 - 05:58:50 EST


Lockdep is not able to detect simple rw deadlocks because it is not
tracking recursive read dependencies:

read_lock(A) --> spin_lock(B)
spin_lock(B) --> write_lock(A) /* should fail */

Furthermore, the following should not result in a deadlock for
recursive read locks:

read_lock(A) --> spin_lock(B)
spin_lock(B) --> read_lock(A) /* success */

Add these checks so that we may improve lockdep to accurately track
recursive read locks and report the correct answers.

Signed-off-by: Peter Zijlstra <a.p.zijlstra@xxxxxxxxx>
---
lib/locking-selftest.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)

Index: tip/lib/locking-selftest.c
===================================================================
--- tip.orig/lib/locking-selftest.c
+++ tip/lib/locking-selftest.c
@@ -185,13 +185,16 @@ static void init_shared_classes(void)

#define ML(x) mutex_lock(&mutex_##x)
#define MU(x) mutex_unlock(&mutex_##x)
+#define MLU(x) ML(x); MU(x)
#define MI(x) mutex_init(&mutex_##x)

#define WSL(x) down_write(&rwsem_##x)
#define WSU(x) up_write(&rwsem_##x)
+#define WSLU(x) WSL(x); WSU(x)

#define RSL(x) down_read(&rwsem_##x)
#define RSU(x) up_read(&rwsem_##x)
+#define RSLU(x) RSL(x); RSU(x)
#define RWSI(x) init_rwsem(&rwsem_##x)

#define LOCK_UNLOCK_2(x,y) LOCK(x); LOCK(y); UNLOCK(y); UNLOCK(x)
@@ -300,6 +303,50 @@ static void rsem_AA3(void)
RSL(X2); // this one should fail
}

+static void rwlock_spinlock_ABBA(void)
+{
+ RL(A);
+ LU(B);
+ RU(A);
+
+ L(B);
+ WLU(A); /* fail */
+ U(B);
+}
+
+static void rlock_spinlock_ABBA(void)
+{
+ RL(A);
+ LU(B);
+ RU(A);
+
+ L(B);
+ RLU(A); /* not fail */
+ U(B);
+}
+
+static void rwsem_mutex_ABBA(void)
+{
+ RSL(A);
+ MLU(B);
+ RSU(A);
+
+ ML(B);
+ WSLU(A); /* fail */
+ MU(B);
+}
+
+static void rsem_mutex_ABBA(void)
+{
+ RSL(A);
+ MLU(B);
+ RSU(A);
+
+ ML(B);
+ RSLU(A); /* fail */
+ MU(B);
+}
+
/*
* ABBA deadlock:
*/
@@ -1174,6 +1221,20 @@ void locking_selftest(void)
dotest(rsem_AA3, FAILURE, LOCKTYPE_RWSEM);
printk("\n");

+ print_testname("mixed write-spin-read-lock");
+ printk(" |");
+ dotest(rwlock_spinlock_ABBA, FAILURE, LOCKTYPE_RWLOCK);
+ printk(" |");
+ dotest(rwsem_mutex_ABBA, FAILURE, LOCKTYPE_RWSEM);
+ printk("\n");
+
+ print_testname("mixed read-spin-read-lock");
+ printk(" |");
+ dotest(rlock_spinlock_ABBA, SUCCESS, LOCKTYPE_RWLOCK);
+ printk(" |");
+ dotest(rsem_mutex_ABBA, FAILURE, LOCKTYPE_RWSEM);
+ printk("\n");
+
printk(" --------------------------------------------------------------------------\n");

/*


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/