4bff34e37def8a90f9194d81bc345c52ba20086athurlow/*
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * CDDL HEADER START
4bff34e37def8a90f9194d81bc345c52ba20086athurlow *
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * The contents of this file are subject to the terms of the
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * Common Development and Distribution License (the "License").
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * You may not use this file except in compliance with the License.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow *
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * or http://www.opensolaris.org/os/licensing.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * See the License for the specific language governing permissions
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * and limitations under the License.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow *
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * When distributing Covered Code, include this CDDL HEADER in each
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * If applicable, add the following below this CDDL HEADER, with the
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * fields enclosed by brackets "[]" replaced with your own identifying
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * information: Portions Copyright [yyyy] [name of copyright owner]
4bff34e37def8a90f9194d81bc345c52ba20086athurlow *
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * CDDL HEADER END
4bff34e37def8a90f9194d81bc345c52ba20086athurlow */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow/*
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * Use is subject to license terms.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow *
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * All rights reserved.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow#pragma ident "%Z%%M% %I% %E% SMI"
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow/*
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * A homegrown reader/writer lock implementation. It addresses
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * two requirements not addressed by the system primitives. They
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * are that the `enter" operation is optionally interruptible and
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * that that they can be re`enter'ed by writers without deadlock.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow *
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * All of this was borrowed from NFS.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * See: uts/common/fs/nfs/nfs_subr.c
4bff34e37def8a90f9194d81bc345c52ba20086athurlow *
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * XXX: Could we make this serve our needs instead?
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * See: uts/common/os/rwstlock.c
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * (and then use it for NFS too)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow#include <sys/param.h>
4bff34e37def8a90f9194d81bc345c52ba20086athurlow#include <sys/systm.h>
4bff34e37def8a90f9194d81bc345c52ba20086athurlow#include <sys/time.h>
4bff34e37def8a90f9194d81bc345c52ba20086athurlow#include <sys/vnode.h>
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow#include <smbfs/smbfs.h>
4bff34e37def8a90f9194d81bc345c52ba20086athurlow#include <smbfs/smbfs_node.h>
4bff34e37def8a90f9194d81bc345c52ba20086athurlow#include <smbfs/smbfs_subr.h>
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow/*
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * Only can return non-zero if intr != 0.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow */
4bff34e37def8a90f9194d81bc345c52ba20086athurlowint
4bff34e37def8a90f9194d81bc345c52ba20086athurlowsmbfs_rw_enter_sig(smbfs_rwlock_t *l, krw_t rw, int intr)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow{
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow mutex_enter(&l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow /*
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * If this is a nested enter, then allow it. There
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * must be as many exits as enters through.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (l->owner == curthread) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow /* lock is held for writing by current thread */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow ASSERT(rw == RW_READER || rw == RW_WRITER);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->count--;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow } else if (rw == RW_READER) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow /*
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * While there is a writer active or writers waiting,
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * then wait for them to finish up and move on. Then,
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * increment the count to indicate that a reader is
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * active.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow while (l->count < 0 || l->waiters > 0) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (intr) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow klwp_t *lwp = ttolwp(curthread);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (lwp != NULL)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow lwp->lwp_nostop++;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (!cv_wait_sig(&l->cv, &l->lock)) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (lwp != NULL)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow lwp->lwp_nostop--;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow mutex_exit(&l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow return (EINTR);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow }
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (lwp != NULL)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow lwp->lwp_nostop--;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow } else
4bff34e37def8a90f9194d81bc345c52ba20086athurlow cv_wait(&l->cv, &l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow }
4bff34e37def8a90f9194d81bc345c52ba20086athurlow ASSERT(l->count < INT_MAX);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow#ifdef SMBDEBUG
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if ((l->count % 10000) == 9999)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow cmn_err(CE_WARN, "smbfs_rw_enter_sig: count %d on"
4bff34e37def8a90f9194d81bc345c52ba20086athurlow "rwlock @ %p\n", l->count, (void *)&l);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow#endif
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->count++;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow } else {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow ASSERT(rw == RW_WRITER);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow /*
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * While there are readers active or a writer
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * active, then wait for all of the readers
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * to finish or for the writer to finish.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * Then, set the owner field to curthread and
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * decrement count to indicate that a writer
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * is active.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow while (l->count > 0 || l->owner != NULL) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->waiters++;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (intr) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow klwp_t *lwp = ttolwp(curthread);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (lwp != NULL)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow lwp->lwp_nostop++;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (!cv_wait_sig(&l->cv, &l->lock)) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (lwp != NULL)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow lwp->lwp_nostop--;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->waiters--;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow cv_broadcast(&l->cv);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow mutex_exit(&l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow return (EINTR);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow }
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (lwp != NULL)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow lwp->lwp_nostop--;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow } else
4bff34e37def8a90f9194d81bc345c52ba20086athurlow cv_wait(&l->cv, &l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->waiters--;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow }
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->owner = curthread;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->count--;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow }
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow mutex_exit(&l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow return (0);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow}
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow/*
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * If the lock is available, obtain it and return non-zero. If there is
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * already a conflicting lock, return 0 immediately.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlowint
4bff34e37def8a90f9194d81bc345c52ba20086athurlowsmbfs_rw_tryenter(smbfs_rwlock_t *l, krw_t rw)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow{
4bff34e37def8a90f9194d81bc345c52ba20086athurlow mutex_enter(&l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow /*
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * If this is a nested enter, then allow it. There
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * must be as many exits as enters through.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (l->owner == curthread) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow /* lock is held for writing by current thread */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow ASSERT(rw == RW_READER || rw == RW_WRITER);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->count--;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow } else if (rw == RW_READER) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow /*
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * If there is a writer active or writers waiting, deny the
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * lock. Otherwise, bump the count of readers.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (l->count < 0 || l->waiters > 0) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow mutex_exit(&l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow return (0);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow }
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->count++;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow } else {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow ASSERT(rw == RW_WRITER);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow /*
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * If there are readers active or a writer active, deny the
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * lock. Otherwise, set the owner field to curthread and
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * decrement count to indicate that a writer is active.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (l->count > 0 || l->owner != NULL) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow mutex_exit(&l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow return (0);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow }
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->owner = curthread;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->count--;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow }
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow mutex_exit(&l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow return (1);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow}
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlowvoid
4bff34e37def8a90f9194d81bc345c52ba20086athurlowsmbfs_rw_exit(smbfs_rwlock_t *l)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow{
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow mutex_enter(&l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow /*
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * If this is releasing a writer lock, then increment count to
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * indicate that there is one less writer active. If this was
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * the last of possibly nested writer locks, then clear the owner
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * field as well to indicate that there is no writer active
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * and wakeup any possible waiting writers or readers.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow *
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * If releasing a reader lock, then just decrement count to
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * indicate that there is one less reader active. If this was
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * the last active reader and there are writer(s) waiting,
4bff34e37def8a90f9194d81bc345c52ba20086athurlow * then wake up the first.
4bff34e37def8a90f9194d81bc345c52ba20086athurlow */
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (l->owner != NULL) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow ASSERT(l->owner == curthread);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->count++;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (l->count == 0) {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->owner = NULL;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow cv_broadcast(&l->cv);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow }
4bff34e37def8a90f9194d81bc345c52ba20086athurlow } else {
4bff34e37def8a90f9194d81bc345c52ba20086athurlow ASSERT(l->count > 0);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->count--;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (l->count == 0 && l->waiters > 0)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow cv_broadcast(&l->cv);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow }
4bff34e37def8a90f9194d81bc345c52ba20086athurlow mutex_exit(&l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow}
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlowint
4bff34e37def8a90f9194d81bc345c52ba20086athurlowsmbfs_rw_lock_held(smbfs_rwlock_t *l, krw_t rw)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow{
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow if (rw == RW_READER)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow return (l->count > 0);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow ASSERT(rw == RW_WRITER);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow return (l->count < 0);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow}
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow/* ARGSUSED */
4bff34e37def8a90f9194d81bc345c52ba20086athurlowvoid
4bff34e37def8a90f9194d81bc345c52ba20086athurlowsmbfs_rw_init(smbfs_rwlock_t *l, char *name, krw_type_t type, void *arg)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow{
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->count = 0;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->waiters = 0;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow l->owner = NULL;
4bff34e37def8a90f9194d81bc345c52ba20086athurlow mutex_init(&l->lock, NULL, MUTEX_DEFAULT, NULL);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow cv_init(&l->cv, NULL, CV_DEFAULT, NULL);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow}
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlowvoid
4bff34e37def8a90f9194d81bc345c52ba20086athurlowsmbfs_rw_destroy(smbfs_rwlock_t *l)
4bff34e37def8a90f9194d81bc345c52ba20086athurlow{
4bff34e37def8a90f9194d81bc345c52ba20086athurlow
4bff34e37def8a90f9194d81bc345c52ba20086athurlow mutex_destroy(&l->lock);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow cv_destroy(&l->cv);
4bff34e37def8a90f9194d81bc345c52ba20086athurlow}