[PATCH v2 5/8] locking: Add kselftests for ww_mutex ABBA deadlock detection
Signed-off-by: Chris WilsonCc: Peter Zijlstra Cc: Ingo Molnar Cc: Maarten Lankhorst Cc: Nicolai Hähnle --- kernel/locking/test-ww_mutex.c | 98 ++ 1 file changed, 98 insertions(+) diff --git a/kernel/locking/test-ww_mutex.c b/kernel/locking/test-ww_mutex.c index 835fa7a1036e..5a643ba2b020 100644 --- a/kernel/locking/test-ww_mutex.c +++ b/kernel/locking/test-ww_mutex.c @@ -153,6 +153,96 @@ 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; + bool resolve; + int result; +}; + +static void test_abba_work(struct work_struct *work) +{ + struct test_abba *abba = container_of(work, typeof(*abba), work); + struct ww_acquire_ctx ctx; + int err; + + ww_acquire_init(, _class); + ww_mutex_lock(>b_mutex, ); + + complete(>b_ready); + wait_for_completion(>a_ready); + + err = ww_mutex_lock(>a_mutex, ); + if (abba->resolve && err == -EDEADLK) { + ww_mutex_unlock(>b_mutex); + ww_mutex_lock_slow(>a_mutex, ); + err = ww_mutex_lock(>b_mutex, ); + } + + if (!err) + ww_mutex_unlock(>a_mutex); + ww_mutex_unlock(>b_mutex); + ww_acquire_fini(); + + abba->result = err; +} + +static int test_abba(bool resolve) +{ + struct test_abba abba; + struct ww_acquire_ctx ctx; + int err, ret; + + ww_mutex_init(_mutex, _class); + ww_mutex_init(_mutex, _class); + INIT_WORK_ONSTACK(, test_abba_work); + init_completion(_ready); + init_completion(_ready); + abba.resolve = resolve; + + schedule_work(); + + ww_acquire_init(, _class); + ww_mutex_lock(_mutex, ); + + complete(_ready); + wait_for_completion(_ready); + + err = ww_mutex_lock(_mutex, ); + if (resolve && err == -EDEADLK) { + ww_mutex_unlock(_mutex); + ww_mutex_lock_slow(_mutex, ); + err = ww_mutex_lock(_mutex, ); + } + + if (!err) + ww_mutex_unlock(_mutex); + ww_mutex_unlock(_mutex); + ww_acquire_fini(); + + flush_work(); + destroy_work_on_stack(); + + ret = 0; + if (resolve) { + if (err || abba.result) { + pr_err("%s: failed to resolve ABBA deadlock, A err=%d, B err=%d\n", + __func__, err, abba.result); + ret = -EINVAL; + } + } else { + if (err != -EDEADLK && abba.result != -EDEADLK) { + pr_err("%s: missed ABBA deadlock, A err=%d, B err=%d\n", + __func__, err, abba.result); + ret = -EINVAL; + } + } + return ret; +} + static int __init test_ww_mutex_init(void) { int ret; @@ -165,6 +255,14 @@ static int __init test_ww_mutex_init(void) if (ret) return ret; + ret = test_abba(false); + if (ret) + return ret; + + ret = test_abba(true); + if (ret) + return ret; + return 0; } -- 2.10.2
[PATCH v2 5/8] locking: Add kselftests for ww_mutex ABBA deadlock detection
Signed-off-by: Chris Wilson Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Maarten Lankhorst Cc: Nicolai Hähnle --- kernel/locking/test-ww_mutex.c | 98 ++ 1 file changed, 98 insertions(+) diff --git a/kernel/locking/test-ww_mutex.c b/kernel/locking/test-ww_mutex.c index 835fa7a1036e..5a643ba2b020 100644 --- a/kernel/locking/test-ww_mutex.c +++ b/kernel/locking/test-ww_mutex.c @@ -153,6 +153,96 @@ 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; + bool resolve; + int result; +}; + +static void test_abba_work(struct work_struct *work) +{ + struct test_abba *abba = container_of(work, typeof(*abba), work); + struct ww_acquire_ctx ctx; + int err; + + ww_acquire_init(, _class); + ww_mutex_lock(>b_mutex, ); + + complete(>b_ready); + wait_for_completion(>a_ready); + + err = ww_mutex_lock(>a_mutex, ); + if (abba->resolve && err == -EDEADLK) { + ww_mutex_unlock(>b_mutex); + ww_mutex_lock_slow(>a_mutex, ); + err = ww_mutex_lock(>b_mutex, ); + } + + if (!err) + ww_mutex_unlock(>a_mutex); + ww_mutex_unlock(>b_mutex); + ww_acquire_fini(); + + abba->result = err; +} + +static int test_abba(bool resolve) +{ + struct test_abba abba; + struct ww_acquire_ctx ctx; + int err, ret; + + ww_mutex_init(_mutex, _class); + ww_mutex_init(_mutex, _class); + INIT_WORK_ONSTACK(, test_abba_work); + init_completion(_ready); + init_completion(_ready); + abba.resolve = resolve; + + schedule_work(); + + ww_acquire_init(, _class); + ww_mutex_lock(_mutex, ); + + complete(_ready); + wait_for_completion(_ready); + + err = ww_mutex_lock(_mutex, ); + if (resolve && err == -EDEADLK) { + ww_mutex_unlock(_mutex); + ww_mutex_lock_slow(_mutex, ); + err = ww_mutex_lock(_mutex, ); + } + + if (!err) + ww_mutex_unlock(_mutex); + ww_mutex_unlock(_mutex); + ww_acquire_fini(); + + flush_work(); + destroy_work_on_stack(); + + ret = 0; + if (resolve) { + if (err || abba.result) { + pr_err("%s: failed to resolve ABBA deadlock, A err=%d, B err=%d\n", + __func__, err, abba.result); + ret = -EINVAL; + } + } else { + if (err != -EDEADLK && abba.result != -EDEADLK) { + pr_err("%s: missed ABBA deadlock, A err=%d, B err=%d\n", + __func__, err, abba.result); + ret = -EINVAL; + } + } + return ret; +} + static int __init test_ww_mutex_init(void) { int ret; @@ -165,6 +255,14 @@ static int __init test_ww_mutex_init(void) if (ret) return ret; + ret = test_abba(false); + if (ret) + return ret; + + ret = test_abba(true); + if (ret) + return ret; + return 0; } -- 2.10.2