1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright (c) 2001 by Sun Microsystems, Inc. 24*7c478bd9Sstevel@tonic-gate * All rights reserved. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Utility routines and top-level conflict detection code for NBMAND 31*7c478bd9Sstevel@tonic-gate * locks. 32*7c478bd9Sstevel@tonic-gate */ 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/rwlock.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/fcntl.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate /* 43*7c478bd9Sstevel@tonic-gate * Enter the critical region for synchronizing I/O requests with lock/share 44*7c478bd9Sstevel@tonic-gate * requests. "mode" specifies whether the caller intends to update 45*7c478bd9Sstevel@tonic-gate * lock/share state (as opposed to just query it). 46*7c478bd9Sstevel@tonic-gate */ 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate void 49*7c478bd9Sstevel@tonic-gate nbl_start_crit(vnode_t *vp, krw_t mode) 50*7c478bd9Sstevel@tonic-gate { 51*7c478bd9Sstevel@tonic-gate rw_enter(&vp->v_nbllock, mode); 52*7c478bd9Sstevel@tonic-gate } 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate /* 55*7c478bd9Sstevel@tonic-gate * Leave the critical region. 56*7c478bd9Sstevel@tonic-gate */ 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate void 59*7c478bd9Sstevel@tonic-gate nbl_end_crit(vnode_t *vp) 60*7c478bd9Sstevel@tonic-gate { 61*7c478bd9Sstevel@tonic-gate rw_exit(&vp->v_nbllock); 62*7c478bd9Sstevel@tonic-gate } 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate * Return non-zero if some thread is in the critical region. 66*7c478bd9Sstevel@tonic-gate * Note that this is appropriate for use in ASSERT()s only. 67*7c478bd9Sstevel@tonic-gate */ 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate int 70*7c478bd9Sstevel@tonic-gate nbl_in_crit(vnode_t *vp) 71*7c478bd9Sstevel@tonic-gate { 72*7c478bd9Sstevel@tonic-gate return (RW_LOCK_HELD(&vp->v_nbllock)); 73*7c478bd9Sstevel@tonic-gate } 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate /* 76*7c478bd9Sstevel@tonic-gate * Return the nbl_op_t that corresponds to the given lock type (read or 77*7c478bd9Sstevel@tonic-gate * write). 78*7c478bd9Sstevel@tonic-gate */ 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate nbl_op_t 81*7c478bd9Sstevel@tonic-gate nbl_lock_to_op(int lock_type) 82*7c478bd9Sstevel@tonic-gate { 83*7c478bd9Sstevel@tonic-gate int level; 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate switch (lock_type) { 86*7c478bd9Sstevel@tonic-gate case F_WRLCK: 87*7c478bd9Sstevel@tonic-gate return (NBL_READWRITE); 88*7c478bd9Sstevel@tonic-gate case F_RDLCK: 89*7c478bd9Sstevel@tonic-gate return (NBL_READ); 90*7c478bd9Sstevel@tonic-gate default: 91*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 92*7c478bd9Sstevel@tonic-gate level = CE_PANIC; 93*7c478bd9Sstevel@tonic-gate #else 94*7c478bd9Sstevel@tonic-gate level = CE_WARN; 95*7c478bd9Sstevel@tonic-gate #endif 96*7c478bd9Sstevel@tonic-gate cmn_err(level, "unexpected lock type: %d\n", lock_type); 97*7c478bd9Sstevel@tonic-gate return (NBL_WRITE); /* pick something restrictive */ 98*7c478bd9Sstevel@tonic-gate } 99*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 100*7c478bd9Sstevel@tonic-gate } 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate /* 103*7c478bd9Sstevel@tonic-gate * Returns non-zero if we need to look further for an NBMAND lock or 104*7c478bd9Sstevel@tonic-gate * share conflict. 105*7c478bd9Sstevel@tonic-gate */ 106*7c478bd9Sstevel@tonic-gate int 107*7c478bd9Sstevel@tonic-gate nbl_need_check(vnode_t *vp) 108*7c478bd9Sstevel@tonic-gate { 109*7c478bd9Sstevel@tonic-gate /* 110*7c478bd9Sstevel@tonic-gate * Currently we only check if NBMAND locks/shares are allowed on 111*7c478bd9Sstevel@tonic-gate * the filesystem. An option for the future would be to have a 112*7c478bd9Sstevel@tonic-gate * flag on the vnode, though the locking for that can get tricky. 113*7c478bd9Sstevel@tonic-gate */ 114*7c478bd9Sstevel@tonic-gate return ((vp->v_vfsp) && (vp->v_vfsp->vfs_flag & VFS_NBMAND)); 115*7c478bd9Sstevel@tonic-gate } 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate /* 118*7c478bd9Sstevel@tonic-gate * Top-level conflict detection routine. The arguments describe the 119*7c478bd9Sstevel@tonic-gate * operation that is being attempted. If the operation conflicts with an 120*7c478bd9Sstevel@tonic-gate * existing lock or share reservation, a non-zero value is returned. If 121*7c478bd9Sstevel@tonic-gate * the operation is allowed, zero is returned. Note that there is an 122*7c478bd9Sstevel@tonic-gate * implicit argument, which is the process ID of the requester. 123*7c478bd9Sstevel@tonic-gate * 124*7c478bd9Sstevel@tonic-gate * svmand indicates that the file has System V mandatory locking enabled, 125*7c478bd9Sstevel@tonic-gate * so we should look at all record locks, not just NBMAND record locks. 126*7c478bd9Sstevel@tonic-gate * (This is to avoid a deadlock between a process making an I/O request and 127*7c478bd9Sstevel@tonic-gate * a process trying to release a lock. Instead of letting the first 128*7c478bd9Sstevel@tonic-gate * process block in the filesystem code, we flag a conflict here.) 129*7c478bd9Sstevel@tonic-gate */ 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate int 132*7c478bd9Sstevel@tonic-gate nbl_conflict(vnode_t *vp, 133*7c478bd9Sstevel@tonic-gate nbl_op_t op, /* attempted operation */ 134*7c478bd9Sstevel@tonic-gate u_offset_t offset, /* ignore if not I/O */ 135*7c478bd9Sstevel@tonic-gate ssize_t length, /* ignore if not I/O */ 136*7c478bd9Sstevel@tonic-gate int svmand) /* System V mandatory locking */ 137*7c478bd9Sstevel@tonic-gate { 138*7c478bd9Sstevel@tonic-gate ASSERT(nbl_in_crit(vp)); 139*7c478bd9Sstevel@tonic-gate ASSERT(op == NBL_READ || op == NBL_WRITE || op == NBL_RENAME || 140*7c478bd9Sstevel@tonic-gate op == NBL_REMOVE || op == NBL_READWRITE); 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate if (nbl_share_conflict(vp, op)) { 143*7c478bd9Sstevel@tonic-gate return (1); 144*7c478bd9Sstevel@tonic-gate } 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /* 147*7c478bd9Sstevel@tonic-gate * If this is not an I/O request, there's no need to check against 148*7c478bd9Sstevel@tonic-gate * the locks on the file. 149*7c478bd9Sstevel@tonic-gate */ 150*7c478bd9Sstevel@tonic-gate if (op == NBL_REMOVE || op == NBL_RENAME) 151*7c478bd9Sstevel@tonic-gate return (0); 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate return (nbl_lock_conflict(vp, op, offset, length, svmand)); 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate /* 157*7c478bd9Sstevel@tonic-gate * Determine if the given file has mode bits for System V mandatory locks. 158*7c478bd9Sstevel@tonic-gate * If there was an error, the errno value is returned. Otherwise, zero is 159*7c478bd9Sstevel@tonic-gate * returned and *svp is set appropriately (non-zero for mandatory locks, 160*7c478bd9Sstevel@tonic-gate * zero for no mandatory locks). 161*7c478bd9Sstevel@tonic-gate */ 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate int 164*7c478bd9Sstevel@tonic-gate nbl_svmand(vnode_t *vp, cred_t *cr, int *svp) 165*7c478bd9Sstevel@tonic-gate { 166*7c478bd9Sstevel@tonic-gate struct vattr va; 167*7c478bd9Sstevel@tonic-gate int error; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate va.va_mask = AT_MODE; 170*7c478bd9Sstevel@tonic-gate error = VOP_GETATTR(vp, &va, 0, cr); 171*7c478bd9Sstevel@tonic-gate if (error != 0) 172*7c478bd9Sstevel@tonic-gate return (error); 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate *svp = MANDLOCK(vp, va.va_mode); 175*7c478bd9Sstevel@tonic-gate return (0); 176*7c478bd9Sstevel@tonic-gate } 177