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