1*4bff34e3Sthurlow /*
2*4bff34e3Sthurlow  * CDDL HEADER START
3*4bff34e3Sthurlow  *
4*4bff34e3Sthurlow  * The contents of this file are subject to the terms of the
5*4bff34e3Sthurlow  * Common Development and Distribution License (the "License").
6*4bff34e3Sthurlow  * You may not use this file except in compliance with the License.
7*4bff34e3Sthurlow  *
8*4bff34e3Sthurlow  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4bff34e3Sthurlow  * or http://www.opensolaris.org/os/licensing.
10*4bff34e3Sthurlow  * See the License for the specific language governing permissions
11*4bff34e3Sthurlow  * and limitations under the License.
12*4bff34e3Sthurlow  *
13*4bff34e3Sthurlow  * When distributing Covered Code, include this CDDL HEADER in each
14*4bff34e3Sthurlow  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4bff34e3Sthurlow  * If applicable, add the following below this CDDL HEADER, with the
16*4bff34e3Sthurlow  * fields enclosed by brackets "[]" replaced with your own identifying
17*4bff34e3Sthurlow  * information: Portions Copyright [yyyy] [name of copyright owner]
18*4bff34e3Sthurlow  *
19*4bff34e3Sthurlow  * CDDL HEADER END
20*4bff34e3Sthurlow  */
21*4bff34e3Sthurlow /*
22*4bff34e3Sthurlow  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*4bff34e3Sthurlow  * Use is subject to license terms.
24*4bff34e3Sthurlow  *
25*4bff34e3Sthurlow  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
26*4bff34e3Sthurlow  *	All rights reserved.
27*4bff34e3Sthurlow  */
28*4bff34e3Sthurlow 
29*4bff34e3Sthurlow /*
30*4bff34e3Sthurlow  * A homegrown reader/writer lock implementation.  It addresses
31*4bff34e3Sthurlow  * two requirements not addressed by the system primitives.  They
32*4bff34e3Sthurlow  * are that the `enter" operation is optionally interruptible and
33*4bff34e3Sthurlow  * that that they can be re`enter'ed by writers without deadlock.
34*4bff34e3Sthurlow  *
35*4bff34e3Sthurlow  * All of this was borrowed from NFS.
36*4bff34e3Sthurlow  * See: uts/common/fs/nfs/nfs_subr.c
37*4bff34e3Sthurlow  *
38*4bff34e3Sthurlow  * XXX: Could we make this serve our needs instead?
39*4bff34e3Sthurlow  * See: uts/common/os/rwstlock.c
40*4bff34e3Sthurlow  * (and then use it for NFS too)
41*4bff34e3Sthurlow  */
42*4bff34e3Sthurlow 
43*4bff34e3Sthurlow #include <sys/param.h>
44*4bff34e3Sthurlow #include <sys/systm.h>
45*4bff34e3Sthurlow #include <sys/time.h>
46*4bff34e3Sthurlow #include <sys/vnode.h>
47*4bff34e3Sthurlow 
48*4bff34e3Sthurlow #include <smbfs/smbfs.h>
49*4bff34e3Sthurlow #include <smbfs/smbfs_node.h>
50*4bff34e3Sthurlow #include <smbfs/smbfs_subr.h>
51*4bff34e3Sthurlow 
52*4bff34e3Sthurlow 
53*4bff34e3Sthurlow /*
54*4bff34e3Sthurlow  * Only can return non-zero if intr != 0.
55*4bff34e3Sthurlow  */
56*4bff34e3Sthurlow int
smbfs_rw_enter_sig(smbfs_rwlock_t * l,krw_t rw,int intr)57*4bff34e3Sthurlow smbfs_rw_enter_sig(smbfs_rwlock_t *l, krw_t rw, int intr)
58*4bff34e3Sthurlow {
59*4bff34e3Sthurlow 
60*4bff34e3Sthurlow 	mutex_enter(&l->lock);
61*4bff34e3Sthurlow 
62*4bff34e3Sthurlow 	/*
63*4bff34e3Sthurlow 	 * If this is a nested enter, then allow it.  There
64*4bff34e3Sthurlow 	 * must be as many exits as enters through.
65*4bff34e3Sthurlow 	 */
66*4bff34e3Sthurlow 	if (l->owner == curthread) {
67*4bff34e3Sthurlow 		/* lock is held for writing by current thread */
68*4bff34e3Sthurlow 		ASSERT(rw == RW_READER || rw == RW_WRITER);
69*4bff34e3Sthurlow 		l->count--;
70*4bff34e3Sthurlow 	} else if (rw == RW_READER) {
71*4bff34e3Sthurlow 		/*
72*4bff34e3Sthurlow 		 * While there is a writer active or writers waiting,
73*4bff34e3Sthurlow 		 * then wait for them to finish up and move on.  Then,
74*4bff34e3Sthurlow 		 * increment the count to indicate that a reader is
75*4bff34e3Sthurlow 		 * active.
76*4bff34e3Sthurlow 		 */
77*4bff34e3Sthurlow 		while (l->count < 0 || l->waiters > 0) {
78*4bff34e3Sthurlow 			if (intr) {
79*4bff34e3Sthurlow 				klwp_t *lwp = ttolwp(curthread);
80*4bff34e3Sthurlow 
81*4bff34e3Sthurlow 				if (lwp != NULL)
82*4bff34e3Sthurlow 					lwp->lwp_nostop++;
83*4bff34e3Sthurlow 				if (!cv_wait_sig(&l->cv, &l->lock)) {
84*4bff34e3Sthurlow 					if (lwp != NULL)
85*4bff34e3Sthurlow 						lwp->lwp_nostop--;
86*4bff34e3Sthurlow 					mutex_exit(&l->lock);
87*4bff34e3Sthurlow 					return (EINTR);
88*4bff34e3Sthurlow 				}
89*4bff34e3Sthurlow 				if (lwp != NULL)
90*4bff34e3Sthurlow 					lwp->lwp_nostop--;
91*4bff34e3Sthurlow 			} else
92*4bff34e3Sthurlow 				cv_wait(&l->cv, &l->lock);
93*4bff34e3Sthurlow 		}
94*4bff34e3Sthurlow 		ASSERT(l->count < INT_MAX);
95*4bff34e3Sthurlow #ifdef SMBDEBUG
96*4bff34e3Sthurlow 		if ((l->count % 10000) == 9999)
97*4bff34e3Sthurlow 			cmn_err(CE_WARN, "smbfs_rw_enter_sig: count %d on"
98*4bff34e3Sthurlow 			    "rwlock @ %p\n", l->count, (void *)&l);
99*4bff34e3Sthurlow #endif
100*4bff34e3Sthurlow 		l->count++;
101*4bff34e3Sthurlow 	} else {
102*4bff34e3Sthurlow 		ASSERT(rw == RW_WRITER);
103*4bff34e3Sthurlow 		/*
104*4bff34e3Sthurlow 		 * While there are readers active or a writer
105*4bff34e3Sthurlow 		 * active, then wait for all of the readers
106*4bff34e3Sthurlow 		 * to finish or for the writer to finish.
107*4bff34e3Sthurlow 		 * Then, set the owner field to curthread and
108*4bff34e3Sthurlow 		 * decrement count to indicate that a writer
109*4bff34e3Sthurlow 		 * is active.
110*4bff34e3Sthurlow 		 */
111*4bff34e3Sthurlow 		while (l->count > 0 || l->owner != NULL) {
112*4bff34e3Sthurlow 			l->waiters++;
113*4bff34e3Sthurlow 			if (intr) {
114*4bff34e3Sthurlow 				klwp_t *lwp = ttolwp(curthread);
115*4bff34e3Sthurlow 
116*4bff34e3Sthurlow 				if (lwp != NULL)
117*4bff34e3Sthurlow 					lwp->lwp_nostop++;
118*4bff34e3Sthurlow 				if (!cv_wait_sig(&l->cv, &l->lock)) {
119*4bff34e3Sthurlow 					if (lwp != NULL)
120*4bff34e3Sthurlow 						lwp->lwp_nostop--;
121*4bff34e3Sthurlow 					l->waiters--;
122*4bff34e3Sthurlow 					cv_broadcast(&l->cv);
123*4bff34e3Sthurlow 					mutex_exit(&l->lock);
124*4bff34e3Sthurlow 					return (EINTR);
125*4bff34e3Sthurlow 				}
126*4bff34e3Sthurlow 				if (lwp != NULL)
127*4bff34e3Sthurlow 					lwp->lwp_nostop--;
128*4bff34e3Sthurlow 			} else
129*4bff34e3Sthurlow 				cv_wait(&l->cv, &l->lock);
130*4bff34e3Sthurlow 			l->waiters--;
131*4bff34e3Sthurlow 		}
132*4bff34e3Sthurlow 		l->owner = curthread;
133*4bff34e3Sthurlow 		l->count--;
134*4bff34e3Sthurlow 	}
135*4bff34e3Sthurlow 
136*4bff34e3Sthurlow 	mutex_exit(&l->lock);
137*4bff34e3Sthurlow 
138*4bff34e3Sthurlow 	return (0);
139*4bff34e3Sthurlow }
140*4bff34e3Sthurlow 
141*4bff34e3Sthurlow /*
142*4bff34e3Sthurlow  * If the lock is available, obtain it and return non-zero.  If there is
143*4bff34e3Sthurlow  * already a conflicting lock, return 0 immediately.
144*4bff34e3Sthurlow  */
145*4bff34e3Sthurlow 
146*4bff34e3Sthurlow int
smbfs_rw_tryenter(smbfs_rwlock_t * l,krw_t rw)147*4bff34e3Sthurlow smbfs_rw_tryenter(smbfs_rwlock_t *l, krw_t rw)
148*4bff34e3Sthurlow {
149*4bff34e3Sthurlow 	mutex_enter(&l->lock);
150*4bff34e3Sthurlow 
151*4bff34e3Sthurlow 	/*
152*4bff34e3Sthurlow 	 * If this is a nested enter, then allow it.  There
153*4bff34e3Sthurlow 	 * must be as many exits as enters through.
154*4bff34e3Sthurlow 	 */
155*4bff34e3Sthurlow 	if (l->owner == curthread) {
156*4bff34e3Sthurlow 		/* lock is held for writing by current thread */
157*4bff34e3Sthurlow 		ASSERT(rw == RW_READER || rw == RW_WRITER);
158*4bff34e3Sthurlow 		l->count--;
159*4bff34e3Sthurlow 	} else if (rw == RW_READER) {
160*4bff34e3Sthurlow 		/*
161*4bff34e3Sthurlow 		 * If there is a writer active or writers waiting, deny the
162*4bff34e3Sthurlow 		 * lock.  Otherwise, bump the count of readers.
163*4bff34e3Sthurlow 		 */
164*4bff34e3Sthurlow 		if (l->count < 0 || l->waiters > 0) {
165*4bff34e3Sthurlow 			mutex_exit(&l->lock);
166*4bff34e3Sthurlow 			return (0);
167*4bff34e3Sthurlow 		}
168*4bff34e3Sthurlow 		l->count++;
169*4bff34e3Sthurlow 	} else {
170*4bff34e3Sthurlow 		ASSERT(rw == RW_WRITER);
171*4bff34e3Sthurlow 		/*
172*4bff34e3Sthurlow 		 * If there are readers active or a writer active, deny the
173*4bff34e3Sthurlow 		 * lock.  Otherwise, set the owner field to curthread and
174*4bff34e3Sthurlow 		 * decrement count to indicate that a writer is active.
175*4bff34e3Sthurlow 		 */
176*4bff34e3Sthurlow 		if (l->count > 0 || l->owner != NULL) {
177*4bff34e3Sthurlow 			mutex_exit(&l->lock);
178*4bff34e3Sthurlow 			return (0);
179*4bff34e3Sthurlow 		}
180*4bff34e3Sthurlow 		l->owner = curthread;
181*4bff34e3Sthurlow 		l->count--;
182*4bff34e3Sthurlow 	}
183*4bff34e3Sthurlow 
184*4bff34e3Sthurlow 	mutex_exit(&l->lock);
185*4bff34e3Sthurlow 
186*4bff34e3Sthurlow 	return (1);
187*4bff34e3Sthurlow }
188*4bff34e3Sthurlow 
189*4bff34e3Sthurlow void
smbfs_rw_exit(smbfs_rwlock_t * l)190*4bff34e3Sthurlow smbfs_rw_exit(smbfs_rwlock_t *l)
191*4bff34e3Sthurlow {
192*4bff34e3Sthurlow 
193*4bff34e3Sthurlow 	mutex_enter(&l->lock);
194*4bff34e3Sthurlow 	/*
195*4bff34e3Sthurlow 	 * If this is releasing a writer lock, then increment count to
196*4bff34e3Sthurlow 	 * indicate that there is one less writer active.  If this was
197*4bff34e3Sthurlow 	 * the last of possibly nested writer locks, then clear the owner
198*4bff34e3Sthurlow 	 * field as well to indicate that there is no writer active
199*4bff34e3Sthurlow 	 * and wakeup any possible waiting writers or readers.
200*4bff34e3Sthurlow 	 *
201*4bff34e3Sthurlow 	 * If releasing a reader lock, then just decrement count to
202*4bff34e3Sthurlow 	 * indicate that there is one less reader active.  If this was
203*4bff34e3Sthurlow 	 * the last active reader and there are writer(s) waiting,
204*4bff34e3Sthurlow 	 * then wake up the first.
205*4bff34e3Sthurlow 	 */
206*4bff34e3Sthurlow 	if (l->owner != NULL) {
207*4bff34e3Sthurlow 		ASSERT(l->owner == curthread);
208*4bff34e3Sthurlow 		l->count++;
209*4bff34e3Sthurlow 		if (l->count == 0) {
210*4bff34e3Sthurlow 			l->owner = NULL;
211*4bff34e3Sthurlow 			cv_broadcast(&l->cv);
212*4bff34e3Sthurlow 		}
213*4bff34e3Sthurlow 	} else {
214*4bff34e3Sthurlow 		ASSERT(l->count > 0);
215*4bff34e3Sthurlow 		l->count--;
216*4bff34e3Sthurlow 		if (l->count == 0 && l->waiters > 0)
217*4bff34e3Sthurlow 			cv_broadcast(&l->cv);
218*4bff34e3Sthurlow 	}
219*4bff34e3Sthurlow 	mutex_exit(&l->lock);
220*4bff34e3Sthurlow }
221*4bff34e3Sthurlow 
222*4bff34e3Sthurlow int
smbfs_rw_lock_held(smbfs_rwlock_t * l,krw_t rw)223*4bff34e3Sthurlow smbfs_rw_lock_held(smbfs_rwlock_t *l, krw_t rw)
224*4bff34e3Sthurlow {
225*4bff34e3Sthurlow 
226*4bff34e3Sthurlow 	if (rw == RW_READER)
227*4bff34e3Sthurlow 		return (l->count > 0);
228*4bff34e3Sthurlow 	ASSERT(rw == RW_WRITER);
229*4bff34e3Sthurlow 	return (l->count < 0);
230*4bff34e3Sthurlow }
231*4bff34e3Sthurlow 
232*4bff34e3Sthurlow /* ARGSUSED */
233*4bff34e3Sthurlow void
smbfs_rw_init(smbfs_rwlock_t * l,char * name,krw_type_t type,void * arg)234*4bff34e3Sthurlow smbfs_rw_init(smbfs_rwlock_t *l, char *name, krw_type_t type, void *arg)
235*4bff34e3Sthurlow {
236*4bff34e3Sthurlow 
237*4bff34e3Sthurlow 	l->count = 0;
238*4bff34e3Sthurlow 	l->waiters = 0;
239*4bff34e3Sthurlow 	l->owner = NULL;
240*4bff34e3Sthurlow 	mutex_init(&l->lock, NULL, MUTEX_DEFAULT, NULL);
241*4bff34e3Sthurlow 	cv_init(&l->cv, NULL, CV_DEFAULT, NULL);
242*4bff34e3Sthurlow }
243*4bff34e3Sthurlow 
244*4bff34e3Sthurlow void
smbfs_rw_destroy(smbfs_rwlock_t * l)245*4bff34e3Sthurlow smbfs_rw_destroy(smbfs_rwlock_t *l)
246*4bff34e3Sthurlow {
247*4bff34e3Sthurlow 
248*4bff34e3Sthurlow 	mutex_destroy(&l->lock);
249*4bff34e3Sthurlow 	cv_destroy(&l->cv);
250*4bff34e3Sthurlow }
251