10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
55331Samw * Common Development and Distribution License (the "License").
65331Samw * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*7961SNatalie.Li@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/sysmacros.h>
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/fcntl.h>
310Sstevel@tonic-gate #include <sys/vfs.h>
320Sstevel@tonic-gate #include <sys/vnode.h>
330Sstevel@tonic-gate #include <sys/share.h>
340Sstevel@tonic-gate #include <sys/cmn_err.h>
350Sstevel@tonic-gate #include <sys/kmem.h>
360Sstevel@tonic-gate #include <sys/debug.h>
370Sstevel@tonic-gate #include <sys/t_lock.h>
380Sstevel@tonic-gate #include <sys/errno.h>
390Sstevel@tonic-gate #include <sys/nbmlock.h>
400Sstevel@tonic-gate
410Sstevel@tonic-gate int share_debug = 0;
420Sstevel@tonic-gate
430Sstevel@tonic-gate #ifdef DEBUG
440Sstevel@tonic-gate static void print_shares(struct vnode *);
450Sstevel@tonic-gate static void print_share(struct shrlock *);
460Sstevel@tonic-gate #endif
470Sstevel@tonic-gate
480Sstevel@tonic-gate static int isreadonly(struct vnode *);
490Sstevel@tonic-gate
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate * Add the share reservation shr to vp.
520Sstevel@tonic-gate */
530Sstevel@tonic-gate int
add_share(struct vnode * vp,struct shrlock * shr)540Sstevel@tonic-gate add_share(struct vnode *vp, struct shrlock *shr)
550Sstevel@tonic-gate {
560Sstevel@tonic-gate struct shrlocklist *shrl;
570Sstevel@tonic-gate
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate * An access of zero is not legal, however some older clients
600Sstevel@tonic-gate * generate it anyways. Allow the request only if it is
610Sstevel@tonic-gate * coming from a remote system. Be generous in what you
620Sstevel@tonic-gate * accept and strict in what you send.
630Sstevel@tonic-gate */
640Sstevel@tonic-gate if ((shr->s_access == 0) && (GETSYSID(shr->s_sysid) == 0)) {
650Sstevel@tonic-gate return (EINVAL);
660Sstevel@tonic-gate }
670Sstevel@tonic-gate
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate * Sanity check to make sure we have valid options.
700Sstevel@tonic-gate * There is known overlap but it doesn't hurt to be careful.
710Sstevel@tonic-gate */
725331Samw if (shr->s_access & ~(F_RDACC|F_WRACC|F_RWACC|F_RMACC|F_MDACC)) {
730Sstevel@tonic-gate return (EINVAL);
740Sstevel@tonic-gate }
750Sstevel@tonic-gate if (shr->s_deny & ~(F_NODNY|F_RDDNY|F_WRDNY|F_RWDNY|F_COMPAT|
765331Samw F_MANDDNY|F_RMDNY)) {
770Sstevel@tonic-gate return (EINVAL);
780Sstevel@tonic-gate }
790Sstevel@tonic-gate
800Sstevel@tonic-gate mutex_enter(&vp->v_lock);
810Sstevel@tonic-gate for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
820Sstevel@tonic-gate /*
830Sstevel@tonic-gate * If the share owner matches previous request
840Sstevel@tonic-gate * do special handling.
850Sstevel@tonic-gate */
860Sstevel@tonic-gate if ((shrl->shr->s_sysid == shr->s_sysid) &&
870Sstevel@tonic-gate (shrl->shr->s_pid == shr->s_pid) &&
880Sstevel@tonic-gate (shrl->shr->s_own_len == shr->s_own_len) &&
890Sstevel@tonic-gate bcmp(shrl->shr->s_owner, shr->s_owner,
900Sstevel@tonic-gate shr->s_own_len) == 0) {
910Sstevel@tonic-gate
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate * If the existing request is F_COMPAT and
940Sstevel@tonic-gate * is the first share then allow any F_COMPAT
950Sstevel@tonic-gate * from the same process. Trick: If the existing
960Sstevel@tonic-gate * F_COMPAT is write access then it must have
970Sstevel@tonic-gate * the same owner as the first.
980Sstevel@tonic-gate */
990Sstevel@tonic-gate if ((shrl->shr->s_deny & F_COMPAT) &&
1000Sstevel@tonic-gate (shr->s_deny & F_COMPAT) &&
1010Sstevel@tonic-gate ((shrl->next == NULL) ||
1025331Samw (shrl->shr->s_access & F_WRACC)))
1030Sstevel@tonic-gate break;
1040Sstevel@tonic-gate }
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate /*
1070Sstevel@tonic-gate * If a first share has been done in compatibility mode
1080Sstevel@tonic-gate * handle the special cases.
1090Sstevel@tonic-gate */
1100Sstevel@tonic-gate if ((shrl->shr->s_deny & F_COMPAT) && (shrl->next == NULL)) {
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate if (!(shr->s_deny & F_COMPAT)) {
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate * If not compat and want write access or
1150Sstevel@tonic-gate * want to deny read or
1160Sstevel@tonic-gate * write exists, fails
1170Sstevel@tonic-gate */
1180Sstevel@tonic-gate if ((shr->s_access & F_WRACC) ||
1190Sstevel@tonic-gate (shr->s_deny & F_RDDNY) ||
1200Sstevel@tonic-gate (shrl->shr->s_access & F_WRACC)) {
1210Sstevel@tonic-gate mutex_exit(&vp->v_lock);
1220Sstevel@tonic-gate return (EAGAIN);
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate * If read only file allow, this may allow
1260Sstevel@tonic-gate * a deny write but that is meaningless on
1270Sstevel@tonic-gate * a read only file.
1280Sstevel@tonic-gate */
1290Sstevel@tonic-gate if (isreadonly(vp))
1300Sstevel@tonic-gate break;
1310Sstevel@tonic-gate mutex_exit(&vp->v_lock);
1320Sstevel@tonic-gate return (EAGAIN);
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate * This is a compat request and read access
1360Sstevel@tonic-gate * and the first was also read access
1370Sstevel@tonic-gate * we always allow it, otherwise we reject because
1380Sstevel@tonic-gate * we have handled the only valid write case above.
1390Sstevel@tonic-gate */
1400Sstevel@tonic-gate if ((shr->s_access == F_RDACC) &&
1410Sstevel@tonic-gate (shrl->shr->s_access == F_RDACC))
1420Sstevel@tonic-gate break;
1430Sstevel@tonic-gate mutex_exit(&vp->v_lock);
1440Sstevel@tonic-gate return (EAGAIN);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate /*
1480Sstevel@tonic-gate * If we are trying to share in compatibility mode
1490Sstevel@tonic-gate * and the current share is compat (and not the first)
1500Sstevel@tonic-gate * we don't know enough.
1510Sstevel@tonic-gate */
1520Sstevel@tonic-gate if ((shrl->shr->s_deny & F_COMPAT) && (shr->s_deny & F_COMPAT))
1530Sstevel@tonic-gate continue;
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate /*
1560Sstevel@tonic-gate * If this is a compat we check for what can't succeed.
1570Sstevel@tonic-gate */
1580Sstevel@tonic-gate if (shr->s_deny & F_COMPAT) {
1590Sstevel@tonic-gate /*
1600Sstevel@tonic-gate * If we want write access or
1610Sstevel@tonic-gate * if anyone is denying read or
1620Sstevel@tonic-gate * if anyone has write access we fail
1630Sstevel@tonic-gate */
1640Sstevel@tonic-gate if ((shr->s_access & F_WRACC) ||
1650Sstevel@tonic-gate (shrl->shr->s_deny & F_RDDNY) ||
1660Sstevel@tonic-gate (shrl->shr->s_access & F_WRACC)) {
1670Sstevel@tonic-gate mutex_exit(&vp->v_lock);
1680Sstevel@tonic-gate return (EAGAIN);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate * If the first was opened with only read access
1720Sstevel@tonic-gate * and is a read only file we allow.
1730Sstevel@tonic-gate */
1740Sstevel@tonic-gate if (shrl->next == NULL) {
1750Sstevel@tonic-gate if ((shrl->shr->s_access == F_RDACC) &&
1760Sstevel@tonic-gate isreadonly(vp)) {
1770Sstevel@tonic-gate break;
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate mutex_exit(&vp->v_lock);
1800Sstevel@tonic-gate return (EAGAIN);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate /*
1830Sstevel@tonic-gate * We still can't determine our fate so continue
1840Sstevel@tonic-gate */
1850Sstevel@tonic-gate continue;
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate /*
1890Sstevel@tonic-gate * Simple bitwise test, if we are trying to access what
1900Sstevel@tonic-gate * someone else is denying or we are trying to deny
1910Sstevel@tonic-gate * what someone else is accessing we fail.
1920Sstevel@tonic-gate */
1930Sstevel@tonic-gate if ((shr->s_access & shrl->shr->s_deny) ||
1940Sstevel@tonic-gate (shr->s_deny & shrl->shr->s_access)) {
1950Sstevel@tonic-gate mutex_exit(&vp->v_lock);
1960Sstevel@tonic-gate return (EAGAIN);
1970Sstevel@tonic-gate }
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate shrl = kmem_alloc(sizeof (struct shrlocklist), KM_SLEEP);
2010Sstevel@tonic-gate shrl->shr = kmem_alloc(sizeof (struct shrlock), KM_SLEEP);
2020Sstevel@tonic-gate shrl->shr->s_access = shr->s_access;
2030Sstevel@tonic-gate shrl->shr->s_deny = shr->s_deny;
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate /*
2060Sstevel@tonic-gate * Make sure no other deny modes are also set with F_COMPAT
2070Sstevel@tonic-gate */
2080Sstevel@tonic-gate if (shrl->shr->s_deny & F_COMPAT)
2090Sstevel@tonic-gate shrl->shr->s_deny = F_COMPAT;
2100Sstevel@tonic-gate shrl->shr->s_sysid = shr->s_sysid; /* XXX ref cnt? */
2110Sstevel@tonic-gate shrl->shr->s_pid = shr->s_pid;
2120Sstevel@tonic-gate shrl->shr->s_own_len = shr->s_own_len;
2130Sstevel@tonic-gate shrl->shr->s_owner = kmem_alloc(shr->s_own_len, KM_SLEEP);
2140Sstevel@tonic-gate bcopy(shr->s_owner, shrl->shr->s_owner, shr->s_own_len);
2150Sstevel@tonic-gate shrl->next = vp->v_shrlocks;
2160Sstevel@tonic-gate vp->v_shrlocks = shrl;
2170Sstevel@tonic-gate #ifdef DEBUG
2180Sstevel@tonic-gate if (share_debug)
2190Sstevel@tonic-gate print_shares(vp);
2200Sstevel@tonic-gate #endif
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate mutex_exit(&vp->v_lock);
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate return (0);
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate /*
2280Sstevel@tonic-gate * nlmid sysid pid
2290Sstevel@tonic-gate * ===== ===== ===
2300Sstevel@tonic-gate * !=0 !=0 =0 in cluster; NLM lock
2310Sstevel@tonic-gate * !=0 =0 =0 in cluster; special case for NLM lock
2320Sstevel@tonic-gate * !=0 =0 !=0 in cluster; PXFS local lock
2330Sstevel@tonic-gate * !=0 !=0 !=0 cannot happen
2340Sstevel@tonic-gate * =0 !=0 =0 not in cluster; NLM lock
2350Sstevel@tonic-gate * =0 =0 !=0 not in cluster; local lock
2360Sstevel@tonic-gate * =0 =0 =0 cannot happen
2370Sstevel@tonic-gate * =0 !=0 !=0 cannot happen
2380Sstevel@tonic-gate */
2390Sstevel@tonic-gate static int
is_match_for_del(struct shrlock * shr,struct shrlock * element)2400Sstevel@tonic-gate is_match_for_del(struct shrlock *shr, struct shrlock *element)
2410Sstevel@tonic-gate {
2420Sstevel@tonic-gate int nlmid1, nlmid2;
2430Sstevel@tonic-gate int result = 0;
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate nlmid1 = GETNLMID(shr->s_sysid);
2460Sstevel@tonic-gate nlmid2 = GETNLMID(element->s_sysid);
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate if (nlmid1 != 0) { /* in a cluster */
2490Sstevel@tonic-gate if (GETSYSID(shr->s_sysid) != 0 && shr->s_pid == 0) {
2500Sstevel@tonic-gate /*
2510Sstevel@tonic-gate * Lock obtained through nlm server. Just need to
2520Sstevel@tonic-gate * compare whole sysids. pid will always = 0.
2530Sstevel@tonic-gate */
2540Sstevel@tonic-gate result = shr->s_sysid == element->s_sysid;
2550Sstevel@tonic-gate } else if (GETSYSID(shr->s_sysid) == 0 && shr->s_pid == 0) {
2560Sstevel@tonic-gate /*
2570Sstevel@tonic-gate * This is a special case. The NLM server wishes to
2580Sstevel@tonic-gate * delete all share locks obtained through nlmid1.
2590Sstevel@tonic-gate */
2600Sstevel@tonic-gate result = (nlmid1 == nlmid2);
2610Sstevel@tonic-gate } else if (GETSYSID(shr->s_sysid) == 0 && shr->s_pid != 0) {
2620Sstevel@tonic-gate /*
2630Sstevel@tonic-gate * Lock obtained locally through PXFS. Match nlmids
2640Sstevel@tonic-gate * and pids.
2650Sstevel@tonic-gate */
2660Sstevel@tonic-gate result = (nlmid1 == nlmid2 &&
2675331Samw shr->s_pid == element->s_pid);
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate } else { /* not in a cluster */
2700Sstevel@tonic-gate result = ((shr->s_sysid == 0 &&
2715331Samw shr->s_pid == element->s_pid) ||
2725331Samw (shr->s_sysid != 0 &&
2735331Samw shr->s_sysid == element->s_sysid));
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate return (result);
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate * Delete the given share reservation. Returns 0 if okay, EINVAL if the
2800Sstevel@tonic-gate * share could not be found. If the share reservation is an NBMAND share
2810Sstevel@tonic-gate * reservation, signal anyone waiting for the share to go away (e.g.,
2820Sstevel@tonic-gate * blocking lock requests).
2830Sstevel@tonic-gate */
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate int
del_share(struct vnode * vp,struct shrlock * shr)2860Sstevel@tonic-gate del_share(struct vnode *vp, struct shrlock *shr)
2870Sstevel@tonic-gate {
2880Sstevel@tonic-gate struct shrlocklist *shrl;
2890Sstevel@tonic-gate struct shrlocklist **shrlp;
2900Sstevel@tonic-gate int found = 0;
2910Sstevel@tonic-gate int is_nbmand = 0;
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate mutex_enter(&vp->v_lock);
2940Sstevel@tonic-gate /*
2950Sstevel@tonic-gate * Delete the shares with the matching sysid and owner
2960Sstevel@tonic-gate * But if own_len == 0 and sysid == 0 delete all with matching pid
2970Sstevel@tonic-gate * But if own_len == 0 delete all with matching sysid.
2980Sstevel@tonic-gate */
2990Sstevel@tonic-gate shrlp = &vp->v_shrlocks;
3000Sstevel@tonic-gate while (*shrlp) {
3010Sstevel@tonic-gate if ((shr->s_own_len == (*shrlp)->shr->s_own_len &&
3025331Samw (bcmp(shr->s_owner, (*shrlp)->shr->s_owner,
3035331Samw shr->s_own_len) == 0)) ||
3040Sstevel@tonic-gate
3055331Samw (shr->s_own_len == 0 &&
3065331Samw is_match_for_del(shr, (*shrlp)->shr))) {
3070Sstevel@tonic-gate
3080Sstevel@tonic-gate shrl = *shrlp;
3090Sstevel@tonic-gate *shrlp = shrl->next;
3100Sstevel@tonic-gate
3110Sstevel@tonic-gate if (shrl->shr->s_deny & F_MANDDNY)
3120Sstevel@tonic-gate is_nbmand = 1;
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate /* XXX deref sysid */
3150Sstevel@tonic-gate kmem_free(shrl->shr->s_owner, shrl->shr->s_own_len);
3160Sstevel@tonic-gate kmem_free(shrl->shr, sizeof (struct shrlock));
3170Sstevel@tonic-gate kmem_free(shrl, sizeof (struct shrlocklist));
3180Sstevel@tonic-gate found++;
3190Sstevel@tonic-gate continue;
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate shrlp = &(*shrlp)->next;
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate if (is_nbmand)
3250Sstevel@tonic-gate cv_broadcast(&vp->v_cv);
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate mutex_exit(&vp->v_lock);
3280Sstevel@tonic-gate return (found ? 0 : EINVAL);
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate /*
3320Sstevel@tonic-gate * Clean up all local share reservations that the given process has with
3330Sstevel@tonic-gate * the given file.
3340Sstevel@tonic-gate */
3350Sstevel@tonic-gate void
cleanshares(struct vnode * vp,pid_t pid)3360Sstevel@tonic-gate cleanshares(struct vnode *vp, pid_t pid)
3370Sstevel@tonic-gate {
3380Sstevel@tonic-gate struct shrlock shr;
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate if (vp->v_shrlocks == NULL)
3410Sstevel@tonic-gate return;
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate shr.s_access = 0;
3440Sstevel@tonic-gate shr.s_deny = 0;
3450Sstevel@tonic-gate shr.s_pid = pid;
3460Sstevel@tonic-gate shr.s_sysid = 0;
3470Sstevel@tonic-gate shr.s_own_len = 0;
3480Sstevel@tonic-gate shr.s_owner = NULL;
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate (void) del_share(vp, &shr);
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate static int
is_match_for_has_remote(int32_t sysid1,int32_t sysid2)3540Sstevel@tonic-gate is_match_for_has_remote(int32_t sysid1, int32_t sysid2)
3550Sstevel@tonic-gate {
3560Sstevel@tonic-gate int result = 0;
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate if (GETNLMID(sysid1) != 0) { /* in a cluster */
3590Sstevel@tonic-gate if (GETSYSID(sysid1) != 0) {
3600Sstevel@tonic-gate /*
3610Sstevel@tonic-gate * Lock obtained through nlm server. Just need to
3620Sstevel@tonic-gate * compare whole sysids.
3630Sstevel@tonic-gate */
3640Sstevel@tonic-gate result = (sysid1 == sysid2);
3650Sstevel@tonic-gate } else if (GETSYSID(sysid1) == 0) {
3660Sstevel@tonic-gate /*
3670Sstevel@tonic-gate * This is a special case. The NLM server identified
3680Sstevel@tonic-gate * by nlmid1 wishes to find out if it has obtained
3690Sstevel@tonic-gate * any share locks on the vnode.
3700Sstevel@tonic-gate */
3710Sstevel@tonic-gate result = (GETNLMID(sysid1) == GETNLMID(sysid2));
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate } else { /* not in a cluster */
3740Sstevel@tonic-gate result = ((sysid1 != 0 && sysid1 == sysid2) ||
3750Sstevel@tonic-gate (sysid1 == 0 && sysid2 != 0));
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate return (result);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate * Determine whether there are any shares for the given vnode
3830Sstevel@tonic-gate * with a remote sysid. Returns zero if not, non-zero if there are.
3840Sstevel@tonic-gate * If sysid is non-zero then determine if this sysid has a share.
3850Sstevel@tonic-gate *
3860Sstevel@tonic-gate * Note that the return value from this function is potentially invalid
3870Sstevel@tonic-gate * once it has been returned. The caller is responsible for providing its
3880Sstevel@tonic-gate * own synchronization mechanism to ensure that the return value is useful.
3890Sstevel@tonic-gate */
3900Sstevel@tonic-gate int
shr_has_remote_shares(vnode_t * vp,int32_t sysid)3910Sstevel@tonic-gate shr_has_remote_shares(vnode_t *vp, int32_t sysid)
3920Sstevel@tonic-gate {
3930Sstevel@tonic-gate struct shrlocklist *shrl;
3940Sstevel@tonic-gate int result = 0;
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate mutex_enter(&vp->v_lock);
3970Sstevel@tonic-gate shrl = vp->v_shrlocks;
3980Sstevel@tonic-gate while (shrl) {
3990Sstevel@tonic-gate if (is_match_for_has_remote(sysid, shrl->shr->s_sysid)) {
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate result = 1;
4020Sstevel@tonic-gate break;
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate shrl = shrl->next;
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate mutex_exit(&vp->v_lock);
4070Sstevel@tonic-gate return (result);
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate static int
isreadonly(struct vnode * vp)4110Sstevel@tonic-gate isreadonly(struct vnode *vp)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate return (vp->v_type != VCHR && vp->v_type != VBLK &&
4145331Samw vp->v_type != VFIFO && vn_is_readonly(vp));
4150Sstevel@tonic-gate }
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate #ifdef DEBUG
4180Sstevel@tonic-gate static void
print_shares(struct vnode * vp)4190Sstevel@tonic-gate print_shares(struct vnode *vp)
4200Sstevel@tonic-gate {
4210Sstevel@tonic-gate struct shrlocklist *shrl;
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate if (vp->v_shrlocks == NULL) {
4240Sstevel@tonic-gate printf("<NULL>\n");
4250Sstevel@tonic-gate return;
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate shrl = vp->v_shrlocks;
4290Sstevel@tonic-gate while (shrl) {
4300Sstevel@tonic-gate print_share(shrl->shr);
4310Sstevel@tonic-gate shrl = shrl->next;
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate static void
print_share(struct shrlock * shr)4360Sstevel@tonic-gate print_share(struct shrlock *shr)
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate int i;
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate if (shr == NULL) {
4410Sstevel@tonic-gate printf("<NULL>\n");
4420Sstevel@tonic-gate return;
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate printf(" access(%d): ", shr->s_access);
4460Sstevel@tonic-gate if (shr->s_access & F_RDACC)
4470Sstevel@tonic-gate printf("R");
4480Sstevel@tonic-gate if (shr->s_access & F_WRACC)
4490Sstevel@tonic-gate printf("W");
4500Sstevel@tonic-gate if ((shr->s_access & (F_RDACC|F_WRACC)) == 0)
4510Sstevel@tonic-gate printf("N");
4520Sstevel@tonic-gate printf("\n");
4530Sstevel@tonic-gate printf(" deny: ");
4540Sstevel@tonic-gate if (shr->s_deny & F_COMPAT)
4550Sstevel@tonic-gate printf("C");
4560Sstevel@tonic-gate if (shr->s_deny & F_RDDNY)
4570Sstevel@tonic-gate printf("R");
4580Sstevel@tonic-gate if (shr->s_deny & F_WRDNY)
4590Sstevel@tonic-gate printf("W");
4600Sstevel@tonic-gate if (shr->s_deny == F_NODNY)
4610Sstevel@tonic-gate printf("N");
4620Sstevel@tonic-gate printf("\n");
4630Sstevel@tonic-gate printf(" sysid: %d\n", shr->s_sysid);
4640Sstevel@tonic-gate printf(" pid: %d\n", shr->s_pid);
4650Sstevel@tonic-gate printf(" owner: [%d]", shr->s_own_len);
4660Sstevel@tonic-gate printf("'");
4670Sstevel@tonic-gate for (i = 0; i < shr->s_own_len; i++)
4680Sstevel@tonic-gate printf("%02x", (unsigned)shr->s_owner[i]);
4690Sstevel@tonic-gate printf("'\n");
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate #endif
4720Sstevel@tonic-gate
4730Sstevel@tonic-gate /*
4740Sstevel@tonic-gate * Return non-zero if the given I/O request conflicts with a registered
4750Sstevel@tonic-gate * share reservation.
4765331Samw *
4775331Samw * A process is identified by the tuple (sysid, pid). When the caller
4785331Samw * context is passed to nbl_share_conflict, the sysid and pid in the
4795331Samw * caller context are used. Otherwise the sysid is zero, and the pid is
4805331Samw * taken from the current process.
4815331Samw *
4825331Samw * Conflict Algorithm:
4835331Samw * 1. An op request of NBL_READ will fail if a different
4845331Samw * process has a mandatory share reservation with deny read.
4855331Samw *
4865331Samw * 2. An op request of NBL_WRITE will fail if a different
4875331Samw * process has a mandatory share reservation with deny write.
4885331Samw *
4895331Samw * 3. An op request of NBL_READWRITE will fail if a different
4905331Samw * process has a mandatory share reservation with deny read
4915331Samw * or deny write.
4925331Samw *
4935331Samw * 4. An op request of NBL_REMOVE will fail if there is
4945331Samw * a mandatory share reservation with an access of read,
4955331Samw * write, or remove. (Anything other than meta data access).
4965331Samw *
4975331Samw * 5. An op request of NBL_RENAME will fail if there is
4985331Samw * a mandatory share reservation with:
4995331Samw * a) access write or access remove
5005331Samw * or
5015331Samw * b) access read and deny remove
5025331Samw *
5035331Samw * Otherwise there is no conflict and the op request succeeds.
5045331Samw *
5055331Samw * This behavior is required for interoperability between
5065331Samw * the nfs server, cifs server, and local access.
5075331Samw * This behavior can result in non-posix semantics.
5085331Samw *
5095331Samw * When mandatory share reservations are enabled, a process
5105331Samw * should call nbl_share_conflict to determine if the
5115331Samw * desired operation would conflict with an existing share
5125331Samw * reservation.
5135331Samw *
5145331Samw * The call to nbl_share_conflict may be skipped if the
5155331Samw * process has an existing share reservation and the operation
5165331Samw * is being performed in the context of that existing share
5175331Samw * reservation.
5180Sstevel@tonic-gate */
5190Sstevel@tonic-gate int
nbl_share_conflict(vnode_t * vp,nbl_op_t op,caller_context_t * ct)5205331Samw nbl_share_conflict(vnode_t *vp, nbl_op_t op, caller_context_t *ct)
5210Sstevel@tonic-gate {
5220Sstevel@tonic-gate struct shrlocklist *shrl;
5230Sstevel@tonic-gate int conflict = 0;
5245331Samw pid_t pid;
5255331Samw int sysid;
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate ASSERT(nbl_in_crit(vp));
5280Sstevel@tonic-gate
5295331Samw if (ct == NULL) {
5305331Samw pid = curproc->p_pid;
5315331Samw sysid = 0;
5325331Samw } else {
5335331Samw pid = ct->cc_pid;
5345331Samw sysid = ct->cc_sysid;
5355331Samw }
5365331Samw
5370Sstevel@tonic-gate mutex_enter(&vp->v_lock);
5380Sstevel@tonic-gate for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
5395331Samw if (!(shrl->shr->s_deny & F_MANDDNY))
5405331Samw continue;
5415331Samw /*
5425331Samw * NBL_READ, NBL_WRITE, and NBL_READWRITE need to
5435331Samw * check if the share reservation being examined
5445331Samw * belongs to the current process.
5455331Samw * NBL_REMOVE and NBL_RENAME do not.
5465331Samw * This behavior is required by the conflict
5475331Samw * algorithm described above.
5485331Samw */
5495331Samw switch (op) {
5505331Samw case NBL_READ:
5515331Samw if ((shrl->shr->s_deny & F_RDDNY) &&
5525331Samw (shrl->shr->s_sysid != sysid ||
5535331Samw shrl->shr->s_pid != pid))
5545331Samw conflict = 1;
5555331Samw break;
5565331Samw case NBL_WRITE:
5575331Samw if ((shrl->shr->s_deny & F_WRDNY) &&
5585331Samw (shrl->shr->s_sysid != sysid ||
5595331Samw shrl->shr->s_pid != pid))
5600Sstevel@tonic-gate conflict = 1;
5615331Samw break;
5625331Samw case NBL_READWRITE:
5635331Samw if ((shrl->shr->s_deny & F_RWDNY) &&
5645331Samw (shrl->shr->s_sysid != sysid ||
5655331Samw shrl->shr->s_pid != pid))
5665331Samw conflict = 1;
5675331Samw break;
5685331Samw case NBL_REMOVE:
5695331Samw if (shrl->shr->s_access & (F_RWACC|F_RMACC))
5705331Samw conflict = 1;
5715331Samw break;
5725331Samw case NBL_RENAME:
5735331Samw if (shrl->shr->s_access & (F_WRACC|F_RMACC))
5745331Samw conflict = 1;
5755331Samw
5765331Samw else if ((shrl->shr->s_access & F_RDACC) &&
5775331Samw (shrl->shr->s_deny & F_RMDNY))
5785331Samw conflict = 1;
5795331Samw break;
5800Sstevel@tonic-gate #ifdef DEBUG
5815331Samw default:
5825331Samw cmn_err(CE_PANIC,
5835331Samw "nbl_share_conflict: bogus op (%d)",
5845331Samw op);
5855331Samw break;
5860Sstevel@tonic-gate #endif
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate if (conflict)
5890Sstevel@tonic-gate break;
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate
5920Sstevel@tonic-gate mutex_exit(&vp->v_lock);
5930Sstevel@tonic-gate return (conflict);
5940Sstevel@tonic-gate }
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate /*
5970Sstevel@tonic-gate * Determine if the given process has a NBMAND share reservation on the
5980Sstevel@tonic-gate * given vnode. Returns 1 if the process has such a share reservation,
5990Sstevel@tonic-gate * returns 0 otherwise.
6000Sstevel@tonic-gate */
6010Sstevel@tonic-gate int
proc_has_nbmand_share_on_vp(vnode_t * vp,pid_t pid)6020Sstevel@tonic-gate proc_has_nbmand_share_on_vp(vnode_t *vp, pid_t pid)
6030Sstevel@tonic-gate {
6040Sstevel@tonic-gate struct shrlocklist *shrl;
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate /*
6070Sstevel@tonic-gate * Any NBMAND share reservation on the vp for this process?
6080Sstevel@tonic-gate */
6090Sstevel@tonic-gate mutex_enter(&vp->v_lock);
6100Sstevel@tonic-gate for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
6110Sstevel@tonic-gate if (shrl->shr->s_sysid == 0 &&
6120Sstevel@tonic-gate (shrl->shr->s_deny & F_MANDDNY) &&
6130Sstevel@tonic-gate (shrl->shr->s_pid == pid)) {
6140Sstevel@tonic-gate mutex_exit(&vp->v_lock);
6150Sstevel@tonic-gate return (1);
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate mutex_exit(&vp->v_lock);
6190Sstevel@tonic-gate
6200Sstevel@tonic-gate return (0);
6210Sstevel@tonic-gate }
622