Although ww_mutexes degenerate into mutexes, it would be useful to
torture the deadlock handling between multiple ww_mutexes in addition to
torturing the regular mutexes.

Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk>
Cc: Peter Zijlstra <pet...@infradead.org>
Cc: Ingo Molnar <mi...@redhat.com>
Cc: Maarten Lankhorst <d...@mblankhorst.nl>
Cc: Nicolai Hähnle <nhaeh...@gmail.com>
---
 kernel/locking/locktorture.c                       | 73 ++++++++++++++++++++++
 .../selftests/rcutorture/configs/lock/CFLIST       |  1 +
 .../selftests/rcutorture/configs/lock/LOCK07       |  6 ++
 .../selftests/rcutorture/configs/lock/LOCK07.boot  |  1 +
 4 files changed, 81 insertions(+)
 create mode 100644 tools/testing/selftests/rcutorture/configs/lock/LOCK07
 create mode 100644 tools/testing/selftests/rcutorture/configs/lock/LOCK07.boot

diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c
index f8c5af52a131..9bffedd82884 100644
--- a/kernel/locking/locktorture.c
+++ b/kernel/locking/locktorture.c
@@ -372,6 +372,78 @@ static struct lock_torture_ops mutex_lock_ops = {
        .name           = "mutex_lock"
 };
 
+#include <linux/ww_mutex.h>
+static DEFINE_WW_CLASS(torture_ww_class);
+static DEFINE_WW_MUTEX(torture_ww_mutex_0, &torture_ww_class);
+static DEFINE_WW_MUTEX(torture_ww_mutex_1, &torture_ww_class);
+static DEFINE_WW_MUTEX(torture_ww_mutex_2, &torture_ww_class);
+
+static int torture_ww_mutex_lock(void)
+__acquires(torture_ww_mutex_0)
+__acquires(torture_ww_mutex_1)
+__acquires(torture_ww_mutex_2)
+{
+       LIST_HEAD(list);
+       struct reorder_lock {
+               struct list_head link;
+               struct ww_mutex *lock;
+       } locks[3], *ll, *ln;
+       struct ww_acquire_ctx ctx;
+
+       locks[0].lock = &torture_ww_mutex_0;
+       list_add(&locks[0].link, &list);
+
+       locks[1].lock = &torture_ww_mutex_1;
+       list_add(&locks[1].link, &list);
+
+       locks[2].lock = &torture_ww_mutex_2;
+       list_add(&locks[2].link, &list);
+
+       ww_acquire_init(&ctx, &torture_ww_class);
+
+       list_for_each_entry(ll, &list, link) {
+               int err;
+
+               err = ww_mutex_lock(ll->lock, &ctx);
+               if (!err)
+                       continue;
+
+               ln = ll;
+               list_for_each_entry_continue_reverse(ln, &list, link)
+                       ww_mutex_unlock(ln->lock);
+
+               if (err != -EDEADLK)
+                       return err;
+
+               ww_mutex_lock_slow(ll->lock, &ctx);
+               list_move(&ll->link, &list);
+       }
+
+       ww_acquire_fini(&ctx);
+       return 0;
+}
+
+static void torture_ww_mutex_unlock(void)
+__releases(torture_ww_mutex_0)
+__releases(torture_ww_mutex_1)
+__releases(torture_ww_mutex_2)
+{
+       ww_mutex_unlock(&torture_ww_mutex_0);
+       ww_mutex_unlock(&torture_ww_mutex_1);
+       ww_mutex_unlock(&torture_ww_mutex_2);
+}
+
+static struct lock_torture_ops ww_mutex_lock_ops = {
+       .writelock      = torture_ww_mutex_lock,
+       .write_delay    = torture_mutex_delay,
+       .task_boost     = torture_boost_dummy,
+       .writeunlock    = torture_ww_mutex_unlock,
+       .readlock       = NULL,
+       .read_delay     = NULL,
+       .readunlock     = NULL,
+       .name           = "ww_mutex_lock"
+};
+
 #ifdef CONFIG_RT_MUTEXES
 static DEFINE_RT_MUTEX(torture_rtmutex);
 
@@ -793,6 +865,7 @@ static int __init lock_torture_init(void)
                &spin_lock_ops, &spin_lock_irq_ops,
                &rw_lock_ops, &rw_lock_irq_ops,
                &mutex_lock_ops,
+               &ww_mutex_lock_ops,
 #ifdef CONFIG_RT_MUTEXES
                &rtmutex_lock_ops,
 #endif
diff --git a/tools/testing/selftests/rcutorture/configs/lock/CFLIST 
b/tools/testing/selftests/rcutorture/configs/lock/CFLIST
index b9611c523723..41bae5824339 100644
--- a/tools/testing/selftests/rcutorture/configs/lock/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/lock/CFLIST
@@ -4,3 +4,4 @@ LOCK03
 LOCK04
 LOCK05
 LOCK06
+LOCK07
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK07 
b/tools/testing/selftests/rcutorture/configs/lock/LOCK07
new file mode 100644
index 000000000000..1d1da1477fc3
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK07
@@ -0,0 +1,6 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK07.boot 
b/tools/testing/selftests/rcutorture/configs/lock/LOCK07.boot
new file mode 100644
index 000000000000..97dadd1a9e45
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK07.boot
@@ -0,0 +1 @@
+locktorture.torture_type=ww_mutex_lock
-- 
2.10.2

Reply via email to