kernel/locking: Add context to ww_mutex_trylock()
[linux-2.6-microblaze.git] / kernel / locking / test-ww_mutex.c
index 3e82f44..d63ac41 100644 (file)
 static DEFINE_WD_CLASS(ww_class);
 struct workqueue_struct *wq;
 
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+#define ww_acquire_init_noinject(a, b) do { \
+               ww_acquire_init((a), (b)); \
+               (a)->deadlock_inject_countdown = ~0U; \
+       } while (0)
+#else
+#define ww_acquire_init_noinject(a, b) ww_acquire_init((a), (b))
+#endif
+
 struct test_mutex {
        struct work_struct work;
        struct ww_mutex mutex;
@@ -36,7 +45,7 @@ static void test_mutex_work(struct work_struct *work)
        wait_for_completion(&mtx->go);
 
        if (mtx->flags & TEST_MTX_TRY) {
-               while (!ww_mutex_trylock(&mtx->mutex))
+               while (!ww_mutex_trylock(&mtx->mutex, NULL))
                        cond_resched();
        } else {
                ww_mutex_lock(&mtx->mutex, NULL);
@@ -109,19 +118,38 @@ static int test_mutex(void)
        return 0;
 }
 
-static int test_aa(void)
+static int test_aa(bool trylock)
 {
        struct ww_mutex mutex;
        struct ww_acquire_ctx ctx;
        int ret;
+       const char *from = trylock ? "trylock" : "lock";
 
        ww_mutex_init(&mutex, &ww_class);
        ww_acquire_init(&ctx, &ww_class);
 
-       ww_mutex_lock(&mutex, &ctx);
+       if (!trylock) {
+               ret = ww_mutex_lock(&mutex, &ctx);
+               if (ret) {
+                       pr_err("%s: initial lock failed!\n", __func__);
+                       goto out;
+               }
+       } else {
+               if (!ww_mutex_trylock(&mutex, &ctx)) {
+                       pr_err("%s: initial trylock failed!\n", __func__);
+                       goto out;
+               }
+       }
 
-       if (ww_mutex_trylock(&mutex))  {
-               pr_err("%s: trylocked itself!\n", __func__);
+       if (ww_mutex_trylock(&mutex, NULL))  {
+               pr_err("%s: trylocked itself without context from %s!\n", __func__, from);
+               ww_mutex_unlock(&mutex);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (ww_mutex_trylock(&mutex, &ctx))  {
+               pr_err("%s: trylocked itself with context from %s!\n", __func__, from);
                ww_mutex_unlock(&mutex);
                ret = -EINVAL;
                goto out;
@@ -129,17 +157,17 @@ static int test_aa(void)
 
        ret = ww_mutex_lock(&mutex, &ctx);
        if (ret != -EALREADY) {
-               pr_err("%s: missed deadlock for recursing, ret=%d\n",
-                      __func__, ret);
+               pr_err("%s: missed deadlock for recursing, ret=%d from %s\n",
+                      __func__, ret, from);
                if (!ret)
                        ww_mutex_unlock(&mutex);
                ret = -EINVAL;
                goto out;
        }
 
+       ww_mutex_unlock(&mutex);
        ret = 0;
 out:
-       ww_mutex_unlock(&mutex);
        ww_acquire_fini(&ctx);
        return ret;
 }
@@ -150,7 +178,7 @@ struct test_abba {
        struct ww_mutex b_mutex;
        struct completion a_ready;
        struct completion b_ready;
-       bool resolve;
+       bool resolve, trylock;
        int result;
 };
 
@@ -160,8 +188,13 @@ static void test_abba_work(struct work_struct *work)
        struct ww_acquire_ctx ctx;
        int err;
 
-       ww_acquire_init(&ctx, &ww_class);
-       ww_mutex_lock(&abba->b_mutex, &ctx);
+       ww_acquire_init_noinject(&ctx, &ww_class);
+       if (!abba->trylock)
+               ww_mutex_lock(&abba->b_mutex, &ctx);
+       else
+               WARN_ON(!ww_mutex_trylock(&abba->b_mutex, &ctx));
+
+       WARN_ON(READ_ONCE(abba->b_mutex.ctx) != &ctx);
 
        complete(&abba->b_ready);
        wait_for_completion(&abba->a_ready);
@@ -181,7 +214,7 @@ static void test_abba_work(struct work_struct *work)
        abba->result = err;
 }
 
-static int test_abba(bool resolve)
+static int test_abba(bool trylock, bool resolve)
 {
        struct test_abba abba;
        struct ww_acquire_ctx ctx;
@@ -192,12 +225,18 @@ static int test_abba(bool resolve)
        INIT_WORK_ONSTACK(&abba.work, test_abba_work);
        init_completion(&abba.a_ready);
        init_completion(&abba.b_ready);
+       abba.trylock = trylock;
        abba.resolve = resolve;
 
        schedule_work(&abba.work);
 
-       ww_acquire_init(&ctx, &ww_class);
-       ww_mutex_lock(&abba.a_mutex, &ctx);
+       ww_acquire_init_noinject(&ctx, &ww_class);
+       if (!trylock)
+               ww_mutex_lock(&abba.a_mutex, &ctx);
+       else
+               WARN_ON(!ww_mutex_trylock(&abba.a_mutex, &ctx));
+
+       WARN_ON(READ_ONCE(abba.a_mutex.ctx) != &ctx);
 
        complete(&abba.a_ready);
        wait_for_completion(&abba.b_ready);
@@ -249,7 +288,7 @@ static void test_cycle_work(struct work_struct *work)
        struct ww_acquire_ctx ctx;
        int err, erra = 0;
 
-       ww_acquire_init(&ctx, &ww_class);
+       ww_acquire_init_noinject(&ctx, &ww_class);
        ww_mutex_lock(&cycle->a_mutex, &ctx);
 
        complete(cycle->a_signal);
@@ -581,7 +620,9 @@ static int stress(int nlocks, int nthreads, unsigned int flags)
 static int __init test_ww_mutex_init(void)
 {
        int ncpus = num_online_cpus();
-       int ret;
+       int ret, i;
+
+       printk(KERN_INFO "Beginning ww mutex selftests\n");
 
        wq = alloc_workqueue("test-ww_mutex", WQ_UNBOUND, 0);
        if (!wq)
@@ -591,17 +632,19 @@ static int __init test_ww_mutex_init(void)
        if (ret)
                return ret;
 
-       ret = test_aa();
+       ret = test_aa(false);
        if (ret)
                return ret;
 
-       ret = test_abba(false);
+       ret = test_aa(true);
        if (ret)
                return ret;
 
-       ret = test_abba(true);
-       if (ret)
-               return ret;
+       for (i = 0; i < 4; i++) {
+               ret = test_abba(i & 1, i & 2);
+               if (ret)
+                       return ret;
+       }
 
        ret = test_cycle(ncpus);
        if (ret)
@@ -619,6 +662,7 @@ static int __init test_ww_mutex_init(void)
        if (ret)
                return ret;
 
+       printk(KERN_INFO "All ww mutex selftests passed\n");
        return 0;
 }