]> git.proxmox.com Git - mirror_spl.git/blobdiff - module/splat/splat-rwlock.c
Refactor some splat macro to function
[mirror_spl.git] / module / splat / splat-rwlock.c
index 13140260c5b3205fc7760e39076a5ea9e29f0988..c11ab94f2a2de262ab558ca8ff9ecd2245eb39e5 100644 (file)
@@ -1,29 +1,34 @@
-/*
- *  This file is part of the SPL: Solaris Porting Layer.
- *
- *  Copyright (c) 2008 Lawrence Livermore National Security, LLC.
- *  Produced at Lawrence Livermore National Laboratory
- *  Written by:
- *       Brian Behlendorf <behlendorf1@llnl.gov>,
- *       Herb Wartens <wartens2@llnl.gov>,
- *       Jim Garlick <garlick@llnl.gov>
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
  *  UCRL-CODE-235197
  *
- *  This is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
  *
- *  This is distributed in the hope that it will be useful, but WITHOUT
+ *  The SPL is distributed in the hope that it will be useful, but WITHOUT
  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  *  for more details.
  *
  *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- */
-
+ *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Read/Writer Lock Tests.
+\*****************************************************************************/
+
+#include <sys/random.h>
+#include <sys/rwlock.h>
+#include <sys/taskq.h>
+#include <linux/delay.h>
+#include <linux/mm_compat.h>
 #include "splat-internal.h"
 
 #define SPLAT_RWLOCK_NAME              "rwlock"
 #define SPLAT_RWLOCK_TEST5_DESC                "Write downgrade"
 
 #define SPLAT_RWLOCK_TEST6_ID          0x0706
-#define SPLAT_RWLOCK_TEST6_NAME                "rw_tryupgrade"
-#define SPLAT_RWLOCK_TEST6_DESC                "Read upgrade"
+#define SPLAT_RWLOCK_TEST6_NAME                "rw_tryupgrade-1"
+#define SPLAT_RWLOCK_TEST6_DESC                "rwsem->count value"
+
+#define SPLAT_RWLOCK_TEST7_ID          0x0707
+#define SPLAT_RWLOCK_TEST7_NAME                "rw_tryupgrade-2"
+#define SPLAT_RWLOCK_TEST7_DESC                "Read upgrade"
 
 #define SPLAT_RWLOCK_TEST_MAGIC                0x115599DDUL
 #define SPLAT_RWLOCK_TEST_NAME         "rwlock_test"
@@ -73,13 +82,13 @@ typedef struct rw_priv {
        int rw_waiters;
        int rw_release;
        int rw_rc;
-       krw_type_t rw_type;
+       krw_t rw_type;
 } rw_priv_t;
 
 typedef struct rw_thr {
        const char *rwt_name;
        rw_priv_t *rwt_rwp;
-       int rwt_id;
+       struct task_struct *rwt_thread;
 } rw_thr_t;
 
 void splat_init_rw_priv(rw_priv_t *rwp, struct file *file)
@@ -103,17 +112,15 @@ splat_rwlock_wr_thr(void *arg)
        rw_thr_t *rwt = (rw_thr_t *)arg;
        rw_priv_t *rwp = rwt->rwt_rwp;
        uint8_t rnd;
-       char name[16];
 
        ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC);
-       snprintf(name, sizeof(name), "rwlock_wr_thr%d", rwt->rwt_id);
-       daemonize(name);
+
        get_random_bytes((void *)&rnd, 1);
        msleep((unsigned int)rnd);
 
        splat_vprint(rwp->rw_file, rwt->rwt_name,
-                    "%s trying to acquire rwlock (%d holding/%d waiting)\n",
-                    name, rwp->rw_holders, rwp->rw_waiters);
+           "%s trying to acquire rwlock (%d holding/%d waiting)\n",
+           rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
        spin_lock(&rwp->rw_lock);
        rwp->rw_waiters++;
        spin_unlock(&rwp->rw_lock);
@@ -124,20 +131,20 @@ splat_rwlock_wr_thr(void *arg)
        rwp->rw_holders++;
        spin_unlock(&rwp->rw_lock);
        splat_vprint(rwp->rw_file, rwt->rwt_name,
-                    "%s acquired rwlock (%d holding/%d waiting)\n",
-                    name, rwp->rw_holders, rwp->rw_waiters);
+           "%s acquired rwlock (%d holding/%d waiting)\n",
+           rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
 
        /* Wait for control thread to signal we can release the write lock */
        wait_event_interruptible(rwp->rw_waitq, splat_locked_test(&rwp->rw_lock,
-                                rwp->rw_release == SPLAT_RWLOCK_RELEASE_WR));
+           rwp->rw_release == SPLAT_RWLOCK_RELEASE_WR));
 
        spin_lock(&rwp->rw_lock);
        rwp->rw_completed++;
        rwp->rw_holders--;
        spin_unlock(&rwp->rw_lock);
        splat_vprint(rwp->rw_file, rwt->rwt_name,
-                  "%s dropped rwlock (%d holding/%d waiting)\n",
-                  name, rwp->rw_holders, rwp->rw_waiters);
+           "%s dropped rwlock (%d holding/%d waiting)\n",
+           rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
 
        rw_exit(&rwp->rw_rwlock);
 
@@ -150,21 +157,19 @@ splat_rwlock_rd_thr(void *arg)
        rw_thr_t *rwt = (rw_thr_t *)arg;
        rw_priv_t *rwp = rwt->rwt_rwp;
        uint8_t rnd;
-       char name[16];
 
        ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC);
-       snprintf(name, sizeof(name), "rwlock_rd_thr%d", rwt->rwt_id);
-       daemonize(name);
+
        get_random_bytes((void *)&rnd, 1);
        msleep((unsigned int)rnd);
 
        /* Don't try and take the semaphore until after someone has it */
-       wait_event_interruptible(rwp->rw_waitq, splat_locked_test(&rwp->rw_lock,
-                                rwp->rw_holders > 0));
+       wait_event_interruptible(rwp->rw_waitq,
+           splat_locked_test(&rwp->rw_lock, rwp->rw_holders > 0));
 
        splat_vprint(rwp->rw_file, rwt->rwt_name,
-                    "%s trying to acquire rwlock (%d holding/%d waiting)\n",
-                    name, rwp->rw_holders, rwp->rw_waiters);
+           "%s trying to acquire rwlock (%d holding/%d waiting)\n",
+           rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
        spin_lock(&rwp->rw_lock);
        rwp->rw_waiters++;
        spin_unlock(&rwp->rw_lock);
@@ -175,20 +180,20 @@ splat_rwlock_rd_thr(void *arg)
        rwp->rw_holders++;
        spin_unlock(&rwp->rw_lock);
        splat_vprint(rwp->rw_file, rwt->rwt_name,
-                    "%s acquired rwlock (%d holding/%d waiting)\n",
-                    name, rwp->rw_holders, rwp->rw_waiters);
+           "%s acquired rwlock (%d holding/%d waiting)\n",
+           rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
 
        /* Wait for control thread to signal we can release the read lock */
        wait_event_interruptible(rwp->rw_waitq, splat_locked_test(&rwp->rw_lock,
-                                rwp->rw_release == SPLAT_RWLOCK_RELEASE_RD));
+           rwp->rw_release == SPLAT_RWLOCK_RELEASE_RD));
 
        spin_lock(&rwp->rw_lock);
        rwp->rw_completed++;
        rwp->rw_holders--;
        spin_unlock(&rwp->rw_lock);
        splat_vprint(rwp->rw_file, rwt->rwt_name,
-                    "%s dropped rwlock (%d holding/%d waiting)\n",
-                    name, rwp->rw_holders, rwp->rw_waiters);
+           "%s dropped rwlock (%d holding/%d waiting)\n",
+           rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
 
        rw_exit(&rwp->rw_rwlock);
 
@@ -199,7 +204,6 @@ static int
 splat_rwlock_test1(struct file *file, void *arg)
 {
        int i, count = 0, rc = 0;
-       long pids[SPLAT_RWLOCK_TEST_COUNT];
        rw_thr_t rwt[SPLAT_RWLOCK_TEST_COUNT];
        rw_priv_t *rwp;
 
@@ -211,22 +215,22 @@ splat_rwlock_test1(struct file *file, void *arg)
 
        /* Create some threads, the exact number isn't important just as
         * long as we know how many we managed to create and should expect. */
-
-
-
        for (i = 0; i < SPLAT_RWLOCK_TEST_COUNT; i++) {
                rwt[i].rwt_rwp = rwp;
-               rwt[i].rwt_id = i;
                rwt[i].rwt_name = SPLAT_RWLOCK_TEST1_NAME;
 
                /* The first thread will be the writer */
                if (i == 0)
-                       pids[i] = kernel_thread(splat_rwlock_wr_thr, &rwt[i], 0);
+                       rwt[i].rwt_thread = spl_kthread_create(splat_rwlock_wr_thr,
+                           &rwt[i], "%s/%d", SPLAT_RWLOCK_TEST_NAME, i);
                else
-                       pids[i] = kernel_thread(splat_rwlock_rd_thr, &rwt[i], 0);
+                       rwt[i].rwt_thread = spl_kthread_create(splat_rwlock_rd_thr,
+                           &rwt[i], "%s/%d", SPLAT_RWLOCK_TEST_NAME, i);
 
-               if (pids[i] >= 0)
+               if (!IS_ERR(rwt[i].rwt_thread)) {
+                       wake_up_process(rwt[i].rwt_thread);
                        count++;
+               }
        }
 
        /* Wait for the writer */
@@ -327,7 +331,7 @@ splat_rwlock_test2(struct file *file, void *arg)
 
        /* Create several threads allowing tasks to race with each other */
        tq = taskq_create(SPLAT_RWLOCK_TEST_TASKQ, num_online_cpus(),
-                         maxclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE);
+                         defclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE);
        if (tq == NULL) {
                rc = -ENOMEM;
                goto out;
@@ -344,7 +348,8 @@ splat_rwlock_test2(struct file *file, void *arg)
         * rwlock is implemented right this will never happy, that's a pass.
         */
        for (i = 0; i < tq_count; i++) {
-               if (!taskq_dispatch(tq,splat_rwlock_test2_func,rwp,TQ_SLEEP)) {
+               if (taskq_dispatch(tq, splat_rwlock_test2_func, rwp,
+                   TQ_SLEEP) == TASKQID_INVALID) {
                        splat_vprint(file, SPLAT_RWLOCK_TEST2_NAME,
                                     "Failed to queue task %d\n", i);
                        rc = -EINVAL;
@@ -465,7 +470,7 @@ splat_rwlock_test4_type(taskq_t *tq, rw_priv_t *rwp, int expected_rc,
                rw_enter(&rwp->rw_rwlock, holder_type);
 
        id = taskq_dispatch(tq, splat_rwlock_test4_func, rwp, TQ_SLEEP);
-       if (id == 0) {
+       if (id == TASKQID_INVALID) {
                splat_vprint(rwp->rw_file, SPLAT_RWLOCK_TEST4_NAME, "%s",
                             "taskq_dispatch() failed\n");
                rc = -EINVAL;
@@ -500,7 +505,7 @@ splat_rwlock_test4(struct file *file, void *arg)
        if (rwp == NULL)
                return -ENOMEM;
 
-       tq = taskq_create(SPLAT_RWLOCK_TEST_TASKQ, 1, maxclsyspri,
+       tq = taskq_create(SPLAT_RWLOCK_TEST_TASKQ, 1, defclsyspri,
                          50, INT_MAX, TASKQ_PREPOPULATE);
        if (tq == NULL) {
                rc = -ENOMEM;
@@ -571,7 +576,7 @@ static int
 splat_rwlock_test6(struct file *file, void *arg)
 {
        rw_priv_t *rwp;
-       int rc = -EINVAL;
+       int rc;
 
        rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
        if (rwp == NULL)
@@ -580,24 +585,73 @@ splat_rwlock_test6(struct file *file, void *arg)
        splat_init_rw_priv(rwp, file);
 
        rw_enter(&rwp->rw_rwlock, RW_READER);
-       if (!RW_READ_HELD(&rwp->rw_rwlock)) {
+       if (RWSEM_COUNT(SEM(&rwp->rw_rwlock)) !=
+           SPL_RWSEM_SINGLE_READER_VALUE) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME,
+                   "We assumed single reader rwsem->count "
+                   "should be %ld, but is %ld\n",
+                   (long int)SPL_RWSEM_SINGLE_READER_VALUE,
+                   (long int)RWSEM_COUNT(SEM(&rwp->rw_rwlock)));
+               rc = -ENOLCK;
+               goto out;
+       }
+       rw_exit(&rwp->rw_rwlock);
+
+       rw_enter(&rwp->rw_rwlock, RW_WRITER);
+       if (RWSEM_COUNT(SEM(&rwp->rw_rwlock)) !=
+           SPL_RWSEM_SINGLE_WRITER_VALUE) {
                splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME,
+                   "We assumed single writer rwsem->count "
+                   "should be %ld, but is %ld\n",
+                   (long int)SPL_RWSEM_SINGLE_WRITER_VALUE,
+                   (long int)RWSEM_COUNT(SEM(&rwp->rw_rwlock)));
+               rc = -ENOLCK;
+               goto out;
+       }
+       rc = 0;
+       splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME, "%s",
+                    "rwsem->count same as we assumed\n");
+out:
+       rw_exit(&rwp->rw_rwlock);
+       rw_destroy(&rwp->rw_rwlock);
+       kfree(rwp);
+
+       return rc;
+}
+
+static int
+splat_rwlock_test7(struct file *file, void *arg)
+{
+       rw_priv_t *rwp;
+       int rc;
+
+       rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
+       if (rwp == NULL)
+               return -ENOMEM;
+
+       splat_init_rw_priv(rwp, file);
+
+       rw_enter(&rwp->rw_rwlock, RW_READER);
+       if (!RW_READ_HELD(&rwp->rw_rwlock)) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME,
                             "rwlock should be read lock: %d\n",
                             RW_READ_HELD(&rwp->rw_rwlock));
+               rc = -ENOLCK;
                goto out;
        }
 
-       /* With one reader upgrade should never fail */
+       /* With one reader upgrade should never fail. */
        rc = rw_tryupgrade(&rwp->rw_rwlock);
        if (!rc) {
-               splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME,
-                            "rwlock contended preventing upgrade: %ld\n",
-                            (long int)RW_COUNT(&rwp->rw_rwlock));
+               splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME,
+                            "rwlock failed upgrade from reader: %d\n",
+                            RW_READ_HELD(&rwp->rw_rwlock));
+               rc = -ENOLCK;
                goto out;
        }
 
        if (RW_READ_HELD(&rwp->rw_rwlock) || !RW_WRITE_HELD(&rwp->rw_rwlock)) {
-               splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME, "rwlock should "
+               splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME, "rwlock should "
                           "have 0 (not %d) reader and 1 (not %d) writer\n",
                           RW_READ_HELD(&rwp->rw_rwlock),
                           RW_WRITE_HELD(&rwp->rw_rwlock));
@@ -605,7 +659,7 @@ splat_rwlock_test6(struct file *file, void *arg)
        }
 
        rc = 0;
-       splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME, "%s",
+       splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME, "%s",
                     "rwlock properly upgraded\n");
 out:
        rw_exit(&rwp->rw_rwlock);
@@ -632,18 +686,20 @@ splat_rwlock_init(void)
        spin_lock_init(&sub->test_lock);
        sub->desc.id = SPLAT_SUBSYSTEM_RWLOCK;
 
-       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST1_NAME, SPLAT_RWLOCK_TEST1_DESC,
+       splat_test_init(sub, SPLAT_RWLOCK_TEST1_NAME, SPLAT_RWLOCK_TEST1_DESC,
                      SPLAT_RWLOCK_TEST1_ID, splat_rwlock_test1);
-       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST2_NAME, SPLAT_RWLOCK_TEST2_DESC,
+       splat_test_init(sub, SPLAT_RWLOCK_TEST2_NAME, SPLAT_RWLOCK_TEST2_DESC,
                      SPLAT_RWLOCK_TEST2_ID, splat_rwlock_test2);
-       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST3_NAME, SPLAT_RWLOCK_TEST3_DESC,
+       splat_test_init(sub, SPLAT_RWLOCK_TEST3_NAME, SPLAT_RWLOCK_TEST3_DESC,
                      SPLAT_RWLOCK_TEST3_ID, splat_rwlock_test3);
-       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST4_NAME, SPLAT_RWLOCK_TEST4_DESC,
+       splat_test_init(sub, SPLAT_RWLOCK_TEST4_NAME, SPLAT_RWLOCK_TEST4_DESC,
                      SPLAT_RWLOCK_TEST4_ID, splat_rwlock_test4);
-       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST5_NAME, SPLAT_RWLOCK_TEST5_DESC,
+       splat_test_init(sub, SPLAT_RWLOCK_TEST5_NAME, SPLAT_RWLOCK_TEST5_DESC,
                      SPLAT_RWLOCK_TEST5_ID, splat_rwlock_test5);
-       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST6_NAME, SPLAT_RWLOCK_TEST6_DESC,
+       splat_test_init(sub, SPLAT_RWLOCK_TEST6_NAME, SPLAT_RWLOCK_TEST6_DESC,
                      SPLAT_RWLOCK_TEST6_ID, splat_rwlock_test6);
+       splat_test_init(sub, SPLAT_RWLOCK_TEST7_NAME, SPLAT_RWLOCK_TEST7_DESC,
+                     SPLAT_RWLOCK_TEST7_ID, splat_rwlock_test7);
 
        return sub;
 }
@@ -652,12 +708,13 @@ void
 splat_rwlock_fini(splat_subsystem_t *sub)
 {
        ASSERT(sub);
-       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST6_ID);
-       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST5_ID);
-       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST4_ID);
-       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST3_ID);
-       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST2_ID);
-       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST1_ID);
+       splat_test_fini(sub, SPLAT_RWLOCK_TEST7_ID);
+       splat_test_fini(sub, SPLAT_RWLOCK_TEST6_ID);
+       splat_test_fini(sub, SPLAT_RWLOCK_TEST5_ID);
+       splat_test_fini(sub, SPLAT_RWLOCK_TEST4_ID);
+       splat_test_fini(sub, SPLAT_RWLOCK_TEST3_ID);
+       splat_test_fini(sub, SPLAT_RWLOCK_TEST2_ID);
+       splat_test_fini(sub, SPLAT_RWLOCK_TEST1_ID);
        kfree(sub);
 }