Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk> Cc: Peter Zijlstra <pet...@infradead.org> Cc: Maarten Lankhorst <d...@mblankhorst.nl> Cc: Nicolai Hähnle <nhaeh...@gmail.com> --- kernel/locking/test-ww_mutex.c | 75 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/kernel/locking/test-ww_mutex.c b/kernel/locking/test-ww_mutex.c index 02a4bacf8aac..63a5031de138 100644 --- a/kernel/locking/test-ww_mutex.c +++ b/kernel/locking/test-ww_mutex.c @@ -153,6 +153,77 @@ static int test_aa(void) return ret; } +struct test_abba { + struct work_struct work; + struct ww_mutex a_mutex; + struct ww_mutex b_mutex; + struct completion a_ready; + struct completion b_ready; + struct completion done; + int ret; +}; + +static void test_abba_work(struct work_struct *work) +{ + struct test_abba *abba = container_of(work, typeof(*abba), work); + struct ww_acquire_ctx ctx; + + ww_acquire_init(&ctx, &ww_class); + ww_mutex_lock(&abba->b_mutex, &ctx); + + complete(&abba->b_ready); + wait_for_completion(&abba->a_ready); + abba->ret = ww_mutex_lock(&abba->a_mutex, &ctx); + if (!abba->ret) + ww_mutex_unlock(&abba->a_mutex); + + ww_mutex_unlock(&abba->b_mutex); + ww_acquire_fini(&ctx); + + complete(&abba->done); +} + +static int test_abba(void) +{ + struct test_abba abba; + struct ww_acquire_ctx ctx; + int ret; + + ww_mutex_init(&abba.a_mutex, &ww_class); + ww_mutex_init(&abba.b_mutex, &ww_class); + INIT_WORK_ONSTACK(&abba.work, test_abba_work); + init_completion(&abba.a_ready); + init_completion(&abba.b_ready); + init_completion(&abba.done); + + schedule_work(&abba.work); + + ww_acquire_init(&ctx, &ww_class); + ww_mutex_lock(&abba.a_mutex, &ctx); + complete(&abba.a_ready); + wait_for_completion(&abba.b_ready); + ret = ww_mutex_lock(&abba.b_mutex, &ctx); + if (!ret) + ww_mutex_unlock(&abba.b_mutex); + ww_mutex_unlock(&abba.a_mutex); + + wait_for_completion(&abba.done); + + if (ret != -EDEADLK && abba.ret != -EDEADLK) { + pr_err("%s: missed ABBA deadlock, A ret=%d, B ret=%d\n", + __func__, ret, abba.ret); + ret = -EINVAL; + goto out; + } + + ret = 0; +out: + ww_acquire_fini(&ctx); + flush_work(&abba.work); + destroy_work_on_stack(&abba.work); + return ret; +} + static int __init test_ww_mutex_init(void) { int ret; @@ -165,6 +236,10 @@ static int __init test_ww_mutex_init(void) if (ret) return ret; + ret = test_abba(); + if (ret) + return ret; + return 0; } -- 2.10.2