X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=module%2Fsplat%2Fsplat-rwlock.c;h=c11ab94f2a2de262ab558ca8ff9ecd2245eb39e5;hb=9c9ad845ef372a4c47a01c20e939fd2c40bc7ac6;hp=9e335d75658e7480c5ecbea8c7a8747dcecfa695;hpb=df870a697fc8669d63534b27a108335269a7884f;p=mirror_spl.git diff --git a/module/splat/splat-rwlock.c b/module/splat/splat-rwlock.c index 9e335d7..c11ab94 100644 --- a/module/splat/splat-rwlock.c +++ b/module/splat/splat-rwlock.c @@ -6,7 +6,7 @@ * UCRL-CODE-235197 * * This file is part of the SPL, Solaris Porting Layer. - * For details, see . + * For details, see . * * 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 @@ -24,9 +24,11 @@ * Solaris Porting LAyer Tests (SPLAT) Read/Writer Lock Tests. \*****************************************************************************/ +#include #include #include -#include +#include +#include #include "splat-internal.h" #define SPLAT_RWLOCK_NAME "rwlock" @@ -53,8 +55,12 @@ #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" @@ -82,7 +88,7 @@ typedef struct rw_priv { 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) @@ -106,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); @@ -127,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); @@ -153,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); @@ -178,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); @@ -202,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; @@ -214,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 */ @@ -330,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; @@ -347,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; @@ -468,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; @@ -503,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; @@ -583,19 +585,65 @@ 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; } -#if defined(CONFIG_RWSEM_GENERIC_SPINLOCK) /* With one reader upgrade should never fail. */ rc = rw_tryupgrade(&rwp->rw_rwlock); if (!rc) { - splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME, + splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME, "rwlock failed upgrade from reader: %d\n", RW_READ_HELD(&rwp->rw_rwlock)); rc = -ENOLCK; @@ -603,7 +651,7 @@ splat_rwlock_test6(struct file *file, void *arg) } 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)); @@ -611,13 +659,8 @@ 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"); -#else - rc = 0; - splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME, "%s", - "rw_tryupgrade() is disabled for this arch\n"); -#endif out: rw_exit(&rwp->rw_rwlock); rw_destroy(&rwp->rw_rwlock); @@ -643,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; } @@ -663,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); }