xref: /titanic_53/usr/src/uts/common/os/share.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*da6c28aaSamw  * Common Development and Distribution License (the "License").
6*da6c28aaSamw  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*da6c28aaSamw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
307c478bd9Sstevel@tonic-gate #include <sys/param.h>
317c478bd9Sstevel@tonic-gate #include <sys/systm.h>
327c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
337c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
347c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
357c478bd9Sstevel@tonic-gate #include <sys/share.h>
367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
377c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
387c478bd9Sstevel@tonic-gate #include <sys/debug.h>
397c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
407c478bd9Sstevel@tonic-gate #include <sys/errno.h>
417c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate int share_debug = 0;
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #ifdef DEBUG
467c478bd9Sstevel@tonic-gate static void print_shares(struct vnode *);
477c478bd9Sstevel@tonic-gate static void print_share(struct shrlock *);
487c478bd9Sstevel@tonic-gate #endif
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static int isreadonly(struct vnode *);
517c478bd9Sstevel@tonic-gate static int lock_blocks_share(struct vnode *, struct shrlock *);
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /*
547c478bd9Sstevel@tonic-gate  * Add the share reservation shr to vp.
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate int
577c478bd9Sstevel@tonic-gate add_share(struct vnode *vp, struct shrlock *shr)
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate 	struct shrlocklist *shrl;
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate 	/*
627c478bd9Sstevel@tonic-gate 	 * An access of zero is not legal, however some older clients
637c478bd9Sstevel@tonic-gate 	 * generate it anyways.  Allow the request only if it is
647c478bd9Sstevel@tonic-gate 	 * coming from a remote system.  Be generous in what you
657c478bd9Sstevel@tonic-gate 	 * accept and strict in what you send.
667c478bd9Sstevel@tonic-gate 	 */
677c478bd9Sstevel@tonic-gate 	if ((shr->s_access == 0) && (GETSYSID(shr->s_sysid) == 0)) {
687c478bd9Sstevel@tonic-gate 		return (EINVAL);
697c478bd9Sstevel@tonic-gate 	}
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	/*
727c478bd9Sstevel@tonic-gate 	 * Sanity check to make sure we have valid options.
737c478bd9Sstevel@tonic-gate 	 * There is known overlap but it doesn't hurt to be careful.
747c478bd9Sstevel@tonic-gate 	 */
75*da6c28aaSamw 	if (shr->s_access & ~(F_RDACC|F_WRACC|F_RWACC|F_RMACC|F_MDACC)) {
767c478bd9Sstevel@tonic-gate 		return (EINVAL);
777c478bd9Sstevel@tonic-gate 	}
787c478bd9Sstevel@tonic-gate 	if (shr->s_deny & ~(F_NODNY|F_RDDNY|F_WRDNY|F_RWDNY|F_COMPAT|
79*da6c28aaSamw 	    F_MANDDNY|F_RMDNY)) {
807c478bd9Sstevel@tonic-gate 		return (EINVAL);
817c478bd9Sstevel@tonic-gate 	}
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	/*
847c478bd9Sstevel@tonic-gate 	 * If the caller wants non-blocking mandatory semantics, make sure
857c478bd9Sstevel@tonic-gate 	 * that there isn't already a conflicting lock.
867c478bd9Sstevel@tonic-gate 	 */
877c478bd9Sstevel@tonic-gate 	if (shr->s_deny & F_MANDDNY) {
887c478bd9Sstevel@tonic-gate 		ASSERT(nbl_in_crit(vp));
897c478bd9Sstevel@tonic-gate 		if (lock_blocks_share(vp, shr)) {
907c478bd9Sstevel@tonic-gate 			return (EAGAIN);
917c478bd9Sstevel@tonic-gate 		}
927c478bd9Sstevel@tonic-gate 	}
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
957c478bd9Sstevel@tonic-gate 	for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
967c478bd9Sstevel@tonic-gate 		/*
977c478bd9Sstevel@tonic-gate 		 * If the share owner matches previous request
987c478bd9Sstevel@tonic-gate 		 * do special handling.
997c478bd9Sstevel@tonic-gate 		 */
1007c478bd9Sstevel@tonic-gate 		if ((shrl->shr->s_sysid == shr->s_sysid) &&
1017c478bd9Sstevel@tonic-gate 		    (shrl->shr->s_pid == shr->s_pid) &&
1027c478bd9Sstevel@tonic-gate 		    (shrl->shr->s_own_len == shr->s_own_len) &&
1037c478bd9Sstevel@tonic-gate 		    bcmp(shrl->shr->s_owner, shr->s_owner,
1047c478bd9Sstevel@tonic-gate 		    shr->s_own_len) == 0) {
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 			/*
1077c478bd9Sstevel@tonic-gate 			 * If the existing request is F_COMPAT and
1087c478bd9Sstevel@tonic-gate 			 * is the first share then allow any F_COMPAT
1097c478bd9Sstevel@tonic-gate 			 * from the same process.  Trick:  If the existing
1107c478bd9Sstevel@tonic-gate 			 * F_COMPAT is write access then it must have
1117c478bd9Sstevel@tonic-gate 			 * the same owner as the first.
1127c478bd9Sstevel@tonic-gate 			 */
1137c478bd9Sstevel@tonic-gate 			if ((shrl->shr->s_deny & F_COMPAT) &&
1147c478bd9Sstevel@tonic-gate 			    (shr->s_deny & F_COMPAT) &&
1157c478bd9Sstevel@tonic-gate 			    ((shrl->next == NULL) ||
1167c478bd9Sstevel@tonic-gate 			    (shrl->shr->s_access & F_WRACC)))
1177c478bd9Sstevel@tonic-gate 				break;
1187c478bd9Sstevel@tonic-gate 		}
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 		/*
1217c478bd9Sstevel@tonic-gate 		 * If a first share has been done in compatibility mode
1227c478bd9Sstevel@tonic-gate 		 * handle the special cases.
1237c478bd9Sstevel@tonic-gate 		 */
1247c478bd9Sstevel@tonic-gate 		if ((shrl->shr->s_deny & F_COMPAT) && (shrl->next == NULL)) {
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 			if (!(shr->s_deny & F_COMPAT)) {
1277c478bd9Sstevel@tonic-gate 				/*
1287c478bd9Sstevel@tonic-gate 				 * If not compat and want write access or
1297c478bd9Sstevel@tonic-gate 				 * want to deny read or
1307c478bd9Sstevel@tonic-gate 				 * write exists, fails
1317c478bd9Sstevel@tonic-gate 				 */
1327c478bd9Sstevel@tonic-gate 				if ((shr->s_access & F_WRACC) ||
1337c478bd9Sstevel@tonic-gate 				    (shr->s_deny & F_RDDNY) ||
1347c478bd9Sstevel@tonic-gate 				    (shrl->shr->s_access & F_WRACC)) {
1357c478bd9Sstevel@tonic-gate 					mutex_exit(&vp->v_lock);
1367c478bd9Sstevel@tonic-gate 					return (EAGAIN);
1377c478bd9Sstevel@tonic-gate 				}
1387c478bd9Sstevel@tonic-gate 				/*
1397c478bd9Sstevel@tonic-gate 				 * If read only file allow, this may allow
1407c478bd9Sstevel@tonic-gate 				 * a deny write but that is meaningless on
1417c478bd9Sstevel@tonic-gate 				 * a read only file.
1427c478bd9Sstevel@tonic-gate 				 */
1437c478bd9Sstevel@tonic-gate 				if (isreadonly(vp))
1447c478bd9Sstevel@tonic-gate 					break;
1457c478bd9Sstevel@tonic-gate 				mutex_exit(&vp->v_lock);
1467c478bd9Sstevel@tonic-gate 				return (EAGAIN);
1477c478bd9Sstevel@tonic-gate 			}
1487c478bd9Sstevel@tonic-gate 			/*
1497c478bd9Sstevel@tonic-gate 			 * This is a compat request and read access
1507c478bd9Sstevel@tonic-gate 			 * and the first was also read access
1517c478bd9Sstevel@tonic-gate 			 * we always allow it, otherwise we reject because
1527c478bd9Sstevel@tonic-gate 			 * we have handled the only valid write case above.
1537c478bd9Sstevel@tonic-gate 			 */
1547c478bd9Sstevel@tonic-gate 			if ((shr->s_access == F_RDACC) &&
1557c478bd9Sstevel@tonic-gate 			    (shrl->shr->s_access == F_RDACC))
1567c478bd9Sstevel@tonic-gate 				break;
1577c478bd9Sstevel@tonic-gate 			mutex_exit(&vp->v_lock);
1587c478bd9Sstevel@tonic-gate 			return (EAGAIN);
1597c478bd9Sstevel@tonic-gate 		}
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 		/*
1627c478bd9Sstevel@tonic-gate 		 * If we are trying to share in compatibility mode
1637c478bd9Sstevel@tonic-gate 		 * and the current share is compat (and not the first)
1647c478bd9Sstevel@tonic-gate 		 * we don't know enough.
1657c478bd9Sstevel@tonic-gate 		 */
1667c478bd9Sstevel@tonic-gate 		if ((shrl->shr->s_deny & F_COMPAT) && (shr->s_deny & F_COMPAT))
1677c478bd9Sstevel@tonic-gate 			continue;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 		/*
1707c478bd9Sstevel@tonic-gate 		 * If this is a compat we check for what can't succeed.
1717c478bd9Sstevel@tonic-gate 		 */
1727c478bd9Sstevel@tonic-gate 		if (shr->s_deny & F_COMPAT) {
1737c478bd9Sstevel@tonic-gate 			/*
1747c478bd9Sstevel@tonic-gate 			 * If we want write access or
1757c478bd9Sstevel@tonic-gate 			 * if anyone is denying read or
1767c478bd9Sstevel@tonic-gate 			 * if anyone has write access we fail
1777c478bd9Sstevel@tonic-gate 			 */
1787c478bd9Sstevel@tonic-gate 			if ((shr->s_access & F_WRACC) ||
1797c478bd9Sstevel@tonic-gate 			    (shrl->shr->s_deny & F_RDDNY) ||
1807c478bd9Sstevel@tonic-gate 			    (shrl->shr->s_access & F_WRACC)) {
1817c478bd9Sstevel@tonic-gate 				mutex_exit(&vp->v_lock);
1827c478bd9Sstevel@tonic-gate 				return (EAGAIN);
1837c478bd9Sstevel@tonic-gate 			}
1847c478bd9Sstevel@tonic-gate 			/*
1857c478bd9Sstevel@tonic-gate 			 * If the first was opened with only read access
1867c478bd9Sstevel@tonic-gate 			 * and is a read only file we allow.
1877c478bd9Sstevel@tonic-gate 			 */
1887c478bd9Sstevel@tonic-gate 			if (shrl->next == NULL) {
1897c478bd9Sstevel@tonic-gate 				if ((shrl->shr->s_access == F_RDACC) &&
1907c478bd9Sstevel@tonic-gate 				    isreadonly(vp)) {
1917c478bd9Sstevel@tonic-gate 					break;
1927c478bd9Sstevel@tonic-gate 				}
1937c478bd9Sstevel@tonic-gate 				mutex_exit(&vp->v_lock);
1947c478bd9Sstevel@tonic-gate 				return (EAGAIN);
1957c478bd9Sstevel@tonic-gate 			}
1967c478bd9Sstevel@tonic-gate 			/*
1977c478bd9Sstevel@tonic-gate 			 * We still can't determine our fate so continue
1987c478bd9Sstevel@tonic-gate 			 */
1997c478bd9Sstevel@tonic-gate 			continue;
2007c478bd9Sstevel@tonic-gate 		}
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 		/*
2037c478bd9Sstevel@tonic-gate 		 * Simple bitwise test, if we are trying to access what
2047c478bd9Sstevel@tonic-gate 		 * someone else is denying or we are trying to deny
2057c478bd9Sstevel@tonic-gate 		 * what someone else is accessing we fail.
2067c478bd9Sstevel@tonic-gate 		 */
2077c478bd9Sstevel@tonic-gate 		if ((shr->s_access & shrl->shr->s_deny) ||
2087c478bd9Sstevel@tonic-gate 		    (shr->s_deny & shrl->shr->s_access)) {
2097c478bd9Sstevel@tonic-gate 			mutex_exit(&vp->v_lock);
2107c478bd9Sstevel@tonic-gate 			return (EAGAIN);
2117c478bd9Sstevel@tonic-gate 		}
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	shrl = kmem_alloc(sizeof (struct shrlocklist), KM_SLEEP);
2157c478bd9Sstevel@tonic-gate 	shrl->shr = kmem_alloc(sizeof (struct shrlock), KM_SLEEP);
2167c478bd9Sstevel@tonic-gate 	shrl->shr->s_access = shr->s_access;
2177c478bd9Sstevel@tonic-gate 	shrl->shr->s_deny = shr->s_deny;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/*
2207c478bd9Sstevel@tonic-gate 	 * Make sure no other deny modes are also set with F_COMPAT
2217c478bd9Sstevel@tonic-gate 	 */
2227c478bd9Sstevel@tonic-gate 	if (shrl->shr->s_deny & F_COMPAT)
2237c478bd9Sstevel@tonic-gate 		shrl->shr->s_deny = F_COMPAT;
2247c478bd9Sstevel@tonic-gate 	shrl->shr->s_sysid = shr->s_sysid;		/* XXX ref cnt? */
2257c478bd9Sstevel@tonic-gate 	shrl->shr->s_pid = shr->s_pid;
2267c478bd9Sstevel@tonic-gate 	shrl->shr->s_own_len = shr->s_own_len;
2277c478bd9Sstevel@tonic-gate 	shrl->shr->s_owner = kmem_alloc(shr->s_own_len, KM_SLEEP);
2287c478bd9Sstevel@tonic-gate 	bcopy(shr->s_owner, shrl->shr->s_owner, shr->s_own_len);
2297c478bd9Sstevel@tonic-gate 	shrl->next = vp->v_shrlocks;
2307c478bd9Sstevel@tonic-gate 	vp->v_shrlocks = shrl;
2317c478bd9Sstevel@tonic-gate #ifdef DEBUG
2327c478bd9Sstevel@tonic-gate 	if (share_debug)
2337c478bd9Sstevel@tonic-gate 		print_shares(vp);
2347c478bd9Sstevel@tonic-gate #endif
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	return (0);
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate /*
2427c478bd9Sstevel@tonic-gate  *	nlmid	sysid	pid
2437c478bd9Sstevel@tonic-gate  *	=====	=====	===
2447c478bd9Sstevel@tonic-gate  *	!=0	!=0	=0	in cluster; NLM lock
2457c478bd9Sstevel@tonic-gate  *	!=0	=0	=0	in cluster; special case for NLM lock
2467c478bd9Sstevel@tonic-gate  *	!=0	=0	!=0	in cluster; PXFS local lock
2477c478bd9Sstevel@tonic-gate  *	!=0	!=0	!=0	cannot happen
2487c478bd9Sstevel@tonic-gate  *	=0	!=0	=0	not in cluster; NLM lock
2497c478bd9Sstevel@tonic-gate  *	=0	=0	!=0	not in cluster; local lock
2507c478bd9Sstevel@tonic-gate  *	=0	=0	=0	cannot happen
2517c478bd9Sstevel@tonic-gate  *	=0	!=0	!=0	cannot happen
2527c478bd9Sstevel@tonic-gate  */
2537c478bd9Sstevel@tonic-gate static int
2547c478bd9Sstevel@tonic-gate is_match_for_del(struct shrlock *shr, struct shrlock *element)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	int nlmid1, nlmid2;
2577c478bd9Sstevel@tonic-gate 	int result = 0;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	nlmid1 = GETNLMID(shr->s_sysid);
2607c478bd9Sstevel@tonic-gate 	nlmid2 = GETNLMID(element->s_sysid);
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	if (nlmid1 != 0) {		/* in a cluster */
2637c478bd9Sstevel@tonic-gate 		if (GETSYSID(shr->s_sysid) != 0 && shr->s_pid == 0) {
2647c478bd9Sstevel@tonic-gate 			/*
2657c478bd9Sstevel@tonic-gate 			 * Lock obtained through nlm server.  Just need to
2667c478bd9Sstevel@tonic-gate 			 * compare whole sysids.  pid will always = 0.
2677c478bd9Sstevel@tonic-gate 			 */
2687c478bd9Sstevel@tonic-gate 			result = shr->s_sysid == element->s_sysid;
2697c478bd9Sstevel@tonic-gate 		} else if (GETSYSID(shr->s_sysid) == 0 && shr->s_pid == 0) {
2707c478bd9Sstevel@tonic-gate 			/*
2717c478bd9Sstevel@tonic-gate 			 * This is a special case.  The NLM server wishes to
2727c478bd9Sstevel@tonic-gate 			 * delete all share locks obtained through nlmid1.
2737c478bd9Sstevel@tonic-gate 			 */
2747c478bd9Sstevel@tonic-gate 			result = (nlmid1 == nlmid2);
2757c478bd9Sstevel@tonic-gate 		} else if (GETSYSID(shr->s_sysid) == 0 && shr->s_pid != 0) {
2767c478bd9Sstevel@tonic-gate 			/*
2777c478bd9Sstevel@tonic-gate 			 * Lock obtained locally through PXFS.  Match nlmids
2787c478bd9Sstevel@tonic-gate 			 * and pids.
2797c478bd9Sstevel@tonic-gate 			 */
2807c478bd9Sstevel@tonic-gate 			result = (nlmid1 == nlmid2 &&
2817c478bd9Sstevel@tonic-gate 			    shr->s_pid == element->s_pid);
2827c478bd9Sstevel@tonic-gate 		}
2837c478bd9Sstevel@tonic-gate 	} else {			/* not in a cluster */
2847c478bd9Sstevel@tonic-gate 		result = ((shr->s_sysid == 0 &&
2857c478bd9Sstevel@tonic-gate 		    shr->s_pid == element->s_pid) ||
2867c478bd9Sstevel@tonic-gate 		    (shr->s_sysid != 0 &&
2877c478bd9Sstevel@tonic-gate 		    shr->s_sysid == element->s_sysid));
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 	return (result);
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate /*
2937c478bd9Sstevel@tonic-gate  * Delete the given share reservation.  Returns 0 if okay, EINVAL if the
2947c478bd9Sstevel@tonic-gate  * share could not be found.  If the share reservation is an NBMAND share
2957c478bd9Sstevel@tonic-gate  * reservation, signal anyone waiting for the share to go away (e.g.,
2967c478bd9Sstevel@tonic-gate  * blocking lock requests).
2977c478bd9Sstevel@tonic-gate  */
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate int
3007c478bd9Sstevel@tonic-gate del_share(struct vnode *vp, struct shrlock *shr)
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate 	struct shrlocklist *shrl;
3037c478bd9Sstevel@tonic-gate 	struct shrlocklist **shrlp;
3047c478bd9Sstevel@tonic-gate 	int found = 0;
3057c478bd9Sstevel@tonic-gate 	int is_nbmand = 0;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
3087c478bd9Sstevel@tonic-gate 	/*
3097c478bd9Sstevel@tonic-gate 	 * Delete the shares with the matching sysid and owner
3107c478bd9Sstevel@tonic-gate 	 * But if own_len == 0 and sysid == 0 delete all with matching pid
3117c478bd9Sstevel@tonic-gate 	 * But if own_len == 0 delete all with matching sysid.
3127c478bd9Sstevel@tonic-gate 	 */
3137c478bd9Sstevel@tonic-gate 	shrlp = &vp->v_shrlocks;
3147c478bd9Sstevel@tonic-gate 	while (*shrlp) {
3157c478bd9Sstevel@tonic-gate 		if ((shr->s_own_len == (*shrlp)->shr->s_own_len &&
3167c478bd9Sstevel@tonic-gate 		    (bcmp(shr->s_owner, (*shrlp)->shr->s_owner,
3177c478bd9Sstevel@tonic-gate 		    shr->s_own_len) == 0)) ||
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 		    (shr->s_own_len == 0 &&
3207c478bd9Sstevel@tonic-gate 		    is_match_for_del(shr, (*shrlp)->shr))) {
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 			shrl = *shrlp;
3237c478bd9Sstevel@tonic-gate 			*shrlp = shrl->next;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 			if (shrl->shr->s_deny & F_MANDDNY)
3267c478bd9Sstevel@tonic-gate 				is_nbmand = 1;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 			/* XXX deref sysid */
3297c478bd9Sstevel@tonic-gate 			kmem_free(shrl->shr->s_owner, shrl->shr->s_own_len);
3307c478bd9Sstevel@tonic-gate 			kmem_free(shrl->shr, sizeof (struct shrlock));
3317c478bd9Sstevel@tonic-gate 			kmem_free(shrl, sizeof (struct shrlocklist));
3327c478bd9Sstevel@tonic-gate 			found++;
3337c478bd9Sstevel@tonic-gate 			continue;
3347c478bd9Sstevel@tonic-gate 		}
3357c478bd9Sstevel@tonic-gate 		shrlp = &(*shrlp)->next;
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	if (is_nbmand)
3397c478bd9Sstevel@tonic-gate 		cv_broadcast(&vp->v_cv);
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
3427c478bd9Sstevel@tonic-gate 	return (found ? 0 : EINVAL);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate  * Clean up all local share reservations that the given process has with
3477c478bd9Sstevel@tonic-gate  * the given file.
3487c478bd9Sstevel@tonic-gate  */
3497c478bd9Sstevel@tonic-gate void
3507c478bd9Sstevel@tonic-gate cleanshares(struct vnode *vp, pid_t pid)
3517c478bd9Sstevel@tonic-gate {
3527c478bd9Sstevel@tonic-gate 	struct shrlock shr;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	if (vp->v_shrlocks == NULL)
3557c478bd9Sstevel@tonic-gate 		return;
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	shr.s_access = 0;
3587c478bd9Sstevel@tonic-gate 	shr.s_deny = 0;
3597c478bd9Sstevel@tonic-gate 	shr.s_pid = pid;
3607c478bd9Sstevel@tonic-gate 	shr.s_sysid = 0;
3617c478bd9Sstevel@tonic-gate 	shr.s_own_len = 0;
3627c478bd9Sstevel@tonic-gate 	shr.s_owner = NULL;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	(void) del_share(vp, &shr);
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate static int
3687c478bd9Sstevel@tonic-gate is_match_for_has_remote(int32_t sysid1, int32_t sysid2)
3697c478bd9Sstevel@tonic-gate {
3707c478bd9Sstevel@tonic-gate 	int result = 0;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	if (GETNLMID(sysid1) != 0) { /* in a cluster */
3737c478bd9Sstevel@tonic-gate 		if (GETSYSID(sysid1) != 0) {
3747c478bd9Sstevel@tonic-gate 			/*
3757c478bd9Sstevel@tonic-gate 			 * Lock obtained through nlm server.  Just need to
3767c478bd9Sstevel@tonic-gate 			 * compare whole sysids.
3777c478bd9Sstevel@tonic-gate 			 */
3787c478bd9Sstevel@tonic-gate 			result = (sysid1 == sysid2);
3797c478bd9Sstevel@tonic-gate 		} else if (GETSYSID(sysid1) == 0) {
3807c478bd9Sstevel@tonic-gate 			/*
3817c478bd9Sstevel@tonic-gate 			 * This is a special case.  The NLM server identified
3827c478bd9Sstevel@tonic-gate 			 * by nlmid1 wishes to find out if it has obtained
3837c478bd9Sstevel@tonic-gate 			 * any share locks on the vnode.
3847c478bd9Sstevel@tonic-gate 			 */
3857c478bd9Sstevel@tonic-gate 			result = (GETNLMID(sysid1) == GETNLMID(sysid2));
3867c478bd9Sstevel@tonic-gate 		}
3877c478bd9Sstevel@tonic-gate 	} else {			/* not in a cluster */
3887c478bd9Sstevel@tonic-gate 		result = ((sysid1 != 0 && sysid1 == sysid2) ||
3897c478bd9Sstevel@tonic-gate 		    (sysid1 == 0 && sysid2 != 0));
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 	return (result);
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate /*
3967c478bd9Sstevel@tonic-gate  * Determine whether there are any shares for the given vnode
3977c478bd9Sstevel@tonic-gate  * with a remote sysid. Returns zero if not, non-zero if there are.
3987c478bd9Sstevel@tonic-gate  * If sysid is non-zero then determine if this sysid has a share.
3997c478bd9Sstevel@tonic-gate  *
4007c478bd9Sstevel@tonic-gate  * Note that the return value from this function is potentially invalid
4017c478bd9Sstevel@tonic-gate  * once it has been returned.  The caller is responsible for providing its
4027c478bd9Sstevel@tonic-gate  * own synchronization mechanism to ensure that the return value is useful.
4037c478bd9Sstevel@tonic-gate  */
4047c478bd9Sstevel@tonic-gate int
4057c478bd9Sstevel@tonic-gate shr_has_remote_shares(vnode_t *vp, int32_t sysid)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate 	struct shrlocklist *shrl;
4087c478bd9Sstevel@tonic-gate 	int result = 0;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
4117c478bd9Sstevel@tonic-gate 	shrl = vp->v_shrlocks;
4127c478bd9Sstevel@tonic-gate 	while (shrl) {
4137c478bd9Sstevel@tonic-gate 		if (is_match_for_has_remote(sysid, shrl->shr->s_sysid)) {
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 			result = 1;
4167c478bd9Sstevel@tonic-gate 			break;
4177c478bd9Sstevel@tonic-gate 		}
4187c478bd9Sstevel@tonic-gate 		shrl = shrl->next;
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
4217c478bd9Sstevel@tonic-gate 	return (result);
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate static int
4257c478bd9Sstevel@tonic-gate isreadonly(struct vnode *vp)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate 	return (vp->v_type != VCHR && vp->v_type != VBLK &&
4287c478bd9Sstevel@tonic-gate 	    vp->v_type != VFIFO && vn_is_readonly(vp));
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate #ifdef DEBUG
4327c478bd9Sstevel@tonic-gate static void
4337c478bd9Sstevel@tonic-gate print_shares(struct vnode *vp)
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate 	struct shrlocklist *shrl;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	if (vp->v_shrlocks == NULL) {
4387c478bd9Sstevel@tonic-gate 		printf("<NULL>\n");
4397c478bd9Sstevel@tonic-gate 		return;
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	shrl = vp->v_shrlocks;
4437c478bd9Sstevel@tonic-gate 	while (shrl) {
4447c478bd9Sstevel@tonic-gate 		print_share(shrl->shr);
4457c478bd9Sstevel@tonic-gate 		shrl = shrl->next;
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate static void
4507c478bd9Sstevel@tonic-gate print_share(struct shrlock *shr)
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate 	int i;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	if (shr == NULL) {
4557c478bd9Sstevel@tonic-gate 		printf("<NULL>\n");
4567c478bd9Sstevel@tonic-gate 		return;
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	printf("    access(%d):	", shr->s_access);
4607c478bd9Sstevel@tonic-gate 	if (shr->s_access & F_RDACC)
4617c478bd9Sstevel@tonic-gate 		printf("R");
4627c478bd9Sstevel@tonic-gate 	if (shr->s_access & F_WRACC)
4637c478bd9Sstevel@tonic-gate 		printf("W");
4647c478bd9Sstevel@tonic-gate 	if ((shr->s_access & (F_RDACC|F_WRACC)) == 0)
4657c478bd9Sstevel@tonic-gate 		printf("N");
4667c478bd9Sstevel@tonic-gate 	printf("\n");
4677c478bd9Sstevel@tonic-gate 	printf("    deny:	");
4687c478bd9Sstevel@tonic-gate 	if (shr->s_deny & F_COMPAT)
4697c478bd9Sstevel@tonic-gate 		printf("C");
4707c478bd9Sstevel@tonic-gate 	if (shr->s_deny & F_RDDNY)
4717c478bd9Sstevel@tonic-gate 		printf("R");
4727c478bd9Sstevel@tonic-gate 	if (shr->s_deny & F_WRDNY)
4737c478bd9Sstevel@tonic-gate 		printf("W");
4747c478bd9Sstevel@tonic-gate 	if (shr->s_deny == F_NODNY)
4757c478bd9Sstevel@tonic-gate 		printf("N");
4767c478bd9Sstevel@tonic-gate 	printf("\n");
4777c478bd9Sstevel@tonic-gate 	printf("    sysid:	%d\n", shr->s_sysid);
4787c478bd9Sstevel@tonic-gate 	printf("    pid:	%d\n", shr->s_pid);
4797c478bd9Sstevel@tonic-gate 	printf("    owner:	[%d]", shr->s_own_len);
4807c478bd9Sstevel@tonic-gate 	printf("'");
4817c478bd9Sstevel@tonic-gate 	for (i = 0; i < shr->s_own_len; i++)
4827c478bd9Sstevel@tonic-gate 		printf("%02x", (unsigned)shr->s_owner[i]);
4837c478bd9Sstevel@tonic-gate 	printf("'\n");
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate #endif
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate /*
4887c478bd9Sstevel@tonic-gate  * Return non-zero if the given I/O request conflicts with a registered
4897c478bd9Sstevel@tonic-gate  * share reservation.
490*da6c28aaSamw  *
491*da6c28aaSamw  * A process is identified by the tuple (sysid, pid). When the caller
492*da6c28aaSamw  * context is passed to nbl_share_conflict, the sysid and pid in the
493*da6c28aaSamw  * caller context are used. Otherwise the sysid is zero, and the pid is
494*da6c28aaSamw  * taken from the current process.
495*da6c28aaSamw  *
496*da6c28aaSamw  * Conflict Algorithm:
497*da6c28aaSamw  *   1. An op request of NBL_READ will fail if a different
498*da6c28aaSamw  *      process has a mandatory share reservation with deny read.
499*da6c28aaSamw  *
500*da6c28aaSamw  *   2. An op request of NBL_WRITE will fail if a different
501*da6c28aaSamw  *      process has a mandatory share reservation with deny write.
502*da6c28aaSamw  *
503*da6c28aaSamw  *   3. An op request of NBL_READWRITE will fail if a different
504*da6c28aaSamw  *      process has a mandatory share reservation with deny read
505*da6c28aaSamw  *      or deny write.
506*da6c28aaSamw  *
507*da6c28aaSamw  *   4. An op request of NBL_REMOVE will fail if there is
508*da6c28aaSamw  *      a mandatory share reservation with an access of read,
509*da6c28aaSamw  *      write, or remove. (Anything other than meta data access).
510*da6c28aaSamw  *
511*da6c28aaSamw  *   5. An op request of NBL_RENAME will fail if there is
512*da6c28aaSamw  *      a mandatory share reservation with:
513*da6c28aaSamw  *        a) access write or access remove
514*da6c28aaSamw  *      or
515*da6c28aaSamw  *        b) access read and deny remove
516*da6c28aaSamw  *
517*da6c28aaSamw  *   Otherwise there is no conflict and the op request succeeds.
518*da6c28aaSamw  *
519*da6c28aaSamw  * This behavior is required for interoperability between
520*da6c28aaSamw  * the nfs server, cifs server, and local access.
521*da6c28aaSamw  * This behavior can result in non-posix semantics.
522*da6c28aaSamw  *
523*da6c28aaSamw  * When mandatory share reservations are enabled, a process
524*da6c28aaSamw  * should call nbl_share_conflict to determine if the
525*da6c28aaSamw  * desired operation would conflict with an existing share
526*da6c28aaSamw  * reservation.
527*da6c28aaSamw  *
528*da6c28aaSamw  * The call to nbl_share_conflict may be skipped if the
529*da6c28aaSamw  * process has an existing share reservation and the operation
530*da6c28aaSamw  * is being performed in the context of that existing share
531*da6c28aaSamw  * reservation.
5327c478bd9Sstevel@tonic-gate  */
5337c478bd9Sstevel@tonic-gate int
534*da6c28aaSamw nbl_share_conflict(vnode_t *vp, nbl_op_t op, caller_context_t *ct)
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate 	struct shrlocklist *shrl;
5377c478bd9Sstevel@tonic-gate 	int conflict = 0;
538*da6c28aaSamw 	pid_t pid;
539*da6c28aaSamw 	int sysid;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	ASSERT(nbl_in_crit(vp));
5427c478bd9Sstevel@tonic-gate 
543*da6c28aaSamw 	if (ct == NULL) {
544*da6c28aaSamw 		pid = curproc->p_pid;
545*da6c28aaSamw 		sysid = 0;
546*da6c28aaSamw 	} else {
547*da6c28aaSamw 		pid = ct->cc_pid;
548*da6c28aaSamw 		sysid = ct->cc_sysid;
549*da6c28aaSamw 	}
550*da6c28aaSamw 
5517c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
5527c478bd9Sstevel@tonic-gate 	for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
553*da6c28aaSamw 		if (!(shrl->shr->s_deny & F_MANDDNY))
554*da6c28aaSamw 			continue;
555*da6c28aaSamw 		/*
556*da6c28aaSamw 		 * NBL_READ, NBL_WRITE, and NBL_READWRITE need to
557*da6c28aaSamw 		 * check if the share reservation being examined
558*da6c28aaSamw 		 * belongs to the current process.
559*da6c28aaSamw 		 * NBL_REMOVE and NBL_RENAME do not.
560*da6c28aaSamw 		 * This behavior is required by the conflict
561*da6c28aaSamw 		 * algorithm described above.
562*da6c28aaSamw 		 */
5637c478bd9Sstevel@tonic-gate 		switch (op) {
5647c478bd9Sstevel@tonic-gate 		case NBL_READ:
565*da6c28aaSamw 			if ((shrl->shr->s_deny & F_RDDNY) &&
566*da6c28aaSamw 			    (shrl->shr->s_sysid != sysid ||
567*da6c28aaSamw 			    shrl->shr->s_pid != pid))
5687c478bd9Sstevel@tonic-gate 				conflict = 1;
5697c478bd9Sstevel@tonic-gate 			break;
5707c478bd9Sstevel@tonic-gate 		case NBL_WRITE:
571*da6c28aaSamw 			if ((shrl->shr->s_deny & F_WRDNY) &&
572*da6c28aaSamw 			    (shrl->shr->s_sysid != sysid ||
573*da6c28aaSamw 			    shrl->shr->s_pid != pid))
5747c478bd9Sstevel@tonic-gate 				conflict = 1;
5757c478bd9Sstevel@tonic-gate 			break;
5767c478bd9Sstevel@tonic-gate 		case NBL_READWRITE:
577*da6c28aaSamw 			if ((shrl->shr->s_deny & F_RWDNY) &&
578*da6c28aaSamw 			    (shrl->shr->s_sysid != sysid ||
579*da6c28aaSamw 			    shrl->shr->s_pid != pid))
580*da6c28aaSamw 				conflict = 1;
581*da6c28aaSamw 			break;
582*da6c28aaSamw 		case NBL_REMOVE:
583*da6c28aaSamw 			if (shrl->shr->s_access & (F_RWACC|F_RMACC))
5847c478bd9Sstevel@tonic-gate 				conflict = 1;
5857c478bd9Sstevel@tonic-gate 			break;
5867c478bd9Sstevel@tonic-gate 		case NBL_RENAME:
587*da6c28aaSamw 			if (shrl->shr->s_access & (F_WRACC|F_RMACC))
588*da6c28aaSamw 				conflict = 1;
589*da6c28aaSamw 
590*da6c28aaSamw 			else if ((shrl->shr->s_access & F_RDACC) &&
591*da6c28aaSamw 			    (shrl->shr->s_deny & F_RMDNY))
5927c478bd9Sstevel@tonic-gate 				conflict = 1;
5937c478bd9Sstevel@tonic-gate 			break;
5947c478bd9Sstevel@tonic-gate #ifdef DEBUG
5957c478bd9Sstevel@tonic-gate 		default:
5967c478bd9Sstevel@tonic-gate 			cmn_err(CE_PANIC,
5977c478bd9Sstevel@tonic-gate 			    "nbl_share_conflict: bogus op (%d)",
5987c478bd9Sstevel@tonic-gate 			    op);
5997c478bd9Sstevel@tonic-gate 			break;
6007c478bd9Sstevel@tonic-gate #endif
6017c478bd9Sstevel@tonic-gate 		}
6027c478bd9Sstevel@tonic-gate 		if (conflict)
6037c478bd9Sstevel@tonic-gate 			break;
6047c478bd9Sstevel@tonic-gate 	}
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
6077c478bd9Sstevel@tonic-gate 	return (conflict);
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate /*
6117c478bd9Sstevel@tonic-gate  * Return non-zero if the given lock request conflicts with an existing
6127c478bd9Sstevel@tonic-gate  * non-blocking mandatory share reservation.
6137c478bd9Sstevel@tonic-gate  */
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate int
6167c478bd9Sstevel@tonic-gate share_blocks_lock(vnode_t *vp, flock64_t *flkp)
6177c478bd9Sstevel@tonic-gate {
618*da6c28aaSamw 	caller_context_t ct;
619*da6c28aaSamw 
6207c478bd9Sstevel@tonic-gate 	ASSERT(nbl_in_crit(vp));
6217c478bd9Sstevel@tonic-gate 
622*da6c28aaSamw 	ct.cc_pid = flkp->l_pid;
623*da6c28aaSamw 	ct.cc_sysid = flkp->l_sysid;
624*da6c28aaSamw 	ct.cc_caller_id = 0;
625*da6c28aaSamw 
6267c478bd9Sstevel@tonic-gate 	if ((flkp->l_type == F_RDLCK || flkp->l_type == F_WRLCK) &&
627*da6c28aaSamw 	    nbl_share_conflict(vp, nbl_lock_to_op(flkp->l_type), &ct))
6287c478bd9Sstevel@tonic-gate 		return (1);
6297c478bd9Sstevel@tonic-gate 	else
6307c478bd9Sstevel@tonic-gate 		return (0);
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate /*
6347c478bd9Sstevel@tonic-gate  * Wait for all share reservations to go away that block the given lock
6357c478bd9Sstevel@tonic-gate  * request.  Returns 0 after successfully waiting, or EINTR.
6367c478bd9Sstevel@tonic-gate  */
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate int
6397c478bd9Sstevel@tonic-gate wait_for_share(vnode_t *vp, flock64_t *flkp)
6407c478bd9Sstevel@tonic-gate {
6417c478bd9Sstevel@tonic-gate 	int result = 0;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	ASSERT(nbl_in_crit(vp));
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	/*
6467c478bd9Sstevel@tonic-gate 	 * We have to hold the vnode's lock before leaving the nbmand
6477c478bd9Sstevel@tonic-gate 	 * critical region, to prevent a race with the thread that deletes
6487c478bd9Sstevel@tonic-gate 	 * the share that's blocking us.  Then we have to drop the lock
6497c478bd9Sstevel@tonic-gate 	 * before reentering the critical region, to avoid a deadlock.
6507c478bd9Sstevel@tonic-gate 	 */
6517c478bd9Sstevel@tonic-gate 	while (result == 0 && share_blocks_lock(vp, flkp)) {
6527c478bd9Sstevel@tonic-gate 		mutex_enter(&vp->v_lock);
6537c478bd9Sstevel@tonic-gate 		nbl_end_crit(vp);
6547c478bd9Sstevel@tonic-gate 		if (cv_wait_sig(&vp->v_cv, &vp->v_lock) == 0)
6557c478bd9Sstevel@tonic-gate 			result = EINTR;
6567c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
6577c478bd9Sstevel@tonic-gate 		nbl_start_crit(vp, RW_WRITER);
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	return (result);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate /*
6647c478bd9Sstevel@tonic-gate  * Determine if the given share reservation conflicts with any existing
6657c478bd9Sstevel@tonic-gate  * locks or mapped regions for the file.  This is used to compensate for
6667c478bd9Sstevel@tonic-gate  * the fact that most Unix applications don't get a share reservation, so
6677c478bd9Sstevel@tonic-gate  * we use existing locks as an indication of what files are open.
6687c478bd9Sstevel@tonic-gate  *
6697c478bd9Sstevel@tonic-gate  * XXX needs a better name to reflect that it also looks for mapped file
6707c478bd9Sstevel@tonic-gate  * conflicts.
6717c478bd9Sstevel@tonic-gate  *
6727c478bd9Sstevel@tonic-gate  * Returns non-zero if there is a conflict, zero if okay.
6737c478bd9Sstevel@tonic-gate  */
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate static int
6767c478bd9Sstevel@tonic-gate lock_blocks_share(vnode_t *vp, struct shrlock *shr)
6777c478bd9Sstevel@tonic-gate {
6787c478bd9Sstevel@tonic-gate 	struct flock64 lck;
6797c478bd9Sstevel@tonic-gate 	int error;
680*da6c28aaSamw 	v_mode_t mode = 0;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	if ((shr->s_deny & (F_RWDNY|F_COMPAT)) == 0) {
6837c478bd9Sstevel@tonic-gate 		/* if no deny mode, then there's no conflict */
6847c478bd9Sstevel@tonic-gate 		return (0);
6857c478bd9Sstevel@tonic-gate 	}
6867c478bd9Sstevel@tonic-gate 
687*da6c28aaSamw 	/* check for conflict with mapped region */
688*da6c28aaSamw 	if ((shr->s_deny & F_RWDNY) == F_WRDNY) {
689*da6c28aaSamw 		mode = V_WRITE;
690*da6c28aaSamw 	} else if ((shr->s_deny & F_RWDNY) == F_RDDNY) {
691*da6c28aaSamw 		mode = V_READ;
692*da6c28aaSamw 	} else {
693*da6c28aaSamw 		mode = V_RDORWR;
694*da6c28aaSamw 	}
695*da6c28aaSamw 	if (vn_is_mapped(vp, mode))
696*da6c28aaSamw 		return (1);
6977c478bd9Sstevel@tonic-gate 
698*da6c28aaSamw 	lck.l_type = ((shr->s_deny & F_RDDNY) ? F_WRLCK : F_RDLCK);
6997c478bd9Sstevel@tonic-gate 	lck.l_whence = 0;
7007c478bd9Sstevel@tonic-gate 	lck.l_start = 0;
7017c478bd9Sstevel@tonic-gate 	lck.l_len = 0;			/* to EOF */
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	/* XXX should use non-NULL cred? */
704*da6c28aaSamw 	error = VOP_FRLOCK(vp, F_GETLK, &lck, 0, 0, NULL, NULL, NULL);
7057c478bd9Sstevel@tonic-gate 	if (error != 0) {
7067c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "lock_blocks_share: unexpected error (%d)",
7077c478bd9Sstevel@tonic-gate 		    error);
7087c478bd9Sstevel@tonic-gate 		return (1);
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	return (lck.l_type == F_UNLCK ? 0 : 1);
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate /*
7157c478bd9Sstevel@tonic-gate  * Determine if the given process has a NBMAND share reservation on the
7167c478bd9Sstevel@tonic-gate  * given vnode. Returns 1 if the process has such a share reservation,
7177c478bd9Sstevel@tonic-gate  * returns 0 otherwise.
7187c478bd9Sstevel@tonic-gate  */
7197c478bd9Sstevel@tonic-gate int
7207c478bd9Sstevel@tonic-gate proc_has_nbmand_share_on_vp(vnode_t *vp, pid_t pid)
7217c478bd9Sstevel@tonic-gate {
7227c478bd9Sstevel@tonic-gate 	struct shrlocklist *shrl;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	/*
7257c478bd9Sstevel@tonic-gate 	 * Any NBMAND share reservation on the vp for this process?
7267c478bd9Sstevel@tonic-gate 	 */
7277c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
7287c478bd9Sstevel@tonic-gate 	for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
7297c478bd9Sstevel@tonic-gate 		if (shrl->shr->s_sysid == 0 &&
7307c478bd9Sstevel@tonic-gate 		    (shrl->shr->s_deny & F_MANDDNY) &&
7317c478bd9Sstevel@tonic-gate 		    (shrl->shr->s_pid == pid)) {
7327c478bd9Sstevel@tonic-gate 			mutex_exit(&vp->v_lock);
7337c478bd9Sstevel@tonic-gate 			return (1);
7347c478bd9Sstevel@tonic-gate 		}
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	return (0);
7397c478bd9Sstevel@tonic-gate }
740