xref: /titanic_53/usr/src/uts/common/os/share.c (revision b89a8333f5e1f75ec0c269b22524bd2eccb972ba)
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
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * 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*b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
287c478bd9Sstevel@tonic-gate #include <sys/param.h>
297c478bd9Sstevel@tonic-gate #include <sys/systm.h>
307c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
317c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
327c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
337c478bd9Sstevel@tonic-gate #include <sys/share.h>
347c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
357c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
367c478bd9Sstevel@tonic-gate #include <sys/debug.h>
377c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
387c478bd9Sstevel@tonic-gate #include <sys/errno.h>
397c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate int share_debug = 0;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #ifdef DEBUG
447c478bd9Sstevel@tonic-gate static void print_shares(struct vnode *);
457c478bd9Sstevel@tonic-gate static void print_share(struct shrlock *);
467c478bd9Sstevel@tonic-gate #endif
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static int isreadonly(struct vnode *);
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * Add the share reservation shr to vp.
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate int
547c478bd9Sstevel@tonic-gate add_share(struct vnode *vp, struct shrlock *shr)
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate 	struct shrlocklist *shrl;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 	/*
597c478bd9Sstevel@tonic-gate 	 * An access of zero is not legal, however some older clients
607c478bd9Sstevel@tonic-gate 	 * generate it anyways.  Allow the request only if it is
617c478bd9Sstevel@tonic-gate 	 * coming from a remote system.  Be generous in what you
627c478bd9Sstevel@tonic-gate 	 * accept and strict in what you send.
637c478bd9Sstevel@tonic-gate 	 */
647c478bd9Sstevel@tonic-gate 	if ((shr->s_access == 0) && (GETSYSID(shr->s_sysid) == 0)) {
657c478bd9Sstevel@tonic-gate 		return (EINVAL);
667c478bd9Sstevel@tonic-gate 	}
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	/*
697c478bd9Sstevel@tonic-gate 	 * Sanity check to make sure we have valid options.
707c478bd9Sstevel@tonic-gate 	 * There is known overlap but it doesn't hurt to be careful.
717c478bd9Sstevel@tonic-gate 	 */
72da6c28aaSamw 	if (shr->s_access & ~(F_RDACC|F_WRACC|F_RWACC|F_RMACC|F_MDACC)) {
737c478bd9Sstevel@tonic-gate 		return (EINVAL);
747c478bd9Sstevel@tonic-gate 	}
757c478bd9Sstevel@tonic-gate 	if (shr->s_deny & ~(F_NODNY|F_RDDNY|F_WRDNY|F_RWDNY|F_COMPAT|
76da6c28aaSamw 	    F_MANDDNY|F_RMDNY)) {
777c478bd9Sstevel@tonic-gate 		return (EINVAL);
787c478bd9Sstevel@tonic-gate 	}
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
817c478bd9Sstevel@tonic-gate 	for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
827c478bd9Sstevel@tonic-gate 		/*
837c478bd9Sstevel@tonic-gate 		 * If the share owner matches previous request
847c478bd9Sstevel@tonic-gate 		 * do special handling.
857c478bd9Sstevel@tonic-gate 		 */
867c478bd9Sstevel@tonic-gate 		if ((shrl->shr->s_sysid == shr->s_sysid) &&
877c478bd9Sstevel@tonic-gate 		    (shrl->shr->s_pid == shr->s_pid) &&
887c478bd9Sstevel@tonic-gate 		    (shrl->shr->s_own_len == shr->s_own_len) &&
897c478bd9Sstevel@tonic-gate 		    bcmp(shrl->shr->s_owner, shr->s_owner,
907c478bd9Sstevel@tonic-gate 		    shr->s_own_len) == 0) {
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 			/*
937c478bd9Sstevel@tonic-gate 			 * If the existing request is F_COMPAT and
947c478bd9Sstevel@tonic-gate 			 * is the first share then allow any F_COMPAT
957c478bd9Sstevel@tonic-gate 			 * from the same process.  Trick:  If the existing
967c478bd9Sstevel@tonic-gate 			 * F_COMPAT is write access then it must have
977c478bd9Sstevel@tonic-gate 			 * the same owner as the first.
987c478bd9Sstevel@tonic-gate 			 */
997c478bd9Sstevel@tonic-gate 			if ((shrl->shr->s_deny & F_COMPAT) &&
1007c478bd9Sstevel@tonic-gate 			    (shr->s_deny & F_COMPAT) &&
1017c478bd9Sstevel@tonic-gate 			    ((shrl->next == NULL) ||
1027c478bd9Sstevel@tonic-gate 			    (shrl->shr->s_access & F_WRACC)))
1037c478bd9Sstevel@tonic-gate 				break;
1047c478bd9Sstevel@tonic-gate 		}
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 		/*
1077c478bd9Sstevel@tonic-gate 		 * If a first share has been done in compatibility mode
1087c478bd9Sstevel@tonic-gate 		 * handle the special cases.
1097c478bd9Sstevel@tonic-gate 		 */
1107c478bd9Sstevel@tonic-gate 		if ((shrl->shr->s_deny & F_COMPAT) && (shrl->next == NULL)) {
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 			if (!(shr->s_deny & F_COMPAT)) {
1137c478bd9Sstevel@tonic-gate 				/*
1147c478bd9Sstevel@tonic-gate 				 * If not compat and want write access or
1157c478bd9Sstevel@tonic-gate 				 * want to deny read or
1167c478bd9Sstevel@tonic-gate 				 * write exists, fails
1177c478bd9Sstevel@tonic-gate 				 */
1187c478bd9Sstevel@tonic-gate 				if ((shr->s_access & F_WRACC) ||
1197c478bd9Sstevel@tonic-gate 				    (shr->s_deny & F_RDDNY) ||
1207c478bd9Sstevel@tonic-gate 				    (shrl->shr->s_access & F_WRACC)) {
1217c478bd9Sstevel@tonic-gate 					mutex_exit(&vp->v_lock);
1227c478bd9Sstevel@tonic-gate 					return (EAGAIN);
1237c478bd9Sstevel@tonic-gate 				}
1247c478bd9Sstevel@tonic-gate 				/*
1257c478bd9Sstevel@tonic-gate 				 * If read only file allow, this may allow
1267c478bd9Sstevel@tonic-gate 				 * a deny write but that is meaningless on
1277c478bd9Sstevel@tonic-gate 				 * a read only file.
1287c478bd9Sstevel@tonic-gate 				 */
1297c478bd9Sstevel@tonic-gate 				if (isreadonly(vp))
1307c478bd9Sstevel@tonic-gate 					break;
1317c478bd9Sstevel@tonic-gate 				mutex_exit(&vp->v_lock);
1327c478bd9Sstevel@tonic-gate 				return (EAGAIN);
1337c478bd9Sstevel@tonic-gate 			}
1347c478bd9Sstevel@tonic-gate 			/*
1357c478bd9Sstevel@tonic-gate 			 * This is a compat request and read access
1367c478bd9Sstevel@tonic-gate 			 * and the first was also read access
1377c478bd9Sstevel@tonic-gate 			 * we always allow it, otherwise we reject because
1387c478bd9Sstevel@tonic-gate 			 * we have handled the only valid write case above.
1397c478bd9Sstevel@tonic-gate 			 */
1407c478bd9Sstevel@tonic-gate 			if ((shr->s_access == F_RDACC) &&
1417c478bd9Sstevel@tonic-gate 			    (shrl->shr->s_access == F_RDACC))
1427c478bd9Sstevel@tonic-gate 				break;
1437c478bd9Sstevel@tonic-gate 			mutex_exit(&vp->v_lock);
1447c478bd9Sstevel@tonic-gate 			return (EAGAIN);
1457c478bd9Sstevel@tonic-gate 		}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 		/*
1487c478bd9Sstevel@tonic-gate 		 * If we are trying to share in compatibility mode
1497c478bd9Sstevel@tonic-gate 		 * and the current share is compat (and not the first)
1507c478bd9Sstevel@tonic-gate 		 * we don't know enough.
1517c478bd9Sstevel@tonic-gate 		 */
1527c478bd9Sstevel@tonic-gate 		if ((shrl->shr->s_deny & F_COMPAT) && (shr->s_deny & F_COMPAT))
1537c478bd9Sstevel@tonic-gate 			continue;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 		/*
1567c478bd9Sstevel@tonic-gate 		 * If this is a compat we check for what can't succeed.
1577c478bd9Sstevel@tonic-gate 		 */
1587c478bd9Sstevel@tonic-gate 		if (shr->s_deny & F_COMPAT) {
1597c478bd9Sstevel@tonic-gate 			/*
1607c478bd9Sstevel@tonic-gate 			 * If we want write access or
1617c478bd9Sstevel@tonic-gate 			 * if anyone is denying read or
1627c478bd9Sstevel@tonic-gate 			 * if anyone has write access we fail
1637c478bd9Sstevel@tonic-gate 			 */
1647c478bd9Sstevel@tonic-gate 			if ((shr->s_access & F_WRACC) ||
1657c478bd9Sstevel@tonic-gate 			    (shrl->shr->s_deny & F_RDDNY) ||
1667c478bd9Sstevel@tonic-gate 			    (shrl->shr->s_access & F_WRACC)) {
1677c478bd9Sstevel@tonic-gate 				mutex_exit(&vp->v_lock);
1687c478bd9Sstevel@tonic-gate 				return (EAGAIN);
1697c478bd9Sstevel@tonic-gate 			}
1707c478bd9Sstevel@tonic-gate 			/*
1717c478bd9Sstevel@tonic-gate 			 * If the first was opened with only read access
1727c478bd9Sstevel@tonic-gate 			 * and is a read only file we allow.
1737c478bd9Sstevel@tonic-gate 			 */
1747c478bd9Sstevel@tonic-gate 			if (shrl->next == NULL) {
1757c478bd9Sstevel@tonic-gate 				if ((shrl->shr->s_access == F_RDACC) &&
1767c478bd9Sstevel@tonic-gate 				    isreadonly(vp)) {
1777c478bd9Sstevel@tonic-gate 					break;
1787c478bd9Sstevel@tonic-gate 				}
1797c478bd9Sstevel@tonic-gate 				mutex_exit(&vp->v_lock);
1807c478bd9Sstevel@tonic-gate 				return (EAGAIN);
1817c478bd9Sstevel@tonic-gate 			}
1827c478bd9Sstevel@tonic-gate 			/*
1837c478bd9Sstevel@tonic-gate 			 * We still can't determine our fate so continue
1847c478bd9Sstevel@tonic-gate 			 */
1857c478bd9Sstevel@tonic-gate 			continue;
1867c478bd9Sstevel@tonic-gate 		}
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 		/*
1897c478bd9Sstevel@tonic-gate 		 * Simple bitwise test, if we are trying to access what
1907c478bd9Sstevel@tonic-gate 		 * someone else is denying or we are trying to deny
1917c478bd9Sstevel@tonic-gate 		 * what someone else is accessing we fail.
1927c478bd9Sstevel@tonic-gate 		 */
1937c478bd9Sstevel@tonic-gate 		if ((shr->s_access & shrl->shr->s_deny) ||
1947c478bd9Sstevel@tonic-gate 		    (shr->s_deny & shrl->shr->s_access)) {
1957c478bd9Sstevel@tonic-gate 			mutex_exit(&vp->v_lock);
1967c478bd9Sstevel@tonic-gate 			return (EAGAIN);
1977c478bd9Sstevel@tonic-gate 		}
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	shrl = kmem_alloc(sizeof (struct shrlocklist), KM_SLEEP);
2017c478bd9Sstevel@tonic-gate 	shrl->shr = kmem_alloc(sizeof (struct shrlock), KM_SLEEP);
2027c478bd9Sstevel@tonic-gate 	shrl->shr->s_access = shr->s_access;
2037c478bd9Sstevel@tonic-gate 	shrl->shr->s_deny = shr->s_deny;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	/*
2067c478bd9Sstevel@tonic-gate 	 * Make sure no other deny modes are also set with F_COMPAT
2077c478bd9Sstevel@tonic-gate 	 */
2087c478bd9Sstevel@tonic-gate 	if (shrl->shr->s_deny & F_COMPAT)
2097c478bd9Sstevel@tonic-gate 		shrl->shr->s_deny = F_COMPAT;
2107c478bd9Sstevel@tonic-gate 	shrl->shr->s_sysid = shr->s_sysid;		/* XXX ref cnt? */
2117c478bd9Sstevel@tonic-gate 	shrl->shr->s_pid = shr->s_pid;
2127c478bd9Sstevel@tonic-gate 	shrl->shr->s_own_len = shr->s_own_len;
2137c478bd9Sstevel@tonic-gate 	shrl->shr->s_owner = kmem_alloc(shr->s_own_len, KM_SLEEP);
2147c478bd9Sstevel@tonic-gate 	bcopy(shr->s_owner, shrl->shr->s_owner, shr->s_own_len);
2157c478bd9Sstevel@tonic-gate 	shrl->next = vp->v_shrlocks;
2167c478bd9Sstevel@tonic-gate 	vp->v_shrlocks = shrl;
2177c478bd9Sstevel@tonic-gate #ifdef DEBUG
2187c478bd9Sstevel@tonic-gate 	if (share_debug)
2197c478bd9Sstevel@tonic-gate 		print_shares(vp);
2207c478bd9Sstevel@tonic-gate #endif
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	return (0);
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate /*
2287c478bd9Sstevel@tonic-gate  *	nlmid	sysid	pid
2297c478bd9Sstevel@tonic-gate  *	=====	=====	===
2307c478bd9Sstevel@tonic-gate  *	!=0	!=0	=0	in cluster; NLM lock
2317c478bd9Sstevel@tonic-gate  *	!=0	=0	=0	in cluster; special case for NLM lock
2327c478bd9Sstevel@tonic-gate  *	!=0	=0	!=0	in cluster; PXFS local lock
2337c478bd9Sstevel@tonic-gate  *	!=0	!=0	!=0	cannot happen
2347c478bd9Sstevel@tonic-gate  *	=0	!=0	=0	not in cluster; NLM lock
2357c478bd9Sstevel@tonic-gate  *	=0	=0	!=0	not in cluster; local lock
2367c478bd9Sstevel@tonic-gate  *	=0	=0	=0	cannot happen
2377c478bd9Sstevel@tonic-gate  *	=0	!=0	!=0	cannot happen
2387c478bd9Sstevel@tonic-gate  */
2397c478bd9Sstevel@tonic-gate static int
2407c478bd9Sstevel@tonic-gate is_match_for_del(struct shrlock *shr, struct shrlock *element)
2417c478bd9Sstevel@tonic-gate {
2427c478bd9Sstevel@tonic-gate 	int nlmid1, nlmid2;
2437c478bd9Sstevel@tonic-gate 	int result = 0;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	nlmid1 = GETNLMID(shr->s_sysid);
2467c478bd9Sstevel@tonic-gate 	nlmid2 = GETNLMID(element->s_sysid);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	if (nlmid1 != 0) {		/* in a cluster */
2497c478bd9Sstevel@tonic-gate 		if (GETSYSID(shr->s_sysid) != 0 && shr->s_pid == 0) {
2507c478bd9Sstevel@tonic-gate 			/*
2517c478bd9Sstevel@tonic-gate 			 * Lock obtained through nlm server.  Just need to
2527c478bd9Sstevel@tonic-gate 			 * compare whole sysids.  pid will always = 0.
2537c478bd9Sstevel@tonic-gate 			 */
2547c478bd9Sstevel@tonic-gate 			result = shr->s_sysid == element->s_sysid;
2557c478bd9Sstevel@tonic-gate 		} else if (GETSYSID(shr->s_sysid) == 0 && shr->s_pid == 0) {
2567c478bd9Sstevel@tonic-gate 			/*
2577c478bd9Sstevel@tonic-gate 			 * This is a special case.  The NLM server wishes to
2587c478bd9Sstevel@tonic-gate 			 * delete all share locks obtained through nlmid1.
2597c478bd9Sstevel@tonic-gate 			 */
2607c478bd9Sstevel@tonic-gate 			result = (nlmid1 == nlmid2);
2617c478bd9Sstevel@tonic-gate 		} else if (GETSYSID(shr->s_sysid) == 0 && shr->s_pid != 0) {
2627c478bd9Sstevel@tonic-gate 			/*
2637c478bd9Sstevel@tonic-gate 			 * Lock obtained locally through PXFS.  Match nlmids
2647c478bd9Sstevel@tonic-gate 			 * and pids.
2657c478bd9Sstevel@tonic-gate 			 */
2667c478bd9Sstevel@tonic-gate 			result = (nlmid1 == nlmid2 &&
2677c478bd9Sstevel@tonic-gate 			    shr->s_pid == element->s_pid);
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 	} else {			/* not in a cluster */
2707c478bd9Sstevel@tonic-gate 		result = ((shr->s_sysid == 0 &&
2717c478bd9Sstevel@tonic-gate 		    shr->s_pid == element->s_pid) ||
2727c478bd9Sstevel@tonic-gate 		    (shr->s_sysid != 0 &&
2737c478bd9Sstevel@tonic-gate 		    shr->s_sysid == element->s_sysid));
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 	return (result);
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate /*
2797c478bd9Sstevel@tonic-gate  * Delete the given share reservation.  Returns 0 if okay, EINVAL if the
2807c478bd9Sstevel@tonic-gate  * share could not be found.  If the share reservation is an NBMAND share
2817c478bd9Sstevel@tonic-gate  * reservation, signal anyone waiting for the share to go away (e.g.,
2827c478bd9Sstevel@tonic-gate  * blocking lock requests).
2837c478bd9Sstevel@tonic-gate  */
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate int
2867c478bd9Sstevel@tonic-gate del_share(struct vnode *vp, struct shrlock *shr)
2877c478bd9Sstevel@tonic-gate {
2887c478bd9Sstevel@tonic-gate 	struct shrlocklist *shrl;
2897c478bd9Sstevel@tonic-gate 	struct shrlocklist **shrlp;
2907c478bd9Sstevel@tonic-gate 	int found = 0;
2917c478bd9Sstevel@tonic-gate 	int is_nbmand = 0;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
2947c478bd9Sstevel@tonic-gate 	/*
2957c478bd9Sstevel@tonic-gate 	 * Delete the shares with the matching sysid and owner
2967c478bd9Sstevel@tonic-gate 	 * But if own_len == 0 and sysid == 0 delete all with matching pid
2977c478bd9Sstevel@tonic-gate 	 * But if own_len == 0 delete all with matching sysid.
2987c478bd9Sstevel@tonic-gate 	 */
2997c478bd9Sstevel@tonic-gate 	shrlp = &vp->v_shrlocks;
3007c478bd9Sstevel@tonic-gate 	while (*shrlp) {
3017c478bd9Sstevel@tonic-gate 		if ((shr->s_own_len == (*shrlp)->shr->s_own_len &&
3027c478bd9Sstevel@tonic-gate 		    (bcmp(shr->s_owner, (*shrlp)->shr->s_owner,
3037c478bd9Sstevel@tonic-gate 		    shr->s_own_len) == 0)) ||
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 		    (shr->s_own_len == 0 &&
3067c478bd9Sstevel@tonic-gate 		    is_match_for_del(shr, (*shrlp)->shr))) {
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 			shrl = *shrlp;
3097c478bd9Sstevel@tonic-gate 			*shrlp = shrl->next;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 			if (shrl->shr->s_deny & F_MANDDNY)
3127c478bd9Sstevel@tonic-gate 				is_nbmand = 1;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 			/* XXX deref sysid */
3157c478bd9Sstevel@tonic-gate 			kmem_free(shrl->shr->s_owner, shrl->shr->s_own_len);
3167c478bd9Sstevel@tonic-gate 			kmem_free(shrl->shr, sizeof (struct shrlock));
3177c478bd9Sstevel@tonic-gate 			kmem_free(shrl, sizeof (struct shrlocklist));
3187c478bd9Sstevel@tonic-gate 			found++;
3197c478bd9Sstevel@tonic-gate 			continue;
3207c478bd9Sstevel@tonic-gate 		}
3217c478bd9Sstevel@tonic-gate 		shrlp = &(*shrlp)->next;
3227c478bd9Sstevel@tonic-gate 	}
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	if (is_nbmand)
3257c478bd9Sstevel@tonic-gate 		cv_broadcast(&vp->v_cv);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
3287c478bd9Sstevel@tonic-gate 	return (found ? 0 : EINVAL);
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate /*
3327c478bd9Sstevel@tonic-gate  * Clean up all local share reservations that the given process has with
3337c478bd9Sstevel@tonic-gate  * the given file.
3347c478bd9Sstevel@tonic-gate  */
3357c478bd9Sstevel@tonic-gate void
3367c478bd9Sstevel@tonic-gate cleanshares(struct vnode *vp, pid_t pid)
3377c478bd9Sstevel@tonic-gate {
3387c478bd9Sstevel@tonic-gate 	struct shrlock shr;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	if (vp->v_shrlocks == NULL)
3417c478bd9Sstevel@tonic-gate 		return;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	shr.s_access = 0;
3447c478bd9Sstevel@tonic-gate 	shr.s_deny = 0;
3457c478bd9Sstevel@tonic-gate 	shr.s_pid = pid;
3467c478bd9Sstevel@tonic-gate 	shr.s_sysid = 0;
3477c478bd9Sstevel@tonic-gate 	shr.s_own_len = 0;
3487c478bd9Sstevel@tonic-gate 	shr.s_owner = NULL;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	(void) del_share(vp, &shr);
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate static int
3547c478bd9Sstevel@tonic-gate is_match_for_has_remote(int32_t sysid1, int32_t sysid2)
3557c478bd9Sstevel@tonic-gate {
3567c478bd9Sstevel@tonic-gate 	int result = 0;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	if (GETNLMID(sysid1) != 0) { /* in a cluster */
3597c478bd9Sstevel@tonic-gate 		if (GETSYSID(sysid1) != 0) {
3607c478bd9Sstevel@tonic-gate 			/*
3617c478bd9Sstevel@tonic-gate 			 * Lock obtained through nlm server.  Just need to
3627c478bd9Sstevel@tonic-gate 			 * compare whole sysids.
3637c478bd9Sstevel@tonic-gate 			 */
3647c478bd9Sstevel@tonic-gate 			result = (sysid1 == sysid2);
3657c478bd9Sstevel@tonic-gate 		} else if (GETSYSID(sysid1) == 0) {
3667c478bd9Sstevel@tonic-gate 			/*
3677c478bd9Sstevel@tonic-gate 			 * This is a special case.  The NLM server identified
3687c478bd9Sstevel@tonic-gate 			 * by nlmid1 wishes to find out if it has obtained
3697c478bd9Sstevel@tonic-gate 			 * any share locks on the vnode.
3707c478bd9Sstevel@tonic-gate 			 */
3717c478bd9Sstevel@tonic-gate 			result = (GETNLMID(sysid1) == GETNLMID(sysid2));
3727c478bd9Sstevel@tonic-gate 		}
3737c478bd9Sstevel@tonic-gate 	} else {			/* not in a cluster */
3747c478bd9Sstevel@tonic-gate 		result = ((sysid1 != 0 && sysid1 == sysid2) ||
3757c478bd9Sstevel@tonic-gate 		    (sysid1 == 0 && sysid2 != 0));
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate 	return (result);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate /*
3827c478bd9Sstevel@tonic-gate  * Determine whether there are any shares for the given vnode
3837c478bd9Sstevel@tonic-gate  * with a remote sysid. Returns zero if not, non-zero if there are.
3847c478bd9Sstevel@tonic-gate  * If sysid is non-zero then determine if this sysid has a share.
3857c478bd9Sstevel@tonic-gate  *
3867c478bd9Sstevel@tonic-gate  * Note that the return value from this function is potentially invalid
3877c478bd9Sstevel@tonic-gate  * once it has been returned.  The caller is responsible for providing its
3887c478bd9Sstevel@tonic-gate  * own synchronization mechanism to ensure that the return value is useful.
3897c478bd9Sstevel@tonic-gate  */
3907c478bd9Sstevel@tonic-gate int
3917c478bd9Sstevel@tonic-gate shr_has_remote_shares(vnode_t *vp, int32_t sysid)
3927c478bd9Sstevel@tonic-gate {
3937c478bd9Sstevel@tonic-gate 	struct shrlocklist *shrl;
3947c478bd9Sstevel@tonic-gate 	int result = 0;
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
3977c478bd9Sstevel@tonic-gate 	shrl = vp->v_shrlocks;
3987c478bd9Sstevel@tonic-gate 	while (shrl) {
3997c478bd9Sstevel@tonic-gate 		if (is_match_for_has_remote(sysid, shrl->shr->s_sysid)) {
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 			result = 1;
4027c478bd9Sstevel@tonic-gate 			break;
4037c478bd9Sstevel@tonic-gate 		}
4047c478bd9Sstevel@tonic-gate 		shrl = shrl->next;
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
4077c478bd9Sstevel@tonic-gate 	return (result);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate static int
4117c478bd9Sstevel@tonic-gate isreadonly(struct vnode *vp)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate 	return (vp->v_type != VCHR && vp->v_type != VBLK &&
4147c478bd9Sstevel@tonic-gate 	    vp->v_type != VFIFO && vn_is_readonly(vp));
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate #ifdef DEBUG
4187c478bd9Sstevel@tonic-gate static void
4197c478bd9Sstevel@tonic-gate print_shares(struct vnode *vp)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate 	struct shrlocklist *shrl;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	if (vp->v_shrlocks == NULL) {
4247c478bd9Sstevel@tonic-gate 		printf("<NULL>\n");
4257c478bd9Sstevel@tonic-gate 		return;
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	shrl = vp->v_shrlocks;
4297c478bd9Sstevel@tonic-gate 	while (shrl) {
4307c478bd9Sstevel@tonic-gate 		print_share(shrl->shr);
4317c478bd9Sstevel@tonic-gate 		shrl = shrl->next;
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate static void
4367c478bd9Sstevel@tonic-gate print_share(struct shrlock *shr)
4377c478bd9Sstevel@tonic-gate {
4387c478bd9Sstevel@tonic-gate 	int i;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	if (shr == NULL) {
4417c478bd9Sstevel@tonic-gate 		printf("<NULL>\n");
4427c478bd9Sstevel@tonic-gate 		return;
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	printf("    access(%d):	", shr->s_access);
4467c478bd9Sstevel@tonic-gate 	if (shr->s_access & F_RDACC)
4477c478bd9Sstevel@tonic-gate 		printf("R");
4487c478bd9Sstevel@tonic-gate 	if (shr->s_access & F_WRACC)
4497c478bd9Sstevel@tonic-gate 		printf("W");
4507c478bd9Sstevel@tonic-gate 	if ((shr->s_access & (F_RDACC|F_WRACC)) == 0)
4517c478bd9Sstevel@tonic-gate 		printf("N");
4527c478bd9Sstevel@tonic-gate 	printf("\n");
4537c478bd9Sstevel@tonic-gate 	printf("    deny:	");
4547c478bd9Sstevel@tonic-gate 	if (shr->s_deny & F_COMPAT)
4557c478bd9Sstevel@tonic-gate 		printf("C");
4567c478bd9Sstevel@tonic-gate 	if (shr->s_deny & F_RDDNY)
4577c478bd9Sstevel@tonic-gate 		printf("R");
4587c478bd9Sstevel@tonic-gate 	if (shr->s_deny & F_WRDNY)
4597c478bd9Sstevel@tonic-gate 		printf("W");
4607c478bd9Sstevel@tonic-gate 	if (shr->s_deny == F_NODNY)
4617c478bd9Sstevel@tonic-gate 		printf("N");
4627c478bd9Sstevel@tonic-gate 	printf("\n");
4637c478bd9Sstevel@tonic-gate 	printf("    sysid:	%d\n", shr->s_sysid);
4647c478bd9Sstevel@tonic-gate 	printf("    pid:	%d\n", shr->s_pid);
4657c478bd9Sstevel@tonic-gate 	printf("    owner:	[%d]", shr->s_own_len);
4667c478bd9Sstevel@tonic-gate 	printf("'");
4677c478bd9Sstevel@tonic-gate 	for (i = 0; i < shr->s_own_len; i++)
4687c478bd9Sstevel@tonic-gate 		printf("%02x", (unsigned)shr->s_owner[i]);
4697c478bd9Sstevel@tonic-gate 	printf("'\n");
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate #endif
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate /*
4747c478bd9Sstevel@tonic-gate  * Return non-zero if the given I/O request conflicts with a registered
4757c478bd9Sstevel@tonic-gate  * share reservation.
476da6c28aaSamw  *
477da6c28aaSamw  * A process is identified by the tuple (sysid, pid). When the caller
478da6c28aaSamw  * context is passed to nbl_share_conflict, the sysid and pid in the
479da6c28aaSamw  * caller context are used. Otherwise the sysid is zero, and the pid is
480da6c28aaSamw  * taken from the current process.
481da6c28aaSamw  *
482da6c28aaSamw  * Conflict Algorithm:
483da6c28aaSamw  *   1. An op request of NBL_READ will fail if a different
484da6c28aaSamw  *      process has a mandatory share reservation with deny read.
485da6c28aaSamw  *
486da6c28aaSamw  *   2. An op request of NBL_WRITE will fail if a different
487da6c28aaSamw  *      process has a mandatory share reservation with deny write.
488da6c28aaSamw  *
489da6c28aaSamw  *   3. An op request of NBL_READWRITE will fail if a different
490da6c28aaSamw  *      process has a mandatory share reservation with deny read
491da6c28aaSamw  *      or deny write.
492da6c28aaSamw  *
493da6c28aaSamw  *   4. An op request of NBL_REMOVE will fail if there is
494da6c28aaSamw  *      a mandatory share reservation with an access of read,
495da6c28aaSamw  *      write, or remove. (Anything other than meta data access).
496da6c28aaSamw  *
497da6c28aaSamw  *   5. An op request of NBL_RENAME will fail if there is
498da6c28aaSamw  *      a mandatory share reservation with:
499da6c28aaSamw  *        a) access write or access remove
500da6c28aaSamw  *      or
501da6c28aaSamw  *        b) access read and deny remove
502da6c28aaSamw  *
503da6c28aaSamw  *   Otherwise there is no conflict and the op request succeeds.
504da6c28aaSamw  *
505da6c28aaSamw  * This behavior is required for interoperability between
506da6c28aaSamw  * the nfs server, cifs server, and local access.
507da6c28aaSamw  * This behavior can result in non-posix semantics.
508da6c28aaSamw  *
509da6c28aaSamw  * When mandatory share reservations are enabled, a process
510da6c28aaSamw  * should call nbl_share_conflict to determine if the
511da6c28aaSamw  * desired operation would conflict with an existing share
512da6c28aaSamw  * reservation.
513da6c28aaSamw  *
514da6c28aaSamw  * The call to nbl_share_conflict may be skipped if the
515da6c28aaSamw  * process has an existing share reservation and the operation
516da6c28aaSamw  * is being performed in the context of that existing share
517da6c28aaSamw  * reservation.
5187c478bd9Sstevel@tonic-gate  */
5197c478bd9Sstevel@tonic-gate int
520da6c28aaSamw nbl_share_conflict(vnode_t *vp, nbl_op_t op, caller_context_t *ct)
5217c478bd9Sstevel@tonic-gate {
5227c478bd9Sstevel@tonic-gate 	struct shrlocklist *shrl;
5237c478bd9Sstevel@tonic-gate 	int conflict = 0;
524da6c28aaSamw 	pid_t pid;
525da6c28aaSamw 	int sysid;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	ASSERT(nbl_in_crit(vp));
5287c478bd9Sstevel@tonic-gate 
529da6c28aaSamw 	if (ct == NULL) {
530da6c28aaSamw 		pid = curproc->p_pid;
531da6c28aaSamw 		sysid = 0;
532da6c28aaSamw 	} else {
533da6c28aaSamw 		pid = ct->cc_pid;
534da6c28aaSamw 		sysid = ct->cc_sysid;
535da6c28aaSamw 	}
536da6c28aaSamw 
5377c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
5387c478bd9Sstevel@tonic-gate 	for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
539da6c28aaSamw 		if (!(shrl->shr->s_deny & F_MANDDNY))
540da6c28aaSamw 			continue;
541da6c28aaSamw 		/*
542da6c28aaSamw 		 * NBL_READ, NBL_WRITE, and NBL_READWRITE need to
543da6c28aaSamw 		 * check if the share reservation being examined
544da6c28aaSamw 		 * belongs to the current process.
545da6c28aaSamw 		 * NBL_REMOVE and NBL_RENAME do not.
546da6c28aaSamw 		 * This behavior is required by the conflict
547da6c28aaSamw 		 * algorithm described above.
548da6c28aaSamw 		 */
5497c478bd9Sstevel@tonic-gate 		switch (op) {
5507c478bd9Sstevel@tonic-gate 		case NBL_READ:
551da6c28aaSamw 			if ((shrl->shr->s_deny & F_RDDNY) &&
552da6c28aaSamw 			    (shrl->shr->s_sysid != sysid ||
553da6c28aaSamw 			    shrl->shr->s_pid != pid))
5547c478bd9Sstevel@tonic-gate 				conflict = 1;
5557c478bd9Sstevel@tonic-gate 			break;
5567c478bd9Sstevel@tonic-gate 		case NBL_WRITE:
557da6c28aaSamw 			if ((shrl->shr->s_deny & F_WRDNY) &&
558da6c28aaSamw 			    (shrl->shr->s_sysid != sysid ||
559da6c28aaSamw 			    shrl->shr->s_pid != pid))
5607c478bd9Sstevel@tonic-gate 				conflict = 1;
5617c478bd9Sstevel@tonic-gate 			break;
5627c478bd9Sstevel@tonic-gate 		case NBL_READWRITE:
563da6c28aaSamw 			if ((shrl->shr->s_deny & F_RWDNY) &&
564da6c28aaSamw 			    (shrl->shr->s_sysid != sysid ||
565da6c28aaSamw 			    shrl->shr->s_pid != pid))
566da6c28aaSamw 				conflict = 1;
567da6c28aaSamw 			break;
568da6c28aaSamw 		case NBL_REMOVE:
569da6c28aaSamw 			if (shrl->shr->s_access & (F_RWACC|F_RMACC))
5707c478bd9Sstevel@tonic-gate 				conflict = 1;
5717c478bd9Sstevel@tonic-gate 			break;
5727c478bd9Sstevel@tonic-gate 		case NBL_RENAME:
573da6c28aaSamw 			if (shrl->shr->s_access & (F_WRACC|F_RMACC))
574da6c28aaSamw 				conflict = 1;
575da6c28aaSamw 
576da6c28aaSamw 			else if ((shrl->shr->s_access & F_RDACC) &&
577da6c28aaSamw 			    (shrl->shr->s_deny & F_RMDNY))
5787c478bd9Sstevel@tonic-gate 				conflict = 1;
5797c478bd9Sstevel@tonic-gate 			break;
5807c478bd9Sstevel@tonic-gate #ifdef DEBUG
5817c478bd9Sstevel@tonic-gate 		default:
5827c478bd9Sstevel@tonic-gate 			cmn_err(CE_PANIC,
5837c478bd9Sstevel@tonic-gate 			    "nbl_share_conflict: bogus op (%d)",
5847c478bd9Sstevel@tonic-gate 			    op);
5857c478bd9Sstevel@tonic-gate 			break;
5867c478bd9Sstevel@tonic-gate #endif
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 		if (conflict)
5897c478bd9Sstevel@tonic-gate 			break;
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
5937c478bd9Sstevel@tonic-gate 	return (conflict);
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate /*
5977c478bd9Sstevel@tonic-gate  * Determine if the given process has a NBMAND share reservation on the
5987c478bd9Sstevel@tonic-gate  * given vnode. Returns 1 if the process has such a share reservation,
5997c478bd9Sstevel@tonic-gate  * returns 0 otherwise.
6007c478bd9Sstevel@tonic-gate  */
6017c478bd9Sstevel@tonic-gate int
6027c478bd9Sstevel@tonic-gate proc_has_nbmand_share_on_vp(vnode_t *vp, pid_t pid)
6037c478bd9Sstevel@tonic-gate {
6047c478bd9Sstevel@tonic-gate 	struct shrlocklist *shrl;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	/*
6077c478bd9Sstevel@tonic-gate 	 * Any NBMAND share reservation on the vp for this process?
6087c478bd9Sstevel@tonic-gate 	 */
6097c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
6107c478bd9Sstevel@tonic-gate 	for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
6117c478bd9Sstevel@tonic-gate 		if (shrl->shr->s_sysid == 0 &&
6127c478bd9Sstevel@tonic-gate 		    (shrl->shr->s_deny & F_MANDDNY) &&
6137c478bd9Sstevel@tonic-gate 		    (shrl->shr->s_pid == pid)) {
6147c478bd9Sstevel@tonic-gate 			mutex_exit(&vp->v_lock);
6157c478bd9Sstevel@tonic-gate 			return (1);
6167c478bd9Sstevel@tonic-gate 		}
6177c478bd9Sstevel@tonic-gate 	}
6187c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	return (0);
6217c478bd9Sstevel@tonic-gate }
622