xref: /onnv-gate/usr/src/uts/common/os/share.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 1996-1998,2001,2003 Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  * Use is subject to license terms.
26*0Sstevel@tonic-gate  */
27*0Sstevel@tonic-gate 
28*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate #include <sys/types.h>
31*0Sstevel@tonic-gate #include <sys/sysmacros.h>
32*0Sstevel@tonic-gate #include <sys/param.h>
33*0Sstevel@tonic-gate #include <sys/systm.h>
34*0Sstevel@tonic-gate #include <sys/fcntl.h>
35*0Sstevel@tonic-gate #include <sys/vfs.h>
36*0Sstevel@tonic-gate #include <sys/vnode.h>
37*0Sstevel@tonic-gate #include <sys/share.h>
38*0Sstevel@tonic-gate #include <sys/cmn_err.h>
39*0Sstevel@tonic-gate #include <sys/kmem.h>
40*0Sstevel@tonic-gate #include <sys/debug.h>
41*0Sstevel@tonic-gate #include <sys/t_lock.h>
42*0Sstevel@tonic-gate #include <sys/errno.h>
43*0Sstevel@tonic-gate #include <sys/nbmlock.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate int share_debug = 0;
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate #ifdef DEBUG
48*0Sstevel@tonic-gate static void print_shares(struct vnode *);
49*0Sstevel@tonic-gate static void print_share(struct shrlock *);
50*0Sstevel@tonic-gate #endif
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate static int isreadonly(struct vnode *);
53*0Sstevel@tonic-gate static int lock_blocks_share(struct vnode *, struct shrlock *);
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate /*
56*0Sstevel@tonic-gate  * Add the share reservation shr to vp.
57*0Sstevel@tonic-gate  */
58*0Sstevel@tonic-gate int
59*0Sstevel@tonic-gate add_share(struct vnode *vp, struct shrlock *shr)
60*0Sstevel@tonic-gate {
61*0Sstevel@tonic-gate 	struct shrlocklist *shrl;
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate 	/*
64*0Sstevel@tonic-gate 	 * An access of zero is not legal, however some older clients
65*0Sstevel@tonic-gate 	 * generate it anyways.  Allow the request only if it is
66*0Sstevel@tonic-gate 	 * coming from a remote system.  Be generous in what you
67*0Sstevel@tonic-gate 	 * accept and strict in what you send.
68*0Sstevel@tonic-gate 	 */
69*0Sstevel@tonic-gate 	if ((shr->s_access == 0) && (GETSYSID(shr->s_sysid) == 0)) {
70*0Sstevel@tonic-gate 		return (EINVAL);
71*0Sstevel@tonic-gate 	}
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	/*
74*0Sstevel@tonic-gate 	 * Sanity check to make sure we have valid options.
75*0Sstevel@tonic-gate 	 * There is known overlap but it doesn't hurt to be careful.
76*0Sstevel@tonic-gate 	 */
77*0Sstevel@tonic-gate 	if (shr->s_access & ~(F_RDACC|F_WRACC|F_RWACC)) {
78*0Sstevel@tonic-gate 		return (EINVAL);
79*0Sstevel@tonic-gate 	}
80*0Sstevel@tonic-gate 	if (shr->s_deny & ~(F_NODNY|F_RDDNY|F_WRDNY|F_RWDNY|F_COMPAT|
81*0Sstevel@tonic-gate 	    F_MANDDNY)) {
82*0Sstevel@tonic-gate 		return (EINVAL);
83*0Sstevel@tonic-gate 	}
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	/*
86*0Sstevel@tonic-gate 	 * If the caller wants non-blocking mandatory semantics, make sure
87*0Sstevel@tonic-gate 	 * that there isn't already a conflicting lock.
88*0Sstevel@tonic-gate 	 */
89*0Sstevel@tonic-gate 	if (shr->s_deny & F_MANDDNY) {
90*0Sstevel@tonic-gate 		ASSERT(nbl_in_crit(vp));
91*0Sstevel@tonic-gate 		if (lock_blocks_share(vp, shr)) {
92*0Sstevel@tonic-gate 			return (EAGAIN);
93*0Sstevel@tonic-gate 		}
94*0Sstevel@tonic-gate 	}
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
97*0Sstevel@tonic-gate 	for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
98*0Sstevel@tonic-gate 		/*
99*0Sstevel@tonic-gate 		 * If the share owner matches previous request
100*0Sstevel@tonic-gate 		 * do special handling.
101*0Sstevel@tonic-gate 		 */
102*0Sstevel@tonic-gate 		if ((shrl->shr->s_sysid == shr->s_sysid) &&
103*0Sstevel@tonic-gate 		    (shrl->shr->s_pid == shr->s_pid) &&
104*0Sstevel@tonic-gate 		    (shrl->shr->s_own_len == shr->s_own_len) &&
105*0Sstevel@tonic-gate 		    bcmp(shrl->shr->s_owner, shr->s_owner,
106*0Sstevel@tonic-gate 		    shr->s_own_len) == 0) {
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate 			/*
109*0Sstevel@tonic-gate 			 * If the existing request is F_COMPAT and
110*0Sstevel@tonic-gate 			 * is the first share then allow any F_COMPAT
111*0Sstevel@tonic-gate 			 * from the same process.  Trick:  If the existing
112*0Sstevel@tonic-gate 			 * F_COMPAT is write access then it must have
113*0Sstevel@tonic-gate 			 * the same owner as the first.
114*0Sstevel@tonic-gate 			 */
115*0Sstevel@tonic-gate 			if ((shrl->shr->s_deny & F_COMPAT) &&
116*0Sstevel@tonic-gate 			    (shr->s_deny & F_COMPAT) &&
117*0Sstevel@tonic-gate 			    ((shrl->next == NULL) ||
118*0Sstevel@tonic-gate 				(shrl->shr->s_access & F_WRACC)))
119*0Sstevel@tonic-gate 				break;
120*0Sstevel@tonic-gate 		}
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 		/*
123*0Sstevel@tonic-gate 		 * If a first share has been done in compatibility mode
124*0Sstevel@tonic-gate 		 * handle the special cases.
125*0Sstevel@tonic-gate 		 */
126*0Sstevel@tonic-gate 		if ((shrl->shr->s_deny & F_COMPAT) && (shrl->next == NULL)) {
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 			if (!(shr->s_deny & F_COMPAT)) {
129*0Sstevel@tonic-gate 				/*
130*0Sstevel@tonic-gate 				 * If not compat and want write access or
131*0Sstevel@tonic-gate 				 * want to deny read or
132*0Sstevel@tonic-gate 				 * write exists, fails
133*0Sstevel@tonic-gate 				 */
134*0Sstevel@tonic-gate 				if ((shr->s_access & F_WRACC) ||
135*0Sstevel@tonic-gate 				    (shr->s_deny & F_RDDNY) ||
136*0Sstevel@tonic-gate 				    (shrl->shr->s_access & F_WRACC)) {
137*0Sstevel@tonic-gate 					mutex_exit(&vp->v_lock);
138*0Sstevel@tonic-gate 					return (EAGAIN);
139*0Sstevel@tonic-gate 				}
140*0Sstevel@tonic-gate 				/*
141*0Sstevel@tonic-gate 				 * If read only file allow, this may allow
142*0Sstevel@tonic-gate 				 * a deny write but that is meaningless on
143*0Sstevel@tonic-gate 				 * a read only file.
144*0Sstevel@tonic-gate 				 */
145*0Sstevel@tonic-gate 				if (isreadonly(vp))
146*0Sstevel@tonic-gate 					break;
147*0Sstevel@tonic-gate 				mutex_exit(&vp->v_lock);
148*0Sstevel@tonic-gate 				return (EAGAIN);
149*0Sstevel@tonic-gate 			}
150*0Sstevel@tonic-gate 			/*
151*0Sstevel@tonic-gate 			 * This is a compat request and read access
152*0Sstevel@tonic-gate 			 * and the first was also read access
153*0Sstevel@tonic-gate 			 * we always allow it, otherwise we reject because
154*0Sstevel@tonic-gate 			 * we have handled the only valid write case above.
155*0Sstevel@tonic-gate 			 */
156*0Sstevel@tonic-gate 			if ((shr->s_access == F_RDACC) &&
157*0Sstevel@tonic-gate 			    (shrl->shr->s_access == F_RDACC))
158*0Sstevel@tonic-gate 				break;
159*0Sstevel@tonic-gate 			mutex_exit(&vp->v_lock);
160*0Sstevel@tonic-gate 			return (EAGAIN);
161*0Sstevel@tonic-gate 		}
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 		/*
164*0Sstevel@tonic-gate 		 * If we are trying to share in compatibility mode
165*0Sstevel@tonic-gate 		 * and the current share is compat (and not the first)
166*0Sstevel@tonic-gate 		 * we don't know enough.
167*0Sstevel@tonic-gate 		 */
168*0Sstevel@tonic-gate 		if ((shrl->shr->s_deny & F_COMPAT) && (shr->s_deny & F_COMPAT))
169*0Sstevel@tonic-gate 			continue;
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 		/*
172*0Sstevel@tonic-gate 		 * If this is a compat we check for what can't succeed.
173*0Sstevel@tonic-gate 		 */
174*0Sstevel@tonic-gate 		if (shr->s_deny & F_COMPAT) {
175*0Sstevel@tonic-gate 			/*
176*0Sstevel@tonic-gate 			 * If we want write access or
177*0Sstevel@tonic-gate 			 * if anyone is denying read or
178*0Sstevel@tonic-gate 			 * if anyone has write access we fail
179*0Sstevel@tonic-gate 			 */
180*0Sstevel@tonic-gate 			if ((shr->s_access & F_WRACC) ||
181*0Sstevel@tonic-gate 			    (shrl->shr->s_deny & F_RDDNY) ||
182*0Sstevel@tonic-gate 			    (shrl->shr->s_access & F_WRACC)) {
183*0Sstevel@tonic-gate 				mutex_exit(&vp->v_lock);
184*0Sstevel@tonic-gate 				return (EAGAIN);
185*0Sstevel@tonic-gate 			}
186*0Sstevel@tonic-gate 			/*
187*0Sstevel@tonic-gate 			 * If the first was opened with only read access
188*0Sstevel@tonic-gate 			 * and is a read only file we allow.
189*0Sstevel@tonic-gate 			 */
190*0Sstevel@tonic-gate 			if (shrl->next == NULL) {
191*0Sstevel@tonic-gate 				if ((shrl->shr->s_access == F_RDACC) &&
192*0Sstevel@tonic-gate 				    isreadonly(vp)) {
193*0Sstevel@tonic-gate 					break;
194*0Sstevel@tonic-gate 				}
195*0Sstevel@tonic-gate 				mutex_exit(&vp->v_lock);
196*0Sstevel@tonic-gate 				return (EAGAIN);
197*0Sstevel@tonic-gate 			}
198*0Sstevel@tonic-gate 			/*
199*0Sstevel@tonic-gate 			 * We still can't determine our fate so continue
200*0Sstevel@tonic-gate 			 */
201*0Sstevel@tonic-gate 			continue;
202*0Sstevel@tonic-gate 		}
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 		/*
205*0Sstevel@tonic-gate 		 * Simple bitwise test, if we are trying to access what
206*0Sstevel@tonic-gate 		 * someone else is denying or we are trying to deny
207*0Sstevel@tonic-gate 		 * what someone else is accessing we fail.
208*0Sstevel@tonic-gate 		 */
209*0Sstevel@tonic-gate 		if ((shr->s_access & shrl->shr->s_deny) ||
210*0Sstevel@tonic-gate 		    (shr->s_deny & shrl->shr->s_access)) {
211*0Sstevel@tonic-gate 			mutex_exit(&vp->v_lock);
212*0Sstevel@tonic-gate 			return (EAGAIN);
213*0Sstevel@tonic-gate 		}
214*0Sstevel@tonic-gate 	}
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	shrl = kmem_alloc(sizeof (struct shrlocklist), KM_SLEEP);
217*0Sstevel@tonic-gate 	shrl->shr = kmem_alloc(sizeof (struct shrlock), KM_SLEEP);
218*0Sstevel@tonic-gate 	shrl->shr->s_access = shr->s_access;
219*0Sstevel@tonic-gate 	shrl->shr->s_deny = shr->s_deny;
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	/*
222*0Sstevel@tonic-gate 	 * Make sure no other deny modes are also set with F_COMPAT
223*0Sstevel@tonic-gate 	 */
224*0Sstevel@tonic-gate 	if (shrl->shr->s_deny & F_COMPAT)
225*0Sstevel@tonic-gate 		shrl->shr->s_deny = F_COMPAT;
226*0Sstevel@tonic-gate 	shrl->shr->s_sysid = shr->s_sysid;		/* XXX ref cnt? */
227*0Sstevel@tonic-gate 	shrl->shr->s_pid = shr->s_pid;
228*0Sstevel@tonic-gate 	shrl->shr->s_own_len = shr->s_own_len;
229*0Sstevel@tonic-gate 	shrl->shr->s_owner = kmem_alloc(shr->s_own_len, KM_SLEEP);
230*0Sstevel@tonic-gate 	bcopy(shr->s_owner, shrl->shr->s_owner, shr->s_own_len);
231*0Sstevel@tonic-gate 	shrl->next = vp->v_shrlocks;
232*0Sstevel@tonic-gate 	vp->v_shrlocks = shrl;
233*0Sstevel@tonic-gate #ifdef DEBUG
234*0Sstevel@tonic-gate 	if (share_debug)
235*0Sstevel@tonic-gate 		print_shares(vp);
236*0Sstevel@tonic-gate #endif
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	return (0);
241*0Sstevel@tonic-gate }
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate /*
244*0Sstevel@tonic-gate  *	nlmid	sysid	pid
245*0Sstevel@tonic-gate  *	=====	=====	===
246*0Sstevel@tonic-gate  *	!=0	!=0	=0	in cluster; NLM lock
247*0Sstevel@tonic-gate  *	!=0	=0	=0	in cluster; special case for NLM lock
248*0Sstevel@tonic-gate  *	!=0	=0	!=0	in cluster; PXFS local lock
249*0Sstevel@tonic-gate  *	!=0	!=0	!=0	cannot happen
250*0Sstevel@tonic-gate  *	=0	!=0	=0	not in cluster; NLM lock
251*0Sstevel@tonic-gate  *	=0	=0	!=0	not in cluster; local lock
252*0Sstevel@tonic-gate  *	=0	=0	=0	cannot happen
253*0Sstevel@tonic-gate  *	=0	!=0	!=0	cannot happen
254*0Sstevel@tonic-gate  */
255*0Sstevel@tonic-gate static int
256*0Sstevel@tonic-gate is_match_for_del(struct shrlock *shr, struct shrlock *element)
257*0Sstevel@tonic-gate {
258*0Sstevel@tonic-gate 	int nlmid1, nlmid2;
259*0Sstevel@tonic-gate 	int result = 0;
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	nlmid1 = GETNLMID(shr->s_sysid);
262*0Sstevel@tonic-gate 	nlmid2 = GETNLMID(element->s_sysid);
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 	if (nlmid1 != 0) {		/* in a cluster */
265*0Sstevel@tonic-gate 		if (GETSYSID(shr->s_sysid) != 0 && shr->s_pid == 0) {
266*0Sstevel@tonic-gate 			/*
267*0Sstevel@tonic-gate 			 * Lock obtained through nlm server.  Just need to
268*0Sstevel@tonic-gate 			 * compare whole sysids.  pid will always = 0.
269*0Sstevel@tonic-gate 			 */
270*0Sstevel@tonic-gate 			result = shr->s_sysid == element->s_sysid;
271*0Sstevel@tonic-gate 		} else if (GETSYSID(shr->s_sysid) == 0 && shr->s_pid == 0) {
272*0Sstevel@tonic-gate 			/*
273*0Sstevel@tonic-gate 			 * This is a special case.  The NLM server wishes to
274*0Sstevel@tonic-gate 			 * delete all share locks obtained through nlmid1.
275*0Sstevel@tonic-gate 			 */
276*0Sstevel@tonic-gate 			result = (nlmid1 == nlmid2);
277*0Sstevel@tonic-gate 		} else if (GETSYSID(shr->s_sysid) == 0 && shr->s_pid != 0) {
278*0Sstevel@tonic-gate 			/*
279*0Sstevel@tonic-gate 			 * Lock obtained locally through PXFS.  Match nlmids
280*0Sstevel@tonic-gate 			 * and pids.
281*0Sstevel@tonic-gate 			 */
282*0Sstevel@tonic-gate 			result = (nlmid1 == nlmid2 &&
283*0Sstevel@tonic-gate 				shr->s_pid == element->s_pid);
284*0Sstevel@tonic-gate 		}
285*0Sstevel@tonic-gate 	} else {			/* not in a cluster */
286*0Sstevel@tonic-gate 		result = ((shr->s_sysid == 0 &&
287*0Sstevel@tonic-gate 			shr->s_pid == element->s_pid) ||
288*0Sstevel@tonic-gate 			(shr->s_sysid != 0 &&
289*0Sstevel@tonic-gate 				shr->s_sysid == element->s_sysid));
290*0Sstevel@tonic-gate 	}
291*0Sstevel@tonic-gate 	return (result);
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate /*
295*0Sstevel@tonic-gate  * Delete the given share reservation.  Returns 0 if okay, EINVAL if the
296*0Sstevel@tonic-gate  * share could not be found.  If the share reservation is an NBMAND share
297*0Sstevel@tonic-gate  * reservation, signal anyone waiting for the share to go away (e.g.,
298*0Sstevel@tonic-gate  * blocking lock requests).
299*0Sstevel@tonic-gate  */
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate int
302*0Sstevel@tonic-gate del_share(struct vnode *vp, struct shrlock *shr)
303*0Sstevel@tonic-gate {
304*0Sstevel@tonic-gate 	struct shrlocklist *shrl;
305*0Sstevel@tonic-gate 	struct shrlocklist **shrlp;
306*0Sstevel@tonic-gate 	int found = 0;
307*0Sstevel@tonic-gate 	int is_nbmand = 0;
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
310*0Sstevel@tonic-gate 	/*
311*0Sstevel@tonic-gate 	 * Delete the shares with the matching sysid and owner
312*0Sstevel@tonic-gate 	 * But if own_len == 0 and sysid == 0 delete all with matching pid
313*0Sstevel@tonic-gate 	 * But if own_len == 0 delete all with matching sysid.
314*0Sstevel@tonic-gate 	 */
315*0Sstevel@tonic-gate 	shrlp = &vp->v_shrlocks;
316*0Sstevel@tonic-gate 	while (*shrlp) {
317*0Sstevel@tonic-gate 		if ((shr->s_own_len == (*shrlp)->shr->s_own_len &&
318*0Sstevel@tonic-gate 				    (bcmp(shr->s_owner, (*shrlp)->shr->s_owner,
319*0Sstevel@tonic-gate 						shr->s_own_len) == 0)) ||
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 			(shr->s_own_len == 0 &&
322*0Sstevel@tonic-gate 				is_match_for_del(shr, (*shrlp)->shr))) {
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 			shrl = *shrlp;
325*0Sstevel@tonic-gate 			*shrlp = shrl->next;
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 			if (shrl->shr->s_deny & F_MANDDNY)
328*0Sstevel@tonic-gate 				is_nbmand = 1;
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 			/* XXX deref sysid */
331*0Sstevel@tonic-gate 			kmem_free(shrl->shr->s_owner, shrl->shr->s_own_len);
332*0Sstevel@tonic-gate 			kmem_free(shrl->shr, sizeof (struct shrlock));
333*0Sstevel@tonic-gate 			kmem_free(shrl, sizeof (struct shrlocklist));
334*0Sstevel@tonic-gate 			found++;
335*0Sstevel@tonic-gate 			continue;
336*0Sstevel@tonic-gate 		}
337*0Sstevel@tonic-gate 		shrlp = &(*shrlp)->next;
338*0Sstevel@tonic-gate 	}
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	if (is_nbmand)
341*0Sstevel@tonic-gate 		cv_broadcast(&vp->v_cv);
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
344*0Sstevel@tonic-gate 	return (found ? 0 : EINVAL);
345*0Sstevel@tonic-gate }
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate /*
348*0Sstevel@tonic-gate  * Clean up all local share reservations that the given process has with
349*0Sstevel@tonic-gate  * the given file.
350*0Sstevel@tonic-gate  */
351*0Sstevel@tonic-gate void
352*0Sstevel@tonic-gate cleanshares(struct vnode *vp, pid_t pid)
353*0Sstevel@tonic-gate {
354*0Sstevel@tonic-gate 	struct shrlock shr;
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 	if (vp->v_shrlocks == NULL)
357*0Sstevel@tonic-gate 		return;
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	shr.s_access = 0;
360*0Sstevel@tonic-gate 	shr.s_deny = 0;
361*0Sstevel@tonic-gate 	shr.s_pid = pid;
362*0Sstevel@tonic-gate 	shr.s_sysid = 0;
363*0Sstevel@tonic-gate 	shr.s_own_len = 0;
364*0Sstevel@tonic-gate 	shr.s_owner = NULL;
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	(void) del_share(vp, &shr);
367*0Sstevel@tonic-gate }
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate static int
370*0Sstevel@tonic-gate is_match_for_has_remote(int32_t sysid1, int32_t sysid2)
371*0Sstevel@tonic-gate {
372*0Sstevel@tonic-gate 	int result = 0;
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 	if (GETNLMID(sysid1) != 0) { /* in a cluster */
375*0Sstevel@tonic-gate 		if (GETSYSID(sysid1) != 0) {
376*0Sstevel@tonic-gate 			/*
377*0Sstevel@tonic-gate 			 * Lock obtained through nlm server.  Just need to
378*0Sstevel@tonic-gate 			 * compare whole sysids.
379*0Sstevel@tonic-gate 			 */
380*0Sstevel@tonic-gate 			result = (sysid1 == sysid2);
381*0Sstevel@tonic-gate 		} else if (GETSYSID(sysid1) == 0) {
382*0Sstevel@tonic-gate 			/*
383*0Sstevel@tonic-gate 			 * This is a special case.  The NLM server identified
384*0Sstevel@tonic-gate 			 * by nlmid1 wishes to find out if it has obtained
385*0Sstevel@tonic-gate 			 * any share locks on the vnode.
386*0Sstevel@tonic-gate 			 */
387*0Sstevel@tonic-gate 			result = (GETNLMID(sysid1) == GETNLMID(sysid2));
388*0Sstevel@tonic-gate 		}
389*0Sstevel@tonic-gate 	} else {			/* not in a cluster */
390*0Sstevel@tonic-gate 		result = ((sysid1 != 0 && sysid1 == sysid2) ||
391*0Sstevel@tonic-gate 		    (sysid1 == 0 && sysid2 != 0));
392*0Sstevel@tonic-gate 	}
393*0Sstevel@tonic-gate 	return (result);
394*0Sstevel@tonic-gate }
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate /*
398*0Sstevel@tonic-gate  * Determine whether there are any shares for the given vnode
399*0Sstevel@tonic-gate  * with a remote sysid. Returns zero if not, non-zero if there are.
400*0Sstevel@tonic-gate  * If sysid is non-zero then determine if this sysid has a share.
401*0Sstevel@tonic-gate  *
402*0Sstevel@tonic-gate  * Note that the return value from this function is potentially invalid
403*0Sstevel@tonic-gate  * once it has been returned.  The caller is responsible for providing its
404*0Sstevel@tonic-gate  * own synchronization mechanism to ensure that the return value is useful.
405*0Sstevel@tonic-gate  */
406*0Sstevel@tonic-gate int
407*0Sstevel@tonic-gate shr_has_remote_shares(vnode_t *vp, int32_t sysid)
408*0Sstevel@tonic-gate {
409*0Sstevel@tonic-gate 	struct shrlocklist *shrl;
410*0Sstevel@tonic-gate 	int result = 0;
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
413*0Sstevel@tonic-gate 	shrl = vp->v_shrlocks;
414*0Sstevel@tonic-gate 	while (shrl) {
415*0Sstevel@tonic-gate 		if (is_match_for_has_remote(sysid, shrl->shr->s_sysid)) {
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 			result = 1;
418*0Sstevel@tonic-gate 			break;
419*0Sstevel@tonic-gate 		}
420*0Sstevel@tonic-gate 		shrl = shrl->next;
421*0Sstevel@tonic-gate 	}
422*0Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
423*0Sstevel@tonic-gate 	return (result);
424*0Sstevel@tonic-gate }
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate static int
427*0Sstevel@tonic-gate isreadonly(struct vnode *vp)
428*0Sstevel@tonic-gate {
429*0Sstevel@tonic-gate 	return (vp->v_type != VCHR && vp->v_type != VBLK &&
430*0Sstevel@tonic-gate 		vp->v_type != VFIFO && vn_is_readonly(vp));
431*0Sstevel@tonic-gate }
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate #ifdef DEBUG
434*0Sstevel@tonic-gate static void
435*0Sstevel@tonic-gate print_shares(struct vnode *vp)
436*0Sstevel@tonic-gate {
437*0Sstevel@tonic-gate 	struct shrlocklist *shrl;
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	if (vp->v_shrlocks == NULL) {
440*0Sstevel@tonic-gate 		printf("<NULL>\n");
441*0Sstevel@tonic-gate 		return;
442*0Sstevel@tonic-gate 	}
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate 	shrl = vp->v_shrlocks;
445*0Sstevel@tonic-gate 	while (shrl) {
446*0Sstevel@tonic-gate 		print_share(shrl->shr);
447*0Sstevel@tonic-gate 		shrl = shrl->next;
448*0Sstevel@tonic-gate 	}
449*0Sstevel@tonic-gate }
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate static void
452*0Sstevel@tonic-gate print_share(struct shrlock *shr)
453*0Sstevel@tonic-gate {
454*0Sstevel@tonic-gate 	int i;
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	if (shr == NULL) {
457*0Sstevel@tonic-gate 		printf("<NULL>\n");
458*0Sstevel@tonic-gate 		return;
459*0Sstevel@tonic-gate 	}
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 	printf("    access(%d):	", shr->s_access);
462*0Sstevel@tonic-gate 	if (shr->s_access & F_RDACC)
463*0Sstevel@tonic-gate 		printf("R");
464*0Sstevel@tonic-gate 	if (shr->s_access & F_WRACC)
465*0Sstevel@tonic-gate 		printf("W");
466*0Sstevel@tonic-gate 	if ((shr->s_access & (F_RDACC|F_WRACC)) == 0)
467*0Sstevel@tonic-gate 		printf("N");
468*0Sstevel@tonic-gate 	printf("\n");
469*0Sstevel@tonic-gate 	printf("    deny:	");
470*0Sstevel@tonic-gate 	if (shr->s_deny & F_COMPAT)
471*0Sstevel@tonic-gate 		printf("C");
472*0Sstevel@tonic-gate 	if (shr->s_deny & F_RDDNY)
473*0Sstevel@tonic-gate 		printf("R");
474*0Sstevel@tonic-gate 	if (shr->s_deny & F_WRDNY)
475*0Sstevel@tonic-gate 		printf("W");
476*0Sstevel@tonic-gate 	if (shr->s_deny == F_NODNY)
477*0Sstevel@tonic-gate 		printf("N");
478*0Sstevel@tonic-gate 	printf("\n");
479*0Sstevel@tonic-gate 	printf("    sysid:	%d\n", shr->s_sysid);
480*0Sstevel@tonic-gate 	printf("    pid:	%d\n", shr->s_pid);
481*0Sstevel@tonic-gate 	printf("    owner:	[%d]", shr->s_own_len);
482*0Sstevel@tonic-gate 	printf("'");
483*0Sstevel@tonic-gate 	for (i = 0; i < shr->s_own_len; i++)
484*0Sstevel@tonic-gate 		printf("%02x", (unsigned)shr->s_owner[i]);
485*0Sstevel@tonic-gate 	printf("'\n");
486*0Sstevel@tonic-gate }
487*0Sstevel@tonic-gate #endif
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate /*
490*0Sstevel@tonic-gate  * Return non-zero if the given I/O request conflicts with a registered
491*0Sstevel@tonic-gate  * share reservation.
492*0Sstevel@tonic-gate  */
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate int
495*0Sstevel@tonic-gate nbl_share_conflict(vnode_t *vp, nbl_op_t op)
496*0Sstevel@tonic-gate {
497*0Sstevel@tonic-gate 	struct shrlocklist *shrl;
498*0Sstevel@tonic-gate 	int conflict = 0;
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	ASSERT(nbl_in_crit(vp));
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
503*0Sstevel@tonic-gate 	for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
504*0Sstevel@tonic-gate 		if (shrl->shr->s_sysid == 0 &&
505*0Sstevel@tonic-gate 		    (shrl->shr->s_deny & F_MANDDNY) &&
506*0Sstevel@tonic-gate 		    shrl->shr->s_pid != curproc->p_pid) {
507*0Sstevel@tonic-gate 			switch (op) {
508*0Sstevel@tonic-gate 			case NBL_READ:
509*0Sstevel@tonic-gate 				if (shrl->shr->s_deny & F_RDDNY)
510*0Sstevel@tonic-gate 					conflict = 1;
511*0Sstevel@tonic-gate 				break;
512*0Sstevel@tonic-gate 			case NBL_WRITE:
513*0Sstevel@tonic-gate 				if (shrl->shr->s_deny & F_WRDNY)
514*0Sstevel@tonic-gate 					conflict = 1;
515*0Sstevel@tonic-gate 				break;
516*0Sstevel@tonic-gate 			case NBL_READWRITE:
517*0Sstevel@tonic-gate 				if (shrl->shr->s_deny & F_RWDNY)
518*0Sstevel@tonic-gate 					conflict = 1;
519*0Sstevel@tonic-gate 				break;
520*0Sstevel@tonic-gate 			case NBL_RENAME:
521*0Sstevel@tonic-gate 			case NBL_REMOVE:
522*0Sstevel@tonic-gate 				conflict = 1;
523*0Sstevel@tonic-gate 				break;
524*0Sstevel@tonic-gate #ifdef DEBUG
525*0Sstevel@tonic-gate 			default:
526*0Sstevel@tonic-gate 				cmn_err(CE_PANIC,
527*0Sstevel@tonic-gate 					"nbl_share_conflict: bogus op (%d)",
528*0Sstevel@tonic-gate 					op);
529*0Sstevel@tonic-gate 				break;
530*0Sstevel@tonic-gate #endif
531*0Sstevel@tonic-gate 			}
532*0Sstevel@tonic-gate 		}
533*0Sstevel@tonic-gate 		if (conflict)
534*0Sstevel@tonic-gate 			break;
535*0Sstevel@tonic-gate 	}
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
538*0Sstevel@tonic-gate 	return (conflict);
539*0Sstevel@tonic-gate }
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate /*
542*0Sstevel@tonic-gate  * Return non-zero if the given lock request conflicts with an existing
543*0Sstevel@tonic-gate  * non-blocking mandatory share reservation.
544*0Sstevel@tonic-gate  */
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate int
547*0Sstevel@tonic-gate share_blocks_lock(vnode_t *vp, flock64_t *flkp)
548*0Sstevel@tonic-gate {
549*0Sstevel@tonic-gate 	ASSERT(nbl_in_crit(vp));
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 	if ((flkp->l_type == F_RDLCK || flkp->l_type == F_WRLCK) &&
552*0Sstevel@tonic-gate 	    nbl_share_conflict(vp, nbl_lock_to_op(flkp->l_type)))
553*0Sstevel@tonic-gate 		return (1);
554*0Sstevel@tonic-gate 	else
555*0Sstevel@tonic-gate 		return (0);
556*0Sstevel@tonic-gate }
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate /*
559*0Sstevel@tonic-gate  * Wait for all share reservations to go away that block the given lock
560*0Sstevel@tonic-gate  * request.  Returns 0 after successfully waiting, or EINTR.
561*0Sstevel@tonic-gate  */
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate int
564*0Sstevel@tonic-gate wait_for_share(vnode_t *vp, flock64_t *flkp)
565*0Sstevel@tonic-gate {
566*0Sstevel@tonic-gate 	int result = 0;
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 	ASSERT(nbl_in_crit(vp));
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	/*
571*0Sstevel@tonic-gate 	 * We have to hold the vnode's lock before leaving the nbmand
572*0Sstevel@tonic-gate 	 * critical region, to prevent a race with the thread that deletes
573*0Sstevel@tonic-gate 	 * the share that's blocking us.  Then we have to drop the lock
574*0Sstevel@tonic-gate 	 * before reentering the critical region, to avoid a deadlock.
575*0Sstevel@tonic-gate 	 */
576*0Sstevel@tonic-gate 	while (result == 0 && share_blocks_lock(vp, flkp)) {
577*0Sstevel@tonic-gate 		mutex_enter(&vp->v_lock);
578*0Sstevel@tonic-gate 		nbl_end_crit(vp);
579*0Sstevel@tonic-gate 		if (cv_wait_sig(&vp->v_cv, &vp->v_lock) == 0)
580*0Sstevel@tonic-gate 			result = EINTR;
581*0Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
582*0Sstevel@tonic-gate 		nbl_start_crit(vp, RW_WRITER);
583*0Sstevel@tonic-gate 	}
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	return (result);
586*0Sstevel@tonic-gate }
587*0Sstevel@tonic-gate 
588*0Sstevel@tonic-gate /*
589*0Sstevel@tonic-gate  * Determine if the given share reservation conflicts with any existing
590*0Sstevel@tonic-gate  * locks or mapped regions for the file.  This is used to compensate for
591*0Sstevel@tonic-gate  * the fact that most Unix applications don't get a share reservation, so
592*0Sstevel@tonic-gate  * we use existing locks as an indication of what files are open.
593*0Sstevel@tonic-gate  *
594*0Sstevel@tonic-gate  * XXX needs a better name to reflect that it also looks for mapped file
595*0Sstevel@tonic-gate  * conflicts.
596*0Sstevel@tonic-gate  *
597*0Sstevel@tonic-gate  * Returns non-zero if there is a conflict, zero if okay.
598*0Sstevel@tonic-gate  */
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate static int
601*0Sstevel@tonic-gate lock_blocks_share(vnode_t *vp, struct shrlock *shr)
602*0Sstevel@tonic-gate {
603*0Sstevel@tonic-gate 	struct flock64 lck;
604*0Sstevel@tonic-gate 	int error;
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	/*
607*0Sstevel@tonic-gate 	 * We don't currently have a good way to match lock
608*0Sstevel@tonic-gate 	 * ownership with share ownership for remote requests.
609*0Sstevel@tonic-gate 	 * Fortunately, we know that only local processes (in particular,
610*0Sstevel@tonic-gate 	 * local CIFS servers) care about conflicts between locks and
611*0Sstevel@tonic-gate 	 * share reservations, and we can distinguish local processes from
612*0Sstevel@tonic-gate 	 * each other and from remote processes.
613*0Sstevel@tonic-gate 	 */
614*0Sstevel@tonic-gate 	ASSERT(shr->s_sysid == 0);
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 	if ((shr->s_deny & (F_RWDNY|F_COMPAT)) == 0) {
617*0Sstevel@tonic-gate 		/* if no deny mode, then there's no conflict */
618*0Sstevel@tonic-gate 		return (0);
619*0Sstevel@tonic-gate 	}
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 	lck.l_type = ((shr->s_deny & F_RDDNY) ? F_WRLCK : F_RDLCK);
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	lck.l_whence = 0;
624*0Sstevel@tonic-gate 	lck.l_start = 0;
625*0Sstevel@tonic-gate 	lck.l_len = 0;			/* to EOF */
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 	/* would check here for conflict with mapped region */
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	/* XXX should use non-NULL cred? */
630*0Sstevel@tonic-gate 	error = VOP_FRLOCK(vp, F_GETLK, &lck, 0, 0, NULL, NULL);
631*0Sstevel@tonic-gate 	if (error != 0) {
632*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "lock_blocks_share: unexpected error (%d)",
633*0Sstevel@tonic-gate 			error);
634*0Sstevel@tonic-gate 		return (1);
635*0Sstevel@tonic-gate 	}
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	return (lck.l_type == F_UNLCK ? 0 : 1);
638*0Sstevel@tonic-gate }
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate /*
641*0Sstevel@tonic-gate  * Determine if the given process has a NBMAND share reservation on the
642*0Sstevel@tonic-gate  * given vnode. Returns 1 if the process has such a share reservation,
643*0Sstevel@tonic-gate  * returns 0 otherwise.
644*0Sstevel@tonic-gate  */
645*0Sstevel@tonic-gate int
646*0Sstevel@tonic-gate proc_has_nbmand_share_on_vp(vnode_t *vp, pid_t pid)
647*0Sstevel@tonic-gate {
648*0Sstevel@tonic-gate 	struct shrlocklist *shrl;
649*0Sstevel@tonic-gate 
650*0Sstevel@tonic-gate 	/*
651*0Sstevel@tonic-gate 	 * Any NBMAND share reservation on the vp for this process?
652*0Sstevel@tonic-gate 	 */
653*0Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
654*0Sstevel@tonic-gate 	for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
655*0Sstevel@tonic-gate 		if (shrl->shr->s_sysid == 0 &&
656*0Sstevel@tonic-gate 		    (shrl->shr->s_deny & F_MANDDNY) &&
657*0Sstevel@tonic-gate 		    (shrl->shr->s_pid == pid)) {
658*0Sstevel@tonic-gate 			mutex_exit(&vp->v_lock);
659*0Sstevel@tonic-gate 			return (1);
660*0Sstevel@tonic-gate 		}
661*0Sstevel@tonic-gate 	}
662*0Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate 	return (0);
665*0Sstevel@tonic-gate }
666