1d6cd1e9bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f2a5fec1SChris Wilson /*
3f2a5fec1SChris Wilson * Module-based API test facility for ww_mutexes
4f2a5fec1SChris Wilson */
5f2a5fec1SChris Wilson
6f2a5fec1SChris Wilson #include <linux/kernel.h>
7f2a5fec1SChris Wilson
8f2a5fec1SChris Wilson #include <linux/completion.h>
92a0c1128SChris Wilson #include <linux/delay.h>
10f2a5fec1SChris Wilson #include <linux/kthread.h>
11f2a5fec1SChris Wilson #include <linux/module.h>
124812c54dSJohn Stultz #include <linux/prandom.h>
13d1b42b80SChris Wilson #include <linux/slab.h>
14f2a5fec1SChris Wilson #include <linux/ww_mutex.h>
15f2a5fec1SChris Wilson
1608295b3bSThomas Hellstrom static DEFINE_WD_CLASS(ww_class);
17d1b42b80SChris Wilson struct workqueue_struct *wq;
18f2a5fec1SChris Wilson
1912235da8SMaarten Lankhorst #ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
2012235da8SMaarten Lankhorst #define ww_acquire_init_noinject(a, b) do { \
2112235da8SMaarten Lankhorst ww_acquire_init((a), (b)); \
2212235da8SMaarten Lankhorst (a)->deadlock_inject_countdown = ~0U; \
2312235da8SMaarten Lankhorst } while (0)
2412235da8SMaarten Lankhorst #else
2512235da8SMaarten Lankhorst #define ww_acquire_init_noinject(a, b) ww_acquire_init((a), (b))
2612235da8SMaarten Lankhorst #endif
2712235da8SMaarten Lankhorst
28f2a5fec1SChris Wilson struct test_mutex {
29f2a5fec1SChris Wilson struct work_struct work;
30f2a5fec1SChris Wilson struct ww_mutex mutex;
31f2a5fec1SChris Wilson struct completion ready, go, done;
32f2a5fec1SChris Wilson unsigned int flags;
33f2a5fec1SChris Wilson };
34f2a5fec1SChris Wilson
35f2a5fec1SChris Wilson #define TEST_MTX_SPIN BIT(0)
36f2a5fec1SChris Wilson #define TEST_MTX_TRY BIT(1)
37f2a5fec1SChris Wilson #define TEST_MTX_CTX BIT(2)
38f2a5fec1SChris Wilson #define __TEST_MTX_LAST BIT(3)
39f2a5fec1SChris Wilson
test_mutex_work(struct work_struct * work)40f2a5fec1SChris Wilson static void test_mutex_work(struct work_struct *work)
41f2a5fec1SChris Wilson {
42f2a5fec1SChris Wilson struct test_mutex *mtx = container_of(work, typeof(*mtx), work);
43f2a5fec1SChris Wilson
44f2a5fec1SChris Wilson complete(&mtx->ready);
45f2a5fec1SChris Wilson wait_for_completion(&mtx->go);
46f2a5fec1SChris Wilson
47f2a5fec1SChris Wilson if (mtx->flags & TEST_MTX_TRY) {
4812235da8SMaarten Lankhorst while (!ww_mutex_trylock(&mtx->mutex, NULL))
492b232e0cSChris Wilson cond_resched();
50f2a5fec1SChris Wilson } else {
51f2a5fec1SChris Wilson ww_mutex_lock(&mtx->mutex, NULL);
52f2a5fec1SChris Wilson }
53f2a5fec1SChris Wilson complete(&mtx->done);
54f2a5fec1SChris Wilson ww_mutex_unlock(&mtx->mutex);
55f2a5fec1SChris Wilson }
56f2a5fec1SChris Wilson
__test_mutex(unsigned int flags)57f2a5fec1SChris Wilson static int __test_mutex(unsigned int flags)
58f2a5fec1SChris Wilson {
59f2a5fec1SChris Wilson #define TIMEOUT (HZ / 16)
60f2a5fec1SChris Wilson struct test_mutex mtx;
61f2a5fec1SChris Wilson struct ww_acquire_ctx ctx;
62f2a5fec1SChris Wilson int ret;
63f2a5fec1SChris Wilson
64f2a5fec1SChris Wilson ww_mutex_init(&mtx.mutex, &ww_class);
65823a5662SThomas Hellström if (flags & TEST_MTX_CTX)
66f2a5fec1SChris Wilson ww_acquire_init(&ctx, &ww_class);
67f2a5fec1SChris Wilson
68f2a5fec1SChris Wilson INIT_WORK_ONSTACK(&mtx.work, test_mutex_work);
69f2a5fec1SChris Wilson init_completion(&mtx.ready);
70f2a5fec1SChris Wilson init_completion(&mtx.go);
71f2a5fec1SChris Wilson init_completion(&mtx.done);
72f2a5fec1SChris Wilson mtx.flags = flags;
73f2a5fec1SChris Wilson
74f2a5fec1SChris Wilson schedule_work(&mtx.work);
75f2a5fec1SChris Wilson
76f2a5fec1SChris Wilson wait_for_completion(&mtx.ready);
77f2a5fec1SChris Wilson ww_mutex_lock(&mtx.mutex, (flags & TEST_MTX_CTX) ? &ctx : NULL);
78f2a5fec1SChris Wilson complete(&mtx.go);
79f2a5fec1SChris Wilson if (flags & TEST_MTX_SPIN) {
80f2a5fec1SChris Wilson unsigned long timeout = jiffies + TIMEOUT;
81f2a5fec1SChris Wilson
82f2a5fec1SChris Wilson ret = 0;
83f2a5fec1SChris Wilson do {
84f2a5fec1SChris Wilson if (completion_done(&mtx.done)) {
85f2a5fec1SChris Wilson ret = -EINVAL;
86f2a5fec1SChris Wilson break;
87f2a5fec1SChris Wilson }
882b232e0cSChris Wilson cond_resched();
89f2a5fec1SChris Wilson } while (time_before(jiffies, timeout));
90f2a5fec1SChris Wilson } else {
91f2a5fec1SChris Wilson ret = wait_for_completion_timeout(&mtx.done, TIMEOUT);
92f2a5fec1SChris Wilson }
93f2a5fec1SChris Wilson ww_mutex_unlock(&mtx.mutex);
94823a5662SThomas Hellström if (flags & TEST_MTX_CTX)
95f2a5fec1SChris Wilson ww_acquire_fini(&ctx);
96f2a5fec1SChris Wilson
97f2a5fec1SChris Wilson if (ret) {
98f2a5fec1SChris Wilson pr_err("%s(flags=%x): mutual exclusion failure\n",
99f2a5fec1SChris Wilson __func__, flags);
100f2a5fec1SChris Wilson ret = -EINVAL;
101f2a5fec1SChris Wilson }
102f2a5fec1SChris Wilson
103f2a5fec1SChris Wilson flush_work(&mtx.work);
104f2a5fec1SChris Wilson destroy_work_on_stack(&mtx.work);
105f2a5fec1SChris Wilson return ret;
106f2a5fec1SChris Wilson #undef TIMEOUT
107f2a5fec1SChris Wilson }
108f2a5fec1SChris Wilson
test_mutex(void)109f2a5fec1SChris Wilson static int test_mutex(void)
110f2a5fec1SChris Wilson {
111f2a5fec1SChris Wilson int ret;
112f2a5fec1SChris Wilson int i;
113f2a5fec1SChris Wilson
114f2a5fec1SChris Wilson for (i = 0; i < __TEST_MTX_LAST; i++) {
115f2a5fec1SChris Wilson ret = __test_mutex(i);
116f2a5fec1SChris Wilson if (ret)
117f2a5fec1SChris Wilson return ret;
118f2a5fec1SChris Wilson }
119f2a5fec1SChris Wilson
120f2a5fec1SChris Wilson return 0;
121f2a5fec1SChris Wilson }
122f2a5fec1SChris Wilson
test_aa(bool trylock)12312235da8SMaarten Lankhorst static int test_aa(bool trylock)
124c22fb380SChris Wilson {
125c22fb380SChris Wilson struct ww_mutex mutex;
126c22fb380SChris Wilson struct ww_acquire_ctx ctx;
127c22fb380SChris Wilson int ret;
12812235da8SMaarten Lankhorst const char *from = trylock ? "trylock" : "lock";
129c22fb380SChris Wilson
130c22fb380SChris Wilson ww_mutex_init(&mutex, &ww_class);
131c22fb380SChris Wilson ww_acquire_init(&ctx, &ww_class);
132c22fb380SChris Wilson
13312235da8SMaarten Lankhorst if (!trylock) {
13412235da8SMaarten Lankhorst ret = ww_mutex_lock(&mutex, &ctx);
13512235da8SMaarten Lankhorst if (ret) {
13612235da8SMaarten Lankhorst pr_err("%s: initial lock failed!\n", __func__);
13712235da8SMaarten Lankhorst goto out;
13812235da8SMaarten Lankhorst }
13912235da8SMaarten Lankhorst } else {
1401415b49bSNathan Chancellor ret = !ww_mutex_trylock(&mutex, &ctx);
1411415b49bSNathan Chancellor if (ret) {
14212235da8SMaarten Lankhorst pr_err("%s: initial trylock failed!\n", __func__);
14312235da8SMaarten Lankhorst goto out;
14412235da8SMaarten Lankhorst }
14512235da8SMaarten Lankhorst }
146c22fb380SChris Wilson
14712235da8SMaarten Lankhorst if (ww_mutex_trylock(&mutex, NULL)) {
14812235da8SMaarten Lankhorst pr_err("%s: trylocked itself without context from %s!\n", __func__, from);
14912235da8SMaarten Lankhorst ww_mutex_unlock(&mutex);
15012235da8SMaarten Lankhorst ret = -EINVAL;
15112235da8SMaarten Lankhorst goto out;
15212235da8SMaarten Lankhorst }
15312235da8SMaarten Lankhorst
15412235da8SMaarten Lankhorst if (ww_mutex_trylock(&mutex, &ctx)) {
15512235da8SMaarten Lankhorst pr_err("%s: trylocked itself with context from %s!\n", __func__, from);
156c22fb380SChris Wilson ww_mutex_unlock(&mutex);
157c22fb380SChris Wilson ret = -EINVAL;
158c22fb380SChris Wilson goto out;
159c22fb380SChris Wilson }
160c22fb380SChris Wilson
161c22fb380SChris Wilson ret = ww_mutex_lock(&mutex, &ctx);
162c22fb380SChris Wilson if (ret != -EALREADY) {
16312235da8SMaarten Lankhorst pr_err("%s: missed deadlock for recursing, ret=%d from %s\n",
16412235da8SMaarten Lankhorst __func__, ret, from);
165c22fb380SChris Wilson if (!ret)
166c22fb380SChris Wilson ww_mutex_unlock(&mutex);
167c22fb380SChris Wilson ret = -EINVAL;
168c22fb380SChris Wilson goto out;
169c22fb380SChris Wilson }
170c22fb380SChris Wilson
17112235da8SMaarten Lankhorst ww_mutex_unlock(&mutex);
172c22fb380SChris Wilson ret = 0;
173c22fb380SChris Wilson out:
174c22fb380SChris Wilson ww_acquire_fini(&ctx);
175c22fb380SChris Wilson return ret;
176c22fb380SChris Wilson }
177c22fb380SChris Wilson
17870207686SChris Wilson struct test_abba {
17970207686SChris Wilson struct work_struct work;
18070207686SChris Wilson struct ww_mutex a_mutex;
18170207686SChris Wilson struct ww_mutex b_mutex;
18270207686SChris Wilson struct completion a_ready;
18370207686SChris Wilson struct completion b_ready;
18412235da8SMaarten Lankhorst bool resolve, trylock;
18570207686SChris Wilson int result;
18670207686SChris Wilson };
18770207686SChris Wilson
test_abba_work(struct work_struct * work)18870207686SChris Wilson static void test_abba_work(struct work_struct *work)
18970207686SChris Wilson {
19070207686SChris Wilson struct test_abba *abba = container_of(work, typeof(*abba), work);
19170207686SChris Wilson struct ww_acquire_ctx ctx;
19270207686SChris Wilson int err;
19370207686SChris Wilson
19412235da8SMaarten Lankhorst ww_acquire_init_noinject(&ctx, &ww_class);
19512235da8SMaarten Lankhorst if (!abba->trylock)
19670207686SChris Wilson ww_mutex_lock(&abba->b_mutex, &ctx);
19712235da8SMaarten Lankhorst else
19812235da8SMaarten Lankhorst WARN_ON(!ww_mutex_trylock(&abba->b_mutex, &ctx));
19912235da8SMaarten Lankhorst
20012235da8SMaarten Lankhorst WARN_ON(READ_ONCE(abba->b_mutex.ctx) != &ctx);
20170207686SChris Wilson
20270207686SChris Wilson complete(&abba->b_ready);
20370207686SChris Wilson wait_for_completion(&abba->a_ready);
20470207686SChris Wilson
20570207686SChris Wilson err = ww_mutex_lock(&abba->a_mutex, &ctx);
20670207686SChris Wilson if (abba->resolve && err == -EDEADLK) {
20770207686SChris Wilson ww_mutex_unlock(&abba->b_mutex);
20870207686SChris Wilson ww_mutex_lock_slow(&abba->a_mutex, &ctx);
20970207686SChris Wilson err = ww_mutex_lock(&abba->b_mutex, &ctx);
21070207686SChris Wilson }
21170207686SChris Wilson
21270207686SChris Wilson if (!err)
21370207686SChris Wilson ww_mutex_unlock(&abba->a_mutex);
21470207686SChris Wilson ww_mutex_unlock(&abba->b_mutex);
21570207686SChris Wilson ww_acquire_fini(&ctx);
21670207686SChris Wilson
21770207686SChris Wilson abba->result = err;
21870207686SChris Wilson }
21970207686SChris Wilson
test_abba(bool trylock,bool resolve)22012235da8SMaarten Lankhorst static int test_abba(bool trylock, bool resolve)
22170207686SChris Wilson {
22270207686SChris Wilson struct test_abba abba;
22370207686SChris Wilson struct ww_acquire_ctx ctx;
22470207686SChris Wilson int err, ret;
22570207686SChris Wilson
22670207686SChris Wilson ww_mutex_init(&abba.a_mutex, &ww_class);
22770207686SChris Wilson ww_mutex_init(&abba.b_mutex, &ww_class);
22870207686SChris Wilson INIT_WORK_ONSTACK(&abba.work, test_abba_work);
22970207686SChris Wilson init_completion(&abba.a_ready);
23070207686SChris Wilson init_completion(&abba.b_ready);
23112235da8SMaarten Lankhorst abba.trylock = trylock;
23270207686SChris Wilson abba.resolve = resolve;
23370207686SChris Wilson
23470207686SChris Wilson schedule_work(&abba.work);
23570207686SChris Wilson
23612235da8SMaarten Lankhorst ww_acquire_init_noinject(&ctx, &ww_class);
23712235da8SMaarten Lankhorst if (!trylock)
23870207686SChris Wilson ww_mutex_lock(&abba.a_mutex, &ctx);
23912235da8SMaarten Lankhorst else
24012235da8SMaarten Lankhorst WARN_ON(!ww_mutex_trylock(&abba.a_mutex, &ctx));
24112235da8SMaarten Lankhorst
24212235da8SMaarten Lankhorst WARN_ON(READ_ONCE(abba.a_mutex.ctx) != &ctx);
24370207686SChris Wilson
24470207686SChris Wilson complete(&abba.a_ready);
24570207686SChris Wilson wait_for_completion(&abba.b_ready);
24670207686SChris Wilson
24770207686SChris Wilson err = ww_mutex_lock(&abba.b_mutex, &ctx);
24870207686SChris Wilson if (resolve && err == -EDEADLK) {
24970207686SChris Wilson ww_mutex_unlock(&abba.a_mutex);
25070207686SChris Wilson ww_mutex_lock_slow(&abba.b_mutex, &ctx);
25170207686SChris Wilson err = ww_mutex_lock(&abba.a_mutex, &ctx);
25270207686SChris Wilson }
25370207686SChris Wilson
25470207686SChris Wilson if (!err)
25570207686SChris Wilson ww_mutex_unlock(&abba.b_mutex);
25670207686SChris Wilson ww_mutex_unlock(&abba.a_mutex);
25770207686SChris Wilson ww_acquire_fini(&ctx);
25870207686SChris Wilson
25970207686SChris Wilson flush_work(&abba.work);
26070207686SChris Wilson destroy_work_on_stack(&abba.work);
26170207686SChris Wilson
26270207686SChris Wilson ret = 0;
26370207686SChris Wilson if (resolve) {
26470207686SChris Wilson if (err || abba.result) {
26570207686SChris Wilson pr_err("%s: failed to resolve ABBA deadlock, A err=%d, B err=%d\n",
26670207686SChris Wilson __func__, err, abba.result);
26770207686SChris Wilson ret = -EINVAL;
26870207686SChris Wilson }
26970207686SChris Wilson } else {
27070207686SChris Wilson if (err != -EDEADLK && abba.result != -EDEADLK) {
27170207686SChris Wilson pr_err("%s: missed ABBA deadlock, A err=%d, B err=%d\n",
27270207686SChris Wilson __func__, err, abba.result);
27370207686SChris Wilson ret = -EINVAL;
27470207686SChris Wilson }
27570207686SChris Wilson }
27670207686SChris Wilson return ret;
27770207686SChris Wilson }
27870207686SChris Wilson
279d1b42b80SChris Wilson struct test_cycle {
280d1b42b80SChris Wilson struct work_struct work;
281d1b42b80SChris Wilson struct ww_mutex a_mutex;
282d1b42b80SChris Wilson struct ww_mutex *b_mutex;
283d1b42b80SChris Wilson struct completion *a_signal;
284d1b42b80SChris Wilson struct completion b_signal;
285d1b42b80SChris Wilson int result;
286d1b42b80SChris Wilson };
287d1b42b80SChris Wilson
test_cycle_work(struct work_struct * work)288d1b42b80SChris Wilson static void test_cycle_work(struct work_struct *work)
289d1b42b80SChris Wilson {
290d1b42b80SChris Wilson struct test_cycle *cycle = container_of(work, typeof(*cycle), work);
291d1b42b80SChris Wilson struct ww_acquire_ctx ctx;
292e4a02ed2SGuenter Roeck int err, erra = 0;
293d1b42b80SChris Wilson
29412235da8SMaarten Lankhorst ww_acquire_init_noinject(&ctx, &ww_class);
295d1b42b80SChris Wilson ww_mutex_lock(&cycle->a_mutex, &ctx);
296d1b42b80SChris Wilson
297d1b42b80SChris Wilson complete(cycle->a_signal);
298d1b42b80SChris Wilson wait_for_completion(&cycle->b_signal);
299d1b42b80SChris Wilson
300d1b42b80SChris Wilson err = ww_mutex_lock(cycle->b_mutex, &ctx);
301d1b42b80SChris Wilson if (err == -EDEADLK) {
302e4a02ed2SGuenter Roeck err = 0;
303d1b42b80SChris Wilson ww_mutex_unlock(&cycle->a_mutex);
304d1b42b80SChris Wilson ww_mutex_lock_slow(cycle->b_mutex, &ctx);
305e4a02ed2SGuenter Roeck erra = ww_mutex_lock(&cycle->a_mutex, &ctx);
306d1b42b80SChris Wilson }
307d1b42b80SChris Wilson
308d1b42b80SChris Wilson if (!err)
309d1b42b80SChris Wilson ww_mutex_unlock(cycle->b_mutex);
310e4a02ed2SGuenter Roeck if (!erra)
311d1b42b80SChris Wilson ww_mutex_unlock(&cycle->a_mutex);
312d1b42b80SChris Wilson ww_acquire_fini(&ctx);
313d1b42b80SChris Wilson
314e4a02ed2SGuenter Roeck cycle->result = err ?: erra;
315d1b42b80SChris Wilson }
316d1b42b80SChris Wilson
__test_cycle(unsigned int nthreads)317d1b42b80SChris Wilson static int __test_cycle(unsigned int nthreads)
318d1b42b80SChris Wilson {
319d1b42b80SChris Wilson struct test_cycle *cycles;
320d1b42b80SChris Wilson unsigned int n, last = nthreads - 1;
321d1b42b80SChris Wilson int ret;
322d1b42b80SChris Wilson
323d1b42b80SChris Wilson cycles = kmalloc_array(nthreads, sizeof(*cycles), GFP_KERNEL);
324d1b42b80SChris Wilson if (!cycles)
325d1b42b80SChris Wilson return -ENOMEM;
326d1b42b80SChris Wilson
327d1b42b80SChris Wilson for (n = 0; n < nthreads; n++) {
328d1b42b80SChris Wilson struct test_cycle *cycle = &cycles[n];
329d1b42b80SChris Wilson
330d1b42b80SChris Wilson ww_mutex_init(&cycle->a_mutex, &ww_class);
331d1b42b80SChris Wilson if (n == last)
332d1b42b80SChris Wilson cycle->b_mutex = &cycles[0].a_mutex;
333d1b42b80SChris Wilson else
334d1b42b80SChris Wilson cycle->b_mutex = &cycles[n + 1].a_mutex;
335d1b42b80SChris Wilson
336d1b42b80SChris Wilson if (n == 0)
337d1b42b80SChris Wilson cycle->a_signal = &cycles[last].b_signal;
338d1b42b80SChris Wilson else
339d1b42b80SChris Wilson cycle->a_signal = &cycles[n - 1].b_signal;
340d1b42b80SChris Wilson init_completion(&cycle->b_signal);
341d1b42b80SChris Wilson
342d1b42b80SChris Wilson INIT_WORK(&cycle->work, test_cycle_work);
343d1b42b80SChris Wilson cycle->result = 0;
344d1b42b80SChris Wilson }
345d1b42b80SChris Wilson
346d1b42b80SChris Wilson for (n = 0; n < nthreads; n++)
347d1b42b80SChris Wilson queue_work(wq, &cycles[n].work);
348d1b42b80SChris Wilson
349d1b42b80SChris Wilson flush_workqueue(wq);
350d1b42b80SChris Wilson
351d1b42b80SChris Wilson ret = 0;
352d1b42b80SChris Wilson for (n = 0; n < nthreads; n++) {
353d1b42b80SChris Wilson struct test_cycle *cycle = &cycles[n];
354d1b42b80SChris Wilson
355d1b42b80SChris Wilson if (!cycle->result)
356d1b42b80SChris Wilson continue;
357d1b42b80SChris Wilson
3580b405c65SColin Ian King pr_err("cyclic deadlock not resolved, ret[%d/%d] = %d\n",
359d1b42b80SChris Wilson n, nthreads, cycle->result);
360d1b42b80SChris Wilson ret = -EINVAL;
361d1b42b80SChris Wilson break;
362d1b42b80SChris Wilson }
363d1b42b80SChris Wilson
364d1b42b80SChris Wilson for (n = 0; n < nthreads; n++)
365d1b42b80SChris Wilson ww_mutex_destroy(&cycles[n].a_mutex);
366d1b42b80SChris Wilson kfree(cycles);
367d1b42b80SChris Wilson return ret;
368d1b42b80SChris Wilson }
369d1b42b80SChris Wilson
test_cycle(unsigned int ncpus)370d1b42b80SChris Wilson static int test_cycle(unsigned int ncpus)
371d1b42b80SChris Wilson {
372d1b42b80SChris Wilson unsigned int n;
373d1b42b80SChris Wilson int ret;
374d1b42b80SChris Wilson
375d1b42b80SChris Wilson for (n = 2; n <= ncpus + 1; n++) {
376d1b42b80SChris Wilson ret = __test_cycle(n);
377d1b42b80SChris Wilson if (ret)
378d1b42b80SChris Wilson return ret;
379d1b42b80SChris Wilson }
380d1b42b80SChris Wilson
381d1b42b80SChris Wilson return 0;
382d1b42b80SChris Wilson }
383d1b42b80SChris Wilson
3842a0c1128SChris Wilson struct stress {
3852a0c1128SChris Wilson struct work_struct work;
3862a0c1128SChris Wilson struct ww_mutex *locks;
38757dd924eSChris Wilson unsigned long timeout;
3882a0c1128SChris Wilson int nlocks;
3892a0c1128SChris Wilson };
3902a0c1128SChris Wilson
3914812c54dSJohn Stultz struct rnd_state rng;
3924812c54dSJohn Stultz DEFINE_SPINLOCK(rng_lock);
3934812c54dSJohn Stultz
prandom_u32_below(u32 ceil)3944812c54dSJohn Stultz static inline u32 prandom_u32_below(u32 ceil)
3954812c54dSJohn Stultz {
3964812c54dSJohn Stultz u32 ret;
3974812c54dSJohn Stultz
3984812c54dSJohn Stultz spin_lock(&rng_lock);
3994812c54dSJohn Stultz ret = prandom_u32_state(&rng) % ceil;
4004812c54dSJohn Stultz spin_unlock(&rng_lock);
4014812c54dSJohn Stultz return ret;
4024812c54dSJohn Stultz }
4034812c54dSJohn Stultz
get_random_order(int count)4042a0c1128SChris Wilson static int *get_random_order(int count)
4052a0c1128SChris Wilson {
4062a0c1128SChris Wilson int *order;
407*0d3547dfSThorsten Blum int n, r;
4082a0c1128SChris Wilson
4090ee931c4SMichal Hocko order = kmalloc_array(count, sizeof(*order), GFP_KERNEL);
4102a0c1128SChris Wilson if (!order)
4112a0c1128SChris Wilson return order;
4122a0c1128SChris Wilson
4132a0c1128SChris Wilson for (n = 0; n < count; n++)
4142a0c1128SChris Wilson order[n] = n;
4152a0c1128SChris Wilson
4162a0c1128SChris Wilson for (n = count - 1; n > 1; n--) {
4174812c54dSJohn Stultz r = prandom_u32_below(n + 1);
418*0d3547dfSThorsten Blum if (r != n)
419*0d3547dfSThorsten Blum swap(order[n], order[r]);
4202a0c1128SChris Wilson }
4212a0c1128SChris Wilson
4222a0c1128SChris Wilson return order;
4232a0c1128SChris Wilson }
4242a0c1128SChris Wilson
dummy_load(struct stress * stress)4252a0c1128SChris Wilson static void dummy_load(struct stress *stress)
4262a0c1128SChris Wilson {
4272a0c1128SChris Wilson usleep_range(1000, 2000);
4282a0c1128SChris Wilson }
4292a0c1128SChris Wilson
stress_inorder_work(struct work_struct * work)4302a0c1128SChris Wilson static void stress_inorder_work(struct work_struct *work)
4312a0c1128SChris Wilson {
4322a0c1128SChris Wilson struct stress *stress = container_of(work, typeof(*stress), work);
4332a0c1128SChris Wilson const int nlocks = stress->nlocks;
4342a0c1128SChris Wilson struct ww_mutex *locks = stress->locks;
4352a0c1128SChris Wilson struct ww_acquire_ctx ctx;
4362a0c1128SChris Wilson int *order;
4372a0c1128SChris Wilson
4382a0c1128SChris Wilson order = get_random_order(nlocks);
4392a0c1128SChris Wilson if (!order)
4402a0c1128SChris Wilson return;
4412a0c1128SChris Wilson
4422a0c1128SChris Wilson do {
4432a0c1128SChris Wilson int contended = -1;
4442a0c1128SChris Wilson int n, err;
4452a0c1128SChris Wilson
446bf7b3ac2SPeter Zijlstra ww_acquire_init(&ctx, &ww_class);
4472a0c1128SChris Wilson retry:
4482a0c1128SChris Wilson err = 0;
4492a0c1128SChris Wilson for (n = 0; n < nlocks; n++) {
4502a0c1128SChris Wilson if (n == contended)
4512a0c1128SChris Wilson continue;
4522a0c1128SChris Wilson
4532a0c1128SChris Wilson err = ww_mutex_lock(&locks[order[n]], &ctx);
4542a0c1128SChris Wilson if (err < 0)
4552a0c1128SChris Wilson break;
4562a0c1128SChris Wilson }
4572a0c1128SChris Wilson if (!err)
4582a0c1128SChris Wilson dummy_load(stress);
4592a0c1128SChris Wilson
4602a0c1128SChris Wilson if (contended > n)
4612a0c1128SChris Wilson ww_mutex_unlock(&locks[order[contended]]);
4622a0c1128SChris Wilson contended = n;
4632a0c1128SChris Wilson while (n--)
4642a0c1128SChris Wilson ww_mutex_unlock(&locks[order[n]]);
4652a0c1128SChris Wilson
4662a0c1128SChris Wilson if (err == -EDEADLK) {
467cfa92b6dSJohn Stultz if (!time_after(jiffies, stress->timeout)) {
4682a0c1128SChris Wilson ww_mutex_lock_slow(&locks[order[contended]], &ctx);
4692a0c1128SChris Wilson goto retry;
4702a0c1128SChris Wilson }
471cfa92b6dSJohn Stultz }
4722a0c1128SChris Wilson
473cfa92b6dSJohn Stultz ww_acquire_fini(&ctx);
4742a0c1128SChris Wilson if (err) {
4752a0c1128SChris Wilson pr_err_once("stress (%s) failed with %d\n",
4762a0c1128SChris Wilson __func__, err);
4772a0c1128SChris Wilson break;
4782a0c1128SChris Wilson }
47957dd924eSChris Wilson } while (!time_after(jiffies, stress->timeout));
4802a0c1128SChris Wilson
4812a0c1128SChris Wilson kfree(order);
4822a0c1128SChris Wilson }
4832a0c1128SChris Wilson
4842a0c1128SChris Wilson struct reorder_lock {
4852a0c1128SChris Wilson struct list_head link;
4862a0c1128SChris Wilson struct ww_mutex *lock;
4872a0c1128SChris Wilson };
4882a0c1128SChris Wilson
stress_reorder_work(struct work_struct * work)4892a0c1128SChris Wilson static void stress_reorder_work(struct work_struct *work)
4902a0c1128SChris Wilson {
4912a0c1128SChris Wilson struct stress *stress = container_of(work, typeof(*stress), work);
4922a0c1128SChris Wilson LIST_HEAD(locks);
4932a0c1128SChris Wilson struct ww_acquire_ctx ctx;
4942a0c1128SChris Wilson struct reorder_lock *ll, *ln;
4952a0c1128SChris Wilson int *order;
4962a0c1128SChris Wilson int n, err;
4972a0c1128SChris Wilson
4982a0c1128SChris Wilson order = get_random_order(stress->nlocks);
4992a0c1128SChris Wilson if (!order)
5002a0c1128SChris Wilson return;
5012a0c1128SChris Wilson
5022a0c1128SChris Wilson for (n = 0; n < stress->nlocks; n++) {
5032a0c1128SChris Wilson ll = kmalloc(sizeof(*ll), GFP_KERNEL);
5042a0c1128SChris Wilson if (!ll)
5052a0c1128SChris Wilson goto out;
5062a0c1128SChris Wilson
5072a0c1128SChris Wilson ll->lock = &stress->locks[order[n]];
5082a0c1128SChris Wilson list_add(&ll->link, &locks);
5092a0c1128SChris Wilson }
5102a0c1128SChris Wilson kfree(order);
5112a0c1128SChris Wilson order = NULL;
5122a0c1128SChris Wilson
513bf7b3ac2SPeter Zijlstra do {
5142a0c1128SChris Wilson ww_acquire_init(&ctx, &ww_class);
5152a0c1128SChris Wilson
5162a0c1128SChris Wilson list_for_each_entry(ll, &locks, link) {
5172a0c1128SChris Wilson err = ww_mutex_lock(ll->lock, &ctx);
5182a0c1128SChris Wilson if (!err)
5192a0c1128SChris Wilson continue;
5202a0c1128SChris Wilson
5212a0c1128SChris Wilson ln = ll;
5222a0c1128SChris Wilson list_for_each_entry_continue_reverse(ln, &locks, link)
5232a0c1128SChris Wilson ww_mutex_unlock(ln->lock);
5242a0c1128SChris Wilson
5252a0c1128SChris Wilson if (err != -EDEADLK) {
5262a0c1128SChris Wilson pr_err_once("stress (%s) failed with %d\n",
5272a0c1128SChris Wilson __func__, err);
5282a0c1128SChris Wilson break;
5292a0c1128SChris Wilson }
5302a0c1128SChris Wilson
5312a0c1128SChris Wilson ww_mutex_lock_slow(ll->lock, &ctx);
5322a0c1128SChris Wilson list_move(&ll->link, &locks); /* restarts iteration */
5332a0c1128SChris Wilson }
5342a0c1128SChris Wilson
5352a0c1128SChris Wilson dummy_load(stress);
5362a0c1128SChris Wilson list_for_each_entry(ll, &locks, link)
5372a0c1128SChris Wilson ww_mutex_unlock(ll->lock);
5382a0c1128SChris Wilson
5392a0c1128SChris Wilson ww_acquire_fini(&ctx);
54057dd924eSChris Wilson } while (!time_after(jiffies, stress->timeout));
5412a0c1128SChris Wilson
5422a0c1128SChris Wilson out:
5432a0c1128SChris Wilson list_for_each_entry_safe(ll, ln, &locks, link)
5442a0c1128SChris Wilson kfree(ll);
5452a0c1128SChris Wilson kfree(order);
5462a0c1128SChris Wilson }
5472a0c1128SChris Wilson
stress_one_work(struct work_struct * work)5482a0c1128SChris Wilson static void stress_one_work(struct work_struct *work)
5492a0c1128SChris Wilson {
5502a0c1128SChris Wilson struct stress *stress = container_of(work, typeof(*stress), work);
5512a0c1128SChris Wilson const int nlocks = stress->nlocks;
5528032bf12SJason A. Donenfeld struct ww_mutex *lock = stress->locks + get_random_u32_below(nlocks);
5532a0c1128SChris Wilson int err;
5542a0c1128SChris Wilson
5552a0c1128SChris Wilson do {
5562a0c1128SChris Wilson err = ww_mutex_lock(lock, NULL);
5572a0c1128SChris Wilson if (!err) {
5582a0c1128SChris Wilson dummy_load(stress);
5592a0c1128SChris Wilson ww_mutex_unlock(lock);
5602a0c1128SChris Wilson } else {
5612a0c1128SChris Wilson pr_err_once("stress (%s) failed with %d\n",
5622a0c1128SChris Wilson __func__, err);
5632a0c1128SChris Wilson break;
5642a0c1128SChris Wilson }
56557dd924eSChris Wilson } while (!time_after(jiffies, stress->timeout));
5662a0c1128SChris Wilson }
5672a0c1128SChris Wilson
5682a0c1128SChris Wilson #define STRESS_INORDER BIT(0)
5692a0c1128SChris Wilson #define STRESS_REORDER BIT(1)
5702a0c1128SChris Wilson #define STRESS_ONE BIT(2)
5712a0c1128SChris Wilson #define STRESS_ALL (STRESS_INORDER | STRESS_REORDER | STRESS_ONE)
5722a0c1128SChris Wilson
stress(int nlocks,int nthreads,unsigned int flags)57357dd924eSChris Wilson static int stress(int nlocks, int nthreads, unsigned int flags)
5742a0c1128SChris Wilson {
5752a0c1128SChris Wilson struct ww_mutex *locks;
576bccdd808SJohn Stultz struct stress *stress_array;
577bccdd808SJohn Stultz int n, count;
5782a0c1128SChris Wilson
5792a0c1128SChris Wilson locks = kmalloc_array(nlocks, sizeof(*locks), GFP_KERNEL);
5802a0c1128SChris Wilson if (!locks)
5812a0c1128SChris Wilson return -ENOMEM;
5822a0c1128SChris Wilson
583bccdd808SJohn Stultz stress_array = kmalloc_array(nthreads, sizeof(*stress_array),
584bccdd808SJohn Stultz GFP_KERNEL);
585bccdd808SJohn Stultz if (!stress_array) {
586bccdd808SJohn Stultz kfree(locks);
587bccdd808SJohn Stultz return -ENOMEM;
588bccdd808SJohn Stultz }
589bccdd808SJohn Stultz
5902a0c1128SChris Wilson for (n = 0; n < nlocks; n++)
5912a0c1128SChris Wilson ww_mutex_init(&locks[n], &ww_class);
5922a0c1128SChris Wilson
593bccdd808SJohn Stultz count = 0;
5942a0c1128SChris Wilson for (n = 0; nthreads; n++) {
5952a0c1128SChris Wilson struct stress *stress;
5962a0c1128SChris Wilson void (*fn)(struct work_struct *work);
5972a0c1128SChris Wilson
5982a0c1128SChris Wilson fn = NULL;
5992a0c1128SChris Wilson switch (n & 3) {
6002a0c1128SChris Wilson case 0:
6012a0c1128SChris Wilson if (flags & STRESS_INORDER)
6022a0c1128SChris Wilson fn = stress_inorder_work;
6032a0c1128SChris Wilson break;
6042a0c1128SChris Wilson case 1:
6052a0c1128SChris Wilson if (flags & STRESS_REORDER)
6062a0c1128SChris Wilson fn = stress_reorder_work;
6072a0c1128SChris Wilson break;
6082a0c1128SChris Wilson case 2:
6092a0c1128SChris Wilson if (flags & STRESS_ONE)
6102a0c1128SChris Wilson fn = stress_one_work;
6112a0c1128SChris Wilson break;
6122a0c1128SChris Wilson }
6132a0c1128SChris Wilson
6142a0c1128SChris Wilson if (!fn)
6152a0c1128SChris Wilson continue;
6162a0c1128SChris Wilson
617bccdd808SJohn Stultz stress = &stress_array[count++];
6182a0c1128SChris Wilson
6192a0c1128SChris Wilson INIT_WORK(&stress->work, fn);
6202a0c1128SChris Wilson stress->locks = locks;
6212a0c1128SChris Wilson stress->nlocks = nlocks;
62257dd924eSChris Wilson stress->timeout = jiffies + 2*HZ;
6232a0c1128SChris Wilson
6242a0c1128SChris Wilson queue_work(wq, &stress->work);
6252a0c1128SChris Wilson nthreads--;
6262a0c1128SChris Wilson }
6272a0c1128SChris Wilson
6282a0c1128SChris Wilson flush_workqueue(wq);
6292a0c1128SChris Wilson
6302a0c1128SChris Wilson for (n = 0; n < nlocks; n++)
6312a0c1128SChris Wilson ww_mutex_destroy(&locks[n]);
632bccdd808SJohn Stultz kfree(stress_array);
6332a0c1128SChris Wilson kfree(locks);
6342a0c1128SChris Wilson
6352a0c1128SChris Wilson return 0;
6362a0c1128SChris Wilson }
6372a0c1128SChris Wilson
test_ww_mutex_init(void)638f2a5fec1SChris Wilson static int __init test_ww_mutex_init(void)
639f2a5fec1SChris Wilson {
640d1b42b80SChris Wilson int ncpus = num_online_cpus();
64112235da8SMaarten Lankhorst int ret, i;
64212235da8SMaarten Lankhorst
64312235da8SMaarten Lankhorst printk(KERN_INFO "Beginning ww mutex selftests\n");
644f2a5fec1SChris Wilson
6454812c54dSJohn Stultz prandom_seed_state(&rng, get_random_u64());
6464812c54dSJohn Stultz
647d1b42b80SChris Wilson wq = alloc_workqueue("test-ww_mutex", WQ_UNBOUND, 0);
648d1b42b80SChris Wilson if (!wq)
649d1b42b80SChris Wilson return -ENOMEM;
650d1b42b80SChris Wilson
651f2a5fec1SChris Wilson ret = test_mutex();
652f2a5fec1SChris Wilson if (ret)
653f2a5fec1SChris Wilson return ret;
654f2a5fec1SChris Wilson
65512235da8SMaarten Lankhorst ret = test_aa(false);
656c22fb380SChris Wilson if (ret)
657c22fb380SChris Wilson return ret;
658c22fb380SChris Wilson
65912235da8SMaarten Lankhorst ret = test_aa(true);
66070207686SChris Wilson if (ret)
66170207686SChris Wilson return ret;
66270207686SChris Wilson
66312235da8SMaarten Lankhorst for (i = 0; i < 4; i++) {
66412235da8SMaarten Lankhorst ret = test_abba(i & 1, i & 2);
66570207686SChris Wilson if (ret)
66670207686SChris Wilson return ret;
66712235da8SMaarten Lankhorst }
66870207686SChris Wilson
669d1b42b80SChris Wilson ret = test_cycle(ncpus);
670d1b42b80SChris Wilson if (ret)
671d1b42b80SChris Wilson return ret;
672d1b42b80SChris Wilson
67357dd924eSChris Wilson ret = stress(16, 2*ncpus, STRESS_INORDER);
6742a0c1128SChris Wilson if (ret)
6752a0c1128SChris Wilson return ret;
6762a0c1128SChris Wilson
67757dd924eSChris Wilson ret = stress(16, 2*ncpus, STRESS_REORDER);
6782a0c1128SChris Wilson if (ret)
6792a0c1128SChris Wilson return ret;
6802a0c1128SChris Wilson
681823a5662SThomas Hellström ret = stress(2046, hweight32(STRESS_ALL)*ncpus, STRESS_ALL);
6822a0c1128SChris Wilson if (ret)
6832a0c1128SChris Wilson return ret;
6842a0c1128SChris Wilson
68512235da8SMaarten Lankhorst printk(KERN_INFO "All ww mutex selftests passed\n");
686f2a5fec1SChris Wilson return 0;
687f2a5fec1SChris Wilson }
688f2a5fec1SChris Wilson
test_ww_mutex_exit(void)689f2a5fec1SChris Wilson static void __exit test_ww_mutex_exit(void)
690f2a5fec1SChris Wilson {
691d1b42b80SChris Wilson destroy_workqueue(wq);
692f2a5fec1SChris Wilson }
693f2a5fec1SChris Wilson
694f2a5fec1SChris Wilson module_init(test_ww_mutex_init);
695f2a5fec1SChris Wilson module_exit(test_ww_mutex_exit);
696f2a5fec1SChris Wilson
697f2a5fec1SChris Wilson MODULE_LICENSE("GPL");
698f2a5fec1SChris Wilson MODULE_AUTHOR("Intel Corporation");
699588661fdSJeff Johnson MODULE_DESCRIPTION("API test facility for ww_mutexes");
700