locking/lockdep/selftests: Add mixed read-write ABBA tests
authorPeter Zijlstra <peterz@infradead.org>
Wed, 23 Aug 2017 11:13:11 +0000 (13:13 +0200)
committerIngo Molnar <mingo@kernel.org>
Fri, 25 Aug 2017 09:06:31 +0000 (11:06 +0200)
Currently lockdep has limited support for recursive readers, add a few
mixed read-write ABBA selftests to show the extend of these
limitations.

  [    0.000000] ----------------------------------------------------------------------------
  [    0.000000]                                  | spin |wlock |rlock |mutex | wsem | rsem |
  [    0.000000]   --------------------------------------------------------------------------

  [    0.000000]   mixed read-lock/lock-write ABBA:             |FAILED|             |  ok  |
  [    0.000000]    mixed read-lock/lock-read ABBA:             |  ok  |             |  ok  |
  [    0.000000]  mixed write-lock/lock-write ABBA:             |  ok  |             |  ok  |

This clearly illustrates the case where lockdep fails to find a
deadlock.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: boqun.feng@gmail.com
Cc: byungchul.park@lge.com
Cc: david@fromorbit.com
Cc: johannes@sipsolutions.net
Cc: oleg@redhat.com
Cc: tj@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
lib/locking-selftest.c

index 6f2b135dc5e81996dc2582f56d59b5d1769f5377..3c7151a6cd983c7edae9b48e3e951ba780299cb6 100644 (file)
@@ -362,6 +362,103 @@ static void rsem_AA3(void)
        RSL(X2); // this one should fail
 }
 
+/*
+ * read_lock(A)
+ * spin_lock(B)
+ *             spin_lock(B)
+ *             write_lock(A)
+ */
+static void rlock_ABBA1(void)
+{
+       RL(X1);
+       L(Y1);
+       U(Y1);
+       RU(X1);
+
+       L(Y1);
+       WL(X1);
+       WU(X1);
+       U(Y1); // should fail
+}
+
+static void rwsem_ABBA1(void)
+{
+       RSL(X1);
+       ML(Y1);
+       MU(Y1);
+       RSU(X1);
+
+       ML(Y1);
+       WSL(X1);
+       WSU(X1);
+       MU(Y1); // should fail
+}
+
+/*
+ * read_lock(A)
+ * spin_lock(B)
+ *             spin_lock(B)
+ *             read_lock(A)
+ */
+static void rlock_ABBA2(void)
+{
+       RL(X1);
+       L(Y1);
+       U(Y1);
+       RU(X1);
+
+       L(Y1);
+       RL(X1);
+       RU(X1);
+       U(Y1); // should NOT fail
+}
+
+static void rwsem_ABBA2(void)
+{
+       RSL(X1);
+       ML(Y1);
+       MU(Y1);
+       RSU(X1);
+
+       ML(Y1);
+       RSL(X1);
+       RSU(X1);
+       MU(Y1); // should fail
+}
+
+
+/*
+ * write_lock(A)
+ * spin_lock(B)
+ *             spin_lock(B)
+ *             write_lock(A)
+ */
+static void rlock_ABBA3(void)
+{
+       WL(X1);
+       L(Y1);
+       U(Y1);
+       WU(X1);
+
+       L(Y1);
+       WL(X1);
+       WU(X1);
+       U(Y1); // should fail
+}
+
+static void rwsem_ABBA3(void)
+{
+       WSL(X1);
+       ML(Y1);
+       MU(Y1);
+       WSU(X1);
+
+       ML(Y1);
+       WSL(X1);
+       WSU(X1);
+       MU(Y1); // should fail
+}
+
 /*
  * ABBA deadlock:
  */
@@ -1056,8 +1153,6 @@ static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask)
        if (debug_locks != expected) {
                unexpected_testcase_failures++;
                pr_cont("FAILED|");
-
-               dump_stack();
        } else {
                testcase_successes++;
                pr_cont("  ok  |");
@@ -1933,6 +2028,24 @@ void locking_selftest(void)
        dotest(rsem_AA3, FAILURE, LOCKTYPE_RWSEM);
        pr_cont("\n");
 
+       print_testname("mixed read-lock/lock-write ABBA");
+       pr_cont("             |");
+       dotest(rlock_ABBA1, FAILURE, LOCKTYPE_RWLOCK);
+       pr_cont("             |");
+       dotest(rwsem_ABBA1, FAILURE, LOCKTYPE_RWSEM);
+
+       print_testname("mixed read-lock/lock-read ABBA");
+       pr_cont("             |");
+       dotest(rlock_ABBA2, SUCCESS, LOCKTYPE_RWLOCK);
+       pr_cont("             |");
+       dotest(rwsem_ABBA2, FAILURE, LOCKTYPE_RWSEM);
+
+       print_testname("mixed write-lock/lock-write ABBA");
+       pr_cont("             |");
+       dotest(rlock_ABBA3, FAILURE, LOCKTYPE_RWLOCK);
+       pr_cont("             |");
+       dotest(rwsem_ABBA3, FAILURE, LOCKTYPE_RWSEM);
+
        printk("  --------------------------------------------------------------------------\n");
 
        /*