diff options
Diffstat (limited to 'module/spl/spl-rwlock.c')
-rw-r--r-- | module/spl/spl-rwlock.c | 326 |
1 files changed, 29 insertions, 297 deletions
diff --git a/module/spl/spl-rwlock.c b/module/spl/spl-rwlock.c index 07fc2aae4..8ff66bf9f 100644 --- a/module/spl/spl-rwlock.c +++ b/module/spl/spl-rwlock.c @@ -33,6 +33,11 @@ #define DEBUG_SUBSYSTEM S_RWLOCK #ifdef CONFIG_RWSEM_GENERIC_SPINLOCK + +/* + * From lib/rwsem-spinlock.c but modified such that the caller is + * responsible for acquiring and dropping the sem->wait_lock. + */ struct rwsem_waiter { struct list_head list; struct task_struct *task; @@ -40,322 +45,49 @@ struct rwsem_waiter { #define RWSEM_WAITING_FOR_READ 0x00000001 #define RWSEM_WAITING_FOR_WRITE 0x00000002 }; + /* wake a single writer */ static struct rw_semaphore * __rwsem_wake_one_writer_locked(struct rw_semaphore *sem) { - struct rwsem_waiter *waiter; - struct task_struct *tsk; + struct rwsem_waiter *waiter; + struct task_struct *tsk; - sem->activity = -1; + sem->activity = -1; - waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); - list_del(&waiter->list); + waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); + list_del(&waiter->list); - tsk = waiter->task; - smp_mb(); - waiter->task = NULL; - wake_up_process(tsk); - put_task_struct(tsk); - return sem; + tsk = waiter->task; + smp_mb(); + waiter->task = NULL; + wake_up_process(tsk); + put_task_struct(tsk); + return sem; } /* release a read lock on the semaphore */ -static void +void __up_read_locked(struct rw_semaphore *sem) { - if (--sem->activity == 0 && !list_empty(&sem->wait_list)) - (void)__rwsem_wake_one_writer_locked(sem); + if (--sem->activity == 0 && !list_empty(&sem->wait_list)) + (void)__rwsem_wake_one_writer_locked(sem); } +EXPORT_SYMBOL(__up_read_locked); /* trylock for writing -- returns 1 if successful, 0 if contention */ -static int -__down_write_trylock_locked(struct rw_semaphore *sem) -{ - int ret = 0; - - if (sem->activity == 0 && list_empty(&sem->wait_list)) { - /* granted */ - sem->activity = -1; - ret = 1; - } - - return ret; -} -#endif - -void -__rw_init(krwlock_t *rwlp, char *name, krw_type_t type, void *arg) -{ - int flags = KM_SLEEP; - - ASSERT(rwlp); - ASSERT(name); - ASSERT(type == RW_DEFAULT); /* XXX no irq handler use */ - ASSERT(arg == NULL); /* XXX no irq handler use */ - - rwlp->rw_magic = RW_MAGIC; - rwlp->rw_owner = NULL; - rwlp->rw_name = NULL; - rwlp->rw_name_size = strlen(name) + 1; - - /* We may be called when there is a non-zero preempt_count or - * interrupts are disabled is which case we must not sleep. - */ - if (current_thread_info()->preempt_count || irqs_disabled()) - flags = KM_NOSLEEP; - - rwlp->rw_name = kmem_alloc(rwlp->rw_name_size, flags); - if (rwlp->rw_name == NULL) - return; - - init_rwsem(&rwlp->rw_sem); - strcpy(rwlp->rw_name, name); -} -EXPORT_SYMBOL(__rw_init); - -void -__rw_destroy(krwlock_t *rwlp) -{ - ASSERT(rwlp); - ASSERT(rwlp->rw_magic == RW_MAGIC); - ASSERT(rwlp->rw_owner == NULL); - spin_lock(&rwlp->rw_sem.wait_lock); - ASSERT(list_empty(&rwlp->rw_sem.wait_list)); - spin_unlock(&rwlp->rw_sem.wait_lock); - - kmem_free(rwlp->rw_name, rwlp->rw_name_size); - - memset(rwlp, RW_POISON, sizeof(krwlock_t)); -} -EXPORT_SYMBOL(__rw_destroy); - -/* Return 0 if the lock could not be obtained without blocking. */ int -__rw_tryenter(krwlock_t *rwlp, krw_t rw) -{ - int rc = 0; - ENTRY; - - ASSERT(rwlp); - ASSERT(rwlp->rw_magic == RW_MAGIC); - - switch (rw) { - /* these functions return 1 if success, 0 if contention */ - case RW_READER: - /* Here the Solaris code would return 0 - * if there were any write waiters. Specifically - * thinking about the case where readers may have - * the lock and we would also allow this thread - * to grab the read lock with a writer waiting in the - * queue. This doesn't seem like a correctness - * issue, so just call down_read_trylock() - * for the test. We may have to revisit this if - * it becomes an issue */ - rc = down_read_trylock(&rwlp->rw_sem); - break; - case RW_WRITER: - rc = down_write_trylock(&rwlp->rw_sem); - if (rc) { - /* there better not be anyone else - * holding the write lock here */ - ASSERT(rwlp->rw_owner == NULL); - rwlp->rw_owner = current; - } - break; - default: - SBUG(); - } - - RETURN(rc); -} -EXPORT_SYMBOL(__rw_tryenter); - -void -__rw_enter(krwlock_t *rwlp, krw_t rw) -{ - ENTRY; - ASSERT(rwlp); - ASSERT(rwlp->rw_magic == RW_MAGIC); - - switch (rw) { - case RW_READER: - /* Here the Solaris code would block - * if there were any write waiters. Specifically - * thinking about the case where readers may have - * the lock and we would also allow this thread - * to grab the read lock with a writer waiting in the - * queue. This doesn't seem like a correctness - * issue, so just call down_read() - * for the test. We may have to revisit this if - * it becomes an issue */ - down_read(&rwlp->rw_sem); - break; - case RW_WRITER: - down_write(&rwlp->rw_sem); - - /* there better not be anyone else - * holding the write lock here */ - ASSERT(rwlp->rw_owner == NULL); - rwlp->rw_owner = current; - break; - default: - SBUG(); - } - EXIT; -} -EXPORT_SYMBOL(__rw_enter); - -void -__rw_exit(krwlock_t *rwlp) -{ - ENTRY; - ASSERT(rwlp); - ASSERT(rwlp->rw_magic == RW_MAGIC); - - /* rw_owner is held by current - * thread iff it is a writer */ - if (rwlp->rw_owner == current) { - rwlp->rw_owner = NULL; - up_write(&rwlp->rw_sem); - } else { - up_read(&rwlp->rw_sem); - } - EXIT; -} -EXPORT_SYMBOL(__rw_exit); - -void -__rw_downgrade(krwlock_t *rwlp) -{ - ENTRY; - ASSERT(rwlp); - ASSERT(rwlp->rw_magic == RW_MAGIC); - ASSERT(rwlp->rw_owner == current); - - rwlp->rw_owner = NULL; - downgrade_write(&rwlp->rw_sem); - EXIT; -} -EXPORT_SYMBOL(__rw_downgrade); - -/* Return 0 if unable to perform the upgrade. - * Might be wise to fix the caller - * to acquire the write lock first? - */ -int -__rw_tryupgrade(krwlock_t *rwlp) -{ - int rc = 0; - ENTRY; - - ASSERT(rwlp); - ASSERT(rwlp->rw_magic == RW_MAGIC); - - spin_lock(&rwlp->rw_sem.wait_lock); - - /* Check if there is anyone waiting for the - * lock. If there is, then we know we should - * not try to upgrade the lock */ - if (!list_empty(&rwlp->rw_sem.wait_list)) { - spin_unlock(&rwlp->rw_sem.wait_lock); - RETURN(0); - } -#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK - /* Note that activity is protected by - * the wait_lock. Don't try to upgrade - * if there are multiple readers currently - * holding the lock */ - if (rwlp->rw_sem.activity > 1) { -#else - /* Don't try to upgrade - * if there are multiple readers currently - * holding the lock */ - if ((rwlp->rw_sem.count & RWSEM_ACTIVE_MASK) > 1) { -#endif - spin_unlock(&rwlp->rw_sem.wait_lock); - RETURN(0); - } - -#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK - /* Here it should be safe to drop the - * read lock and reacquire it for writing since - * we know there are no waiters */ - __up_read_locked(&rwlp->rw_sem); - - /* returns 1 if success, 0 if contention */ - rc = __down_write_trylock_locked(&rwlp->rw_sem); -#else - /* Here it should be safe to drop the - * read lock and reacquire it for writing since - * we know there are no waiters */ - up_read(&rwlp->rw_sem); - - /* returns 1 if success, 0 if contention */ - rc = down_write_trylock(&rwlp->rw_sem); -#endif - - /* Check if upgrade failed. Should not ever happen - * if we got to this point */ - ASSERT(rc); - ASSERT(rwlp->rw_owner == NULL); - rwlp->rw_owner = current; - spin_unlock(&rwlp->rw_sem.wait_lock); - - RETURN(1); -} -EXPORT_SYMBOL(__rw_tryupgrade); - -kthread_t * -__rw_owner(krwlock_t *rwlp) +__down_write_trylock_locked(struct rw_semaphore *sem) { - ENTRY; - ASSERT(rwlp); - ASSERT(rwlp->rw_magic == RW_MAGIC); - RETURN(rwlp->rw_owner); -} -EXPORT_SYMBOL(__rw_owner); + int ret = 0; -int -__rw_read_held(krwlock_t *rwlp) -{ - ENTRY; - ASSERT(rwlp); - ASSERT(rwlp->rw_magic == RW_MAGIC); - RETURN(__rw_lock_held(rwlp) && rwlp->rw_owner == NULL); -} -EXPORT_SYMBOL(__rw_read_held); + if (sem->activity == 0 && list_empty(&sem->wait_list)) { + sem->activity = -1; + ret = 1; + } -int -__rw_write_held(krwlock_t *rwlp) -{ - ENTRY; - ASSERT(rwlp); - ASSERT(rwlp->rw_magic == RW_MAGIC); - RETURN(rwlp->rw_owner == current); + return ret; } -EXPORT_SYMBOL(__rw_write_held); - -int -__rw_lock_held(krwlock_t *rwlp) -{ - int rc = 0; - ENTRY; +EXPORT_SYMBOL(__down_write_trylock_locked); - ASSERT(rwlp); - ASSERT(rwlp->rw_magic == RW_MAGIC); - - spin_lock_irq(&(rwlp->rw_sem.wait_lock)); -#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK - if (rwlp->rw_sem.activity != 0) { -#else - if (rwlp->rw_sem.count != 0) { #endif - rc = 1; - } - - spin_unlock_irq(&(rwlp->rw_sem.wait_lock)); - - RETURN(rc); -} -EXPORT_SYMBOL(__rw_lock_held); |