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