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 5dd29fa4aSprabahar * Common Development and Distribution License (the "License"). 6dd29fa4aSprabahar * 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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 227c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 237c478bd9Sstevel@tonic-gate 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 2627dd1e87SMark Shellenbaum * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 27a3c49ce1SAlbert Lee * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 28*7a5aac98SJerry Jelinek * Copyright 2015 Joyent, Inc. 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate /* 327c478bd9Sstevel@tonic-gate * Generic vnode operations. 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate #include <sys/param.h> 367c478bd9Sstevel@tonic-gate #include <sys/systm.h> 377c478bd9Sstevel@tonic-gate #include <sys/errno.h> 387c478bd9Sstevel@tonic-gate #include <sys/fcntl.h> 397c478bd9Sstevel@tonic-gate #include <sys/flock.h> 407c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 417c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 427c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 437c478bd9Sstevel@tonic-gate #include <sys/proc.h> 447c478bd9Sstevel@tonic-gate #include <sys/user.h> 457c478bd9Sstevel@tonic-gate #include <sys/unistd.h> 467c478bd9Sstevel@tonic-gate #include <sys/cred.h> 477c478bd9Sstevel@tonic-gate #include <sys/poll.h> 487c478bd9Sstevel@tonic-gate #include <sys/debug.h> 497c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 507c478bd9Sstevel@tonic-gate #include <sys/stream.h> 517c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h> 527a286c47SDai Ngo #include <fs/fs_reparse.h> 537a286c47SDai Ngo #include <sys/door.h> 547c478bd9Sstevel@tonic-gate #include <sys/acl.h> 557c478bd9Sstevel@tonic-gate #include <sys/share.h> 567c478bd9Sstevel@tonic-gate #include <sys/file.h> 577c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 587c478bd9Sstevel@tonic-gate #include <sys/file.h> 597c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h> 60fa9e4066Sahrens #include <acl/acl_common.h> 617a286c47SDai Ngo #include <sys/pathname.h> 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate static callb_cpr_t *frlock_serialize_blocked(flk_cb_when_t, void *); 647c478bd9Sstevel@tonic-gate 65dd29fa4aSprabahar /* 66dd29fa4aSprabahar * Tunable to limit the number of retry to recover from STALE error. 67dd29fa4aSprabahar */ 68dd29fa4aSprabahar int fs_estale_retry = 5; 69dd29fa4aSprabahar 707a286c47SDai Ngo /* 717a286c47SDai Ngo * supports for reparse point door upcall 727a286c47SDai Ngo */ 737a286c47SDai Ngo static door_handle_t reparsed_door; 747a286c47SDai Ngo static kmutex_t reparsed_door_lock; 757a286c47SDai Ngo 767c478bd9Sstevel@tonic-gate /* 777c478bd9Sstevel@tonic-gate * The associated operation is not supported by the file system. 787c478bd9Sstevel@tonic-gate */ 797c478bd9Sstevel@tonic-gate int 807c478bd9Sstevel@tonic-gate fs_nosys() 817c478bd9Sstevel@tonic-gate { 827c478bd9Sstevel@tonic-gate return (ENOSYS); 837c478bd9Sstevel@tonic-gate } 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate /* 867c478bd9Sstevel@tonic-gate * The associated operation is invalid (on this vnode). 877c478bd9Sstevel@tonic-gate */ 887c478bd9Sstevel@tonic-gate int 897c478bd9Sstevel@tonic-gate fs_inval() 907c478bd9Sstevel@tonic-gate { 917c478bd9Sstevel@tonic-gate return (EINVAL); 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate /* 957c478bd9Sstevel@tonic-gate * The associated operation is valid only for directories. 967c478bd9Sstevel@tonic-gate */ 977c478bd9Sstevel@tonic-gate int 987c478bd9Sstevel@tonic-gate fs_notdir() 997c478bd9Sstevel@tonic-gate { 1007c478bd9Sstevel@tonic-gate return (ENOTDIR); 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* 1047c478bd9Sstevel@tonic-gate * Free the file system specific resources. For the file systems that 1057c478bd9Sstevel@tonic-gate * do not support the forced unmount, it will be a nop function. 1067c478bd9Sstevel@tonic-gate */ 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1097c478bd9Sstevel@tonic-gate void 1107c478bd9Sstevel@tonic-gate fs_freevfs(vfs_t *vfsp) 1117c478bd9Sstevel@tonic-gate { 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1157c478bd9Sstevel@tonic-gate int 1167c478bd9Sstevel@tonic-gate fs_nosys_map(struct vnode *vp, 1177c478bd9Sstevel@tonic-gate offset_t off, 1187c478bd9Sstevel@tonic-gate struct as *as, 1197c478bd9Sstevel@tonic-gate caddr_t *addrp, 1207c478bd9Sstevel@tonic-gate size_t len, 1217c478bd9Sstevel@tonic-gate uchar_t prot, 1227c478bd9Sstevel@tonic-gate uchar_t maxprot, 1237c478bd9Sstevel@tonic-gate uint_t flags, 124da6c28aaSamw struct cred *cr, 125da6c28aaSamw caller_context_t *ct) 1267c478bd9Sstevel@tonic-gate { 1277c478bd9Sstevel@tonic-gate return (ENOSYS); 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1317c478bd9Sstevel@tonic-gate int 1327c478bd9Sstevel@tonic-gate fs_nosys_addmap(struct vnode *vp, 1337c478bd9Sstevel@tonic-gate offset_t off, 1347c478bd9Sstevel@tonic-gate struct as *as, 1357c478bd9Sstevel@tonic-gate caddr_t addr, 1367c478bd9Sstevel@tonic-gate size_t len, 1377c478bd9Sstevel@tonic-gate uchar_t prot, 1387c478bd9Sstevel@tonic-gate uchar_t maxprot, 1397c478bd9Sstevel@tonic-gate uint_t flags, 140da6c28aaSamw struct cred *cr, 141da6c28aaSamw caller_context_t *ct) 1427c478bd9Sstevel@tonic-gate { 1437c478bd9Sstevel@tonic-gate return (ENOSYS); 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1477c478bd9Sstevel@tonic-gate int 1487c478bd9Sstevel@tonic-gate fs_nosys_poll(vnode_t *vp, 1497c478bd9Sstevel@tonic-gate register short events, 1507c478bd9Sstevel@tonic-gate int anyyet, 1517c478bd9Sstevel@tonic-gate register short *reventsp, 152da6c28aaSamw struct pollhead **phpp, 153da6c28aaSamw caller_context_t *ct) 1547c478bd9Sstevel@tonic-gate { 1557c478bd9Sstevel@tonic-gate return (ENOSYS); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate /* 1607c478bd9Sstevel@tonic-gate * The file system has nothing to sync to disk. However, the 1617c478bd9Sstevel@tonic-gate * VFS_SYNC operation must not fail. 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1647c478bd9Sstevel@tonic-gate int 1657c478bd9Sstevel@tonic-gate fs_sync(struct vfs *vfspp, short flag, cred_t *cr) 1667c478bd9Sstevel@tonic-gate { 1677c478bd9Sstevel@tonic-gate return (0); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 170da6c28aaSamw /* 171da6c28aaSamw * Does nothing but VOP_FSYNC must not fail. 172da6c28aaSamw */ 173da6c28aaSamw /* ARGSUSED */ 174da6c28aaSamw int 175da6c28aaSamw fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) 176da6c28aaSamw { 177da6c28aaSamw return (0); 178da6c28aaSamw } 179da6c28aaSamw 180da6c28aaSamw /* 181da6c28aaSamw * Does nothing but VOP_PUTPAGE must not fail. 182da6c28aaSamw */ 183da6c28aaSamw /* ARGSUSED */ 184da6c28aaSamw int 185da6c28aaSamw fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr, 186da6c28aaSamw caller_context_t *ctp) 187da6c28aaSamw { 188da6c28aaSamw return (0); 189da6c28aaSamw } 190da6c28aaSamw 191da6c28aaSamw /* 192da6c28aaSamw * Does nothing but VOP_IOCTL must not fail. 193da6c28aaSamw */ 194da6c28aaSamw /* ARGSUSED */ 195da6c28aaSamw int 196da6c28aaSamw fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred, 197da6c28aaSamw int *rvalp) 198da6c28aaSamw { 199da6c28aaSamw return (0); 200da6c28aaSamw } 201da6c28aaSamw 2027c478bd9Sstevel@tonic-gate /* 2037c478bd9Sstevel@tonic-gate * Read/write lock/unlock. Does nothing. 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2067c478bd9Sstevel@tonic-gate int 2077c478bd9Sstevel@tonic-gate fs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 2087c478bd9Sstevel@tonic-gate { 2097c478bd9Sstevel@tonic-gate return (-1); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2137c478bd9Sstevel@tonic-gate void 2147c478bd9Sstevel@tonic-gate fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate /* 2197c478bd9Sstevel@tonic-gate * Compare two vnodes. 2207c478bd9Sstevel@tonic-gate */ 221da6c28aaSamw /*ARGSUSED2*/ 2227c478bd9Sstevel@tonic-gate int 223da6c28aaSamw fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct) 2247c478bd9Sstevel@tonic-gate { 2257c478bd9Sstevel@tonic-gate return (vp1 == vp2); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * No-op seek operation. 2307c478bd9Sstevel@tonic-gate */ 2317c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2327c478bd9Sstevel@tonic-gate int 233da6c28aaSamw fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) 2347c478bd9Sstevel@tonic-gate { 2357c478bd9Sstevel@tonic-gate return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0); 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* 2397c478bd9Sstevel@tonic-gate * File and record locking. 2407c478bd9Sstevel@tonic-gate */ 2417c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2427c478bd9Sstevel@tonic-gate int 2437c478bd9Sstevel@tonic-gate fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 244da6c28aaSamw offset_t offset, flk_callback_t *flk_cbp, cred_t *cr, 245da6c28aaSamw caller_context_t *ct) 2467c478bd9Sstevel@tonic-gate { 2477c478bd9Sstevel@tonic-gate int frcmd; 2487c478bd9Sstevel@tonic-gate int nlmid; 2497c478bd9Sstevel@tonic-gate int error = 0; 250*7a5aac98SJerry Jelinek boolean_t skip_lock = B_FALSE; 2517c478bd9Sstevel@tonic-gate flk_callback_t serialize_callback; 2527c478bd9Sstevel@tonic-gate int serialize = 0; 253da6c28aaSamw v_mode_t mode; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate switch (cmd) { 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate case F_GETLK: 2587c478bd9Sstevel@tonic-gate case F_O_GETLK: 2597c478bd9Sstevel@tonic-gate if (flag & F_REMOTELOCK) { 2607c478bd9Sstevel@tonic-gate frcmd = RCMDLCK; 261da6c28aaSamw } else if (flag & F_PXFSLOCK) { 2627c478bd9Sstevel@tonic-gate frcmd = PCMDLCK; 263da6c28aaSamw } else { 264da6c28aaSamw frcmd = 0; 265da6c28aaSamw bfp->l_pid = ttoproc(curthread)->p_pid; 266da6c28aaSamw bfp->l_sysid = 0; 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate break; 2697c478bd9Sstevel@tonic-gate 270*7a5aac98SJerry Jelinek case F_OFD_GETLK: 271*7a5aac98SJerry Jelinek /* 272*7a5aac98SJerry Jelinek * TBD we do not support remote OFD locks at this time. 273*7a5aac98SJerry Jelinek */ 274*7a5aac98SJerry Jelinek if (flag & (F_REMOTELOCK | F_PXFSLOCK)) { 275*7a5aac98SJerry Jelinek error = EINVAL; 276*7a5aac98SJerry Jelinek goto done; 277*7a5aac98SJerry Jelinek } 278*7a5aac98SJerry Jelinek skip_lock = B_TRUE; 279*7a5aac98SJerry Jelinek break; 280*7a5aac98SJerry Jelinek 2817c478bd9Sstevel@tonic-gate case F_SETLK_NBMAND: 2827c478bd9Sstevel@tonic-gate /* 2837c478bd9Sstevel@tonic-gate * Are NBMAND locks allowed on this file? 2847c478bd9Sstevel@tonic-gate */ 2857c478bd9Sstevel@tonic-gate if (!vp->v_vfsp || 2867c478bd9Sstevel@tonic-gate !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) { 2877c478bd9Sstevel@tonic-gate error = EINVAL; 2887c478bd9Sstevel@tonic-gate goto done; 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) { 2917c478bd9Sstevel@tonic-gate error = EINVAL; 2927c478bd9Sstevel@tonic-gate goto done; 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate case F_SETLK: 297da6c28aaSamw if (flag & F_REMOTELOCK) { 298da6c28aaSamw frcmd = SETFLCK|RCMDLCK; 299da6c28aaSamw } else if (flag & F_PXFSLOCK) { 300da6c28aaSamw frcmd = SETFLCK|PCMDLCK; 301da6c28aaSamw } else { 302da6c28aaSamw frcmd = SETFLCK; 303da6c28aaSamw bfp->l_pid = ttoproc(curthread)->p_pid; 304da6c28aaSamw bfp->l_sysid = 0; 305da6c28aaSamw } 306da6c28aaSamw if (cmd == F_SETLK_NBMAND && 307da6c28aaSamw (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) { 308da6c28aaSamw frcmd |= NBMLCK; 309da6c28aaSamw } 310b89a8333Snatalie li - Sun Microsystems - Irvine United States 3117c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 3127c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_WRITER); 3137c478bd9Sstevel@tonic-gate serialize = 1; 314da6c28aaSamw if (frcmd & NBMLCK) { 315da6c28aaSamw mode = (bfp->l_type == F_RDLCK) ? 316da6c28aaSamw V_READ : V_RDANDWR; 317da6c28aaSamw if (vn_is_mapped(vp, mode)) { 318da6c28aaSamw error = EAGAIN; 319da6c28aaSamw goto done; 320da6c28aaSamw } 321da6c28aaSamw } 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate break; 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate case F_SETLKW: 326da6c28aaSamw if (flag & F_REMOTELOCK) { 327da6c28aaSamw frcmd = SETFLCK|SLPFLCK|RCMDLCK; 328da6c28aaSamw } else if (flag & F_PXFSLOCK) { 329da6c28aaSamw frcmd = SETFLCK|SLPFLCK|PCMDLCK; 330da6c28aaSamw } else { 331da6c28aaSamw frcmd = SETFLCK|SLPFLCK; 332da6c28aaSamw bfp->l_pid = ttoproc(curthread)->p_pid; 333da6c28aaSamw bfp->l_sysid = 0; 334da6c28aaSamw } 335b89a8333Snatalie li - Sun Microsystems - Irvine United States 3367c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 3377c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_WRITER); 3387c478bd9Sstevel@tonic-gate serialize = 1; 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate break; 3417c478bd9Sstevel@tonic-gate 342*7a5aac98SJerry Jelinek case F_OFD_SETLK: 343*7a5aac98SJerry Jelinek case F_OFD_SETLKW: 344*7a5aac98SJerry Jelinek case F_FLOCK: 345*7a5aac98SJerry Jelinek case F_FLOCKW: 346*7a5aac98SJerry Jelinek /* 347*7a5aac98SJerry Jelinek * TBD we do not support remote OFD locks at this time. 348*7a5aac98SJerry Jelinek */ 349*7a5aac98SJerry Jelinek if (flag & (F_REMOTELOCK | F_PXFSLOCK)) { 350*7a5aac98SJerry Jelinek error = EINVAL; 351*7a5aac98SJerry Jelinek goto done; 352*7a5aac98SJerry Jelinek } 353*7a5aac98SJerry Jelinek skip_lock = B_TRUE; 354*7a5aac98SJerry Jelinek break; 355*7a5aac98SJerry Jelinek 3567c478bd9Sstevel@tonic-gate case F_HASREMOTELOCKS: 3577c478bd9Sstevel@tonic-gate nlmid = GETNLMID(bfp->l_sysid); 3587c478bd9Sstevel@tonic-gate if (nlmid != 0) { /* booted as a cluster */ 3597c478bd9Sstevel@tonic-gate l_has_rmt(bfp) = 360da6c28aaSamw cl_flk_has_remote_locks_for_nlmid(vp, nlmid); 3617c478bd9Sstevel@tonic-gate } else { /* not booted as a cluster */ 3627c478bd9Sstevel@tonic-gate l_has_rmt(bfp) = flk_has_remote_locks(vp); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate goto done; 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate default: 3687c478bd9Sstevel@tonic-gate error = EINVAL; 3697c478bd9Sstevel@tonic-gate goto done; 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* 3737c478bd9Sstevel@tonic-gate * If this is a blocking lock request and we're serializing lock 3747c478bd9Sstevel@tonic-gate * requests, modify the callback list to leave the critical region 3757c478bd9Sstevel@tonic-gate * while we're waiting for the lock. 3767c478bd9Sstevel@tonic-gate */ 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate if (serialize && (frcmd & SLPFLCK) != 0) { 3797c478bd9Sstevel@tonic-gate flk_add_callback(&serialize_callback, 380da6c28aaSamw frlock_serialize_blocked, vp, flk_cbp); 3817c478bd9Sstevel@tonic-gate flk_cbp = &serialize_callback; 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 384*7a5aac98SJerry Jelinek if (!skip_lock) 385*7a5aac98SJerry Jelinek error = reclock(vp, bfp, frcmd, flag, offset, flk_cbp); 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate done: 3887c478bd9Sstevel@tonic-gate if (serialize) 3897c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate return (error); 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* 3957c478bd9Sstevel@tonic-gate * Callback when a lock request blocks and we are serializing requests. If 3967c478bd9Sstevel@tonic-gate * before sleeping, leave the critical region. If after wakeup, reenter 3977c478bd9Sstevel@tonic-gate * the critical region. 3987c478bd9Sstevel@tonic-gate */ 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate static callb_cpr_t * 4017c478bd9Sstevel@tonic-gate frlock_serialize_blocked(flk_cb_when_t when, void *infop) 4027c478bd9Sstevel@tonic-gate { 4037c478bd9Sstevel@tonic-gate vnode_t *vp = (vnode_t *)infop; 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate if (when == FLK_BEFORE_SLEEP) 4067c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 4077c478bd9Sstevel@tonic-gate else { 4087c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_WRITER); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate return (NULL); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate /* 4157c478bd9Sstevel@tonic-gate * Allow any flags. 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4187c478bd9Sstevel@tonic-gate int 419da6c28aaSamw fs_setfl( 420da6c28aaSamw vnode_t *vp, 421da6c28aaSamw int oflags, 422da6c28aaSamw int nflags, 423da6c28aaSamw cred_t *cr, 424da6c28aaSamw caller_context_t *ct) 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate return (0); 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate /* 4307c478bd9Sstevel@tonic-gate * Return the answer requested to poll() for non-device files. 4317c478bd9Sstevel@tonic-gate * Only POLLIN, POLLRDNORM, and POLLOUT are recognized. 4327c478bd9Sstevel@tonic-gate */ 4337c478bd9Sstevel@tonic-gate struct pollhead fs_pollhd; 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4367c478bd9Sstevel@tonic-gate int 4377c478bd9Sstevel@tonic-gate fs_poll(vnode_t *vp, 4387c478bd9Sstevel@tonic-gate register short events, 4397c478bd9Sstevel@tonic-gate int anyyet, 4407c478bd9Sstevel@tonic-gate register short *reventsp, 441da6c28aaSamw struct pollhead **phpp, 442da6c28aaSamw caller_context_t *ct) 4437c478bd9Sstevel@tonic-gate { 4447c478bd9Sstevel@tonic-gate *reventsp = 0; 4457c478bd9Sstevel@tonic-gate if (events & POLLIN) 4467c478bd9Sstevel@tonic-gate *reventsp |= POLLIN; 4477c478bd9Sstevel@tonic-gate if (events & POLLRDNORM) 4487c478bd9Sstevel@tonic-gate *reventsp |= POLLRDNORM; 4497c478bd9Sstevel@tonic-gate if (events & POLLRDBAND) 4507c478bd9Sstevel@tonic-gate *reventsp |= POLLRDBAND; 4517c478bd9Sstevel@tonic-gate if (events & POLLOUT) 4527c478bd9Sstevel@tonic-gate *reventsp |= POLLOUT; 4537c478bd9Sstevel@tonic-gate if (events & POLLWRBAND) 4547c478bd9Sstevel@tonic-gate *reventsp |= POLLWRBAND; 4557c478bd9Sstevel@tonic-gate *phpp = !anyyet && !*reventsp ? &fs_pollhd : (struct pollhead *)NULL; 4567c478bd9Sstevel@tonic-gate return (0); 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate * POSIX pathconf() support. 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4637c478bd9Sstevel@tonic-gate int 464da6c28aaSamw fs_pathconf( 465da6c28aaSamw vnode_t *vp, 466da6c28aaSamw int cmd, 467da6c28aaSamw ulong_t *valp, 468da6c28aaSamw cred_t *cr, 469da6c28aaSamw caller_context_t *ct) 4707c478bd9Sstevel@tonic-gate { 4717c478bd9Sstevel@tonic-gate register ulong_t val; 4727c478bd9Sstevel@tonic-gate register int error = 0; 4737c478bd9Sstevel@tonic-gate struct statvfs64 vfsbuf; 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate switch (cmd) { 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate case _PC_LINK_MAX: 4787c478bd9Sstevel@tonic-gate val = MAXLINK; 4797c478bd9Sstevel@tonic-gate break; 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate case _PC_MAX_CANON: 4827c478bd9Sstevel@tonic-gate val = MAX_CANON; 4837c478bd9Sstevel@tonic-gate break; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate case _PC_MAX_INPUT: 4867c478bd9Sstevel@tonic-gate val = MAX_INPUT; 4877c478bd9Sstevel@tonic-gate break; 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate case _PC_NAME_MAX: 4907c478bd9Sstevel@tonic-gate bzero(&vfsbuf, sizeof (vfsbuf)); 4917c478bd9Sstevel@tonic-gate if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf)) 4927c478bd9Sstevel@tonic-gate break; 4937c478bd9Sstevel@tonic-gate val = vfsbuf.f_namemax; 4947c478bd9Sstevel@tonic-gate break; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate case _PC_PATH_MAX: 4977c478bd9Sstevel@tonic-gate case _PC_SYMLINK_MAX: 4987c478bd9Sstevel@tonic-gate val = MAXPATHLEN; 4997c478bd9Sstevel@tonic-gate break; 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate case _PC_PIPE_BUF: 5027c478bd9Sstevel@tonic-gate val = PIPE_BUF; 5037c478bd9Sstevel@tonic-gate break; 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate case _PC_NO_TRUNC: 5067c478bd9Sstevel@tonic-gate if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC) 5077c478bd9Sstevel@tonic-gate val = 1; /* NOTRUNC is enabled for vp */ 5087c478bd9Sstevel@tonic-gate else 5097c478bd9Sstevel@tonic-gate val = (ulong_t)-1; 5107c478bd9Sstevel@tonic-gate break; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate case _PC_VDISABLE: 5137c478bd9Sstevel@tonic-gate val = _POSIX_VDISABLE; 5147c478bd9Sstevel@tonic-gate break; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate case _PC_CHOWN_RESTRICTED: 5177c478bd9Sstevel@tonic-gate if (rstchown) 5187c478bd9Sstevel@tonic-gate val = rstchown; /* chown restricted enabled */ 5197c478bd9Sstevel@tonic-gate else 5207c478bd9Sstevel@tonic-gate val = (ulong_t)-1; 5217c478bd9Sstevel@tonic-gate break; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate case _PC_FILESIZEBITS: 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /* 5267c478bd9Sstevel@tonic-gate * If ever we come here it means that underlying file system 5277c478bd9Sstevel@tonic-gate * does not recognise the command and therefore this 5287c478bd9Sstevel@tonic-gate * configurable limit cannot be determined. We return -1 5297c478bd9Sstevel@tonic-gate * and don't change errno. 5307c478bd9Sstevel@tonic-gate */ 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate val = (ulong_t)-1; /* large file support */ 5337c478bd9Sstevel@tonic-gate break; 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate case _PC_ACL_ENABLED: 5367c478bd9Sstevel@tonic-gate val = 0; 5377c478bd9Sstevel@tonic-gate break; 5387c478bd9Sstevel@tonic-gate 539da6c28aaSamw case _PC_CASE_BEHAVIOR: 540da6c28aaSamw val = _CASE_SENSITIVE; 541da6c28aaSamw if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1) 542da6c28aaSamw val |= _CASE_INSENSITIVE; 543da6c28aaSamw if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1) 544da6c28aaSamw val &= ~_CASE_SENSITIVE; 545da6c28aaSamw break; 546da6c28aaSamw 547da6c28aaSamw case _PC_SATTR_ENABLED: 548da6c28aaSamw case _PC_SATTR_EXISTS: 549da6c28aaSamw val = 0; 550e802abbdSTim Haley break; 551e802abbdSTim Haley 552e802abbdSTim Haley case _PC_ACCESS_FILTERING: 553e802abbdSTim Haley val = 0; 554da6c28aaSamw break; 555da6c28aaSamw 5567c478bd9Sstevel@tonic-gate default: 5577c478bd9Sstevel@tonic-gate error = EINVAL; 5587c478bd9Sstevel@tonic-gate break; 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate if (error == 0) 5627c478bd9Sstevel@tonic-gate *valp = val; 5637c478bd9Sstevel@tonic-gate return (error); 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate /* 5677c478bd9Sstevel@tonic-gate * Dispose of a page. 5687c478bd9Sstevel@tonic-gate */ 5697c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5707c478bd9Sstevel@tonic-gate void 571da6c28aaSamw fs_dispose( 572da6c28aaSamw struct vnode *vp, 573da6c28aaSamw page_t *pp, 574da6c28aaSamw int fl, 575da6c28aaSamw int dn, 576da6c28aaSamw struct cred *cr, 577da6c28aaSamw caller_context_t *ct) 5787c478bd9Sstevel@tonic-gate { 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate ASSERT(fl == B_FREE || fl == B_INVAL); 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate if (fl == B_FREE) 5837c478bd9Sstevel@tonic-gate page_free(pp, dn); 5847c478bd9Sstevel@tonic-gate else 5857c478bd9Sstevel@tonic-gate page_destroy(pp, dn); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5897c478bd9Sstevel@tonic-gate void 590da6c28aaSamw fs_nodispose( 591da6c28aaSamw struct vnode *vp, 592da6c28aaSamw page_t *pp, 593da6c28aaSamw int fl, 594da6c28aaSamw int dn, 595da6c28aaSamw struct cred *cr, 596da6c28aaSamw caller_context_t *ct) 5977c478bd9Sstevel@tonic-gate { 5987c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "fs_nodispose invoked"); 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate /* 6027c478bd9Sstevel@tonic-gate * fabricate acls for file systems that do not support acls. 6037c478bd9Sstevel@tonic-gate */ 6047c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6057c478bd9Sstevel@tonic-gate int 606da6c28aaSamw fs_fab_acl( 607da6c28aaSamw vnode_t *vp, 608da6c28aaSamw vsecattr_t *vsecattr, 609da6c28aaSamw int flag, 610da6c28aaSamw cred_t *cr, 611da6c28aaSamw caller_context_t *ct) 6127c478bd9Sstevel@tonic-gate { 6137c478bd9Sstevel@tonic-gate aclent_t *aclentp; 6147c478bd9Sstevel@tonic-gate struct vattr vattr; 6157c478bd9Sstevel@tonic-gate int error; 616da6c28aaSamw size_t aclsize; 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate vsecattr->vsa_aclcnt = 0; 619da6c28aaSamw vsecattr->vsa_aclentsz = 0; 6207c478bd9Sstevel@tonic-gate vsecattr->vsa_aclentp = NULL; 6217c478bd9Sstevel@tonic-gate vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */ 6227c478bd9Sstevel@tonic-gate vsecattr->vsa_dfaclentp = NULL; 6237c478bd9Sstevel@tonic-gate 6247b3700d1Sszhou vattr.va_mask = AT_MODE | AT_UID | AT_GID; 625da6c28aaSamw if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct)) 6267b3700d1Sszhou return (error); 6277b3700d1Sszhou 628cf53598eSmarks if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) { 629da6c28aaSamw aclsize = 4 * sizeof (aclent_t); 6307b3700d1Sszhou vsecattr->vsa_aclcnt = 4; /* USER, GROUP, OTHER, and CLASS */ 631da6c28aaSamw vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP); 6327c478bd9Sstevel@tonic-gate aclentp = vsecattr->vsa_aclentp; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate aclentp->a_type = USER_OBJ; /* Owner */ 6357c478bd9Sstevel@tonic-gate aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0700)) >> 6; 6367c478bd9Sstevel@tonic-gate aclentp->a_id = vattr.va_uid; /* Really undefined */ 6377c478bd9Sstevel@tonic-gate aclentp++; 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate aclentp->a_type = GROUP_OBJ; /* Group */ 6407c478bd9Sstevel@tonic-gate aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0070)) >> 3; 6417c478bd9Sstevel@tonic-gate aclentp->a_id = vattr.va_gid; /* Really undefined */ 6427c478bd9Sstevel@tonic-gate aclentp++; 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate aclentp->a_type = OTHER_OBJ; /* Other */ 6457c478bd9Sstevel@tonic-gate aclentp->a_perm = vattr.va_mode & 0007; 646f48205beScasper aclentp->a_id = (gid_t)-1; /* Really undefined */ 6477c478bd9Sstevel@tonic-gate aclentp++; 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate aclentp->a_type = CLASS_OBJ; /* Class */ 6507b3700d1Sszhou aclentp->a_perm = (ushort_t)(0007); 651f48205beScasper aclentp->a_id = (gid_t)-1; /* Really undefined */ 652cf53598eSmarks } else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) { 65327dd1e87SMark Shellenbaum VERIFY(0 == acl_trivial_create(vattr.va_mode, 654a3c49ce1SAlbert Lee (vp->v_type == VDIR), (ace_t **)&vsecattr->vsa_aclentp, 655a3c49ce1SAlbert Lee &vsecattr->vsa_aclcnt)); 65627dd1e87SMark Shellenbaum vsecattr->vsa_aclentsz = vsecattr->vsa_aclcnt * sizeof (ace_t); 657cf53598eSmarks } 6587c478bd9Sstevel@tonic-gate 65927dd1e87SMark Shellenbaum return (error); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate /* 6637c478bd9Sstevel@tonic-gate * Common code for implementing DOS share reservations 6647c478bd9Sstevel@tonic-gate */ 6657c478bd9Sstevel@tonic-gate /* ARGSUSED4 */ 6667c478bd9Sstevel@tonic-gate int 667da6c28aaSamw fs_shrlock( 668da6c28aaSamw struct vnode *vp, 669da6c28aaSamw int cmd, 670da6c28aaSamw struct shrlock *shr, 671da6c28aaSamw int flag, 672da6c28aaSamw cred_t *cr, 673da6c28aaSamw caller_context_t *ct) 6747c478bd9Sstevel@tonic-gate { 6757c478bd9Sstevel@tonic-gate int error; 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate /* 6787c478bd9Sstevel@tonic-gate * Make sure that the file was opened with permissions appropriate 6797c478bd9Sstevel@tonic-gate * for the request, and make sure the caller isn't trying to sneak 6807c478bd9Sstevel@tonic-gate * in an NBMAND request. 6817c478bd9Sstevel@tonic-gate */ 6827c478bd9Sstevel@tonic-gate if (cmd == F_SHARE) { 6837c478bd9Sstevel@tonic-gate if (((shr->s_access & F_RDACC) && (flag & FREAD) == 0) || 6847c478bd9Sstevel@tonic-gate ((shr->s_access & F_WRACC) && (flag & FWRITE) == 0)) 6857c478bd9Sstevel@tonic-gate return (EBADF); 686da6c28aaSamw if (shr->s_access & (F_RMACC | F_MDACC)) 687da6c28aaSamw return (EINVAL); 688da6c28aaSamw if (shr->s_deny & (F_MANDDNY | F_RMDNY)) 6897c478bd9Sstevel@tonic-gate return (EINVAL); 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate if (cmd == F_SHARE_NBMAND) { 6927c478bd9Sstevel@tonic-gate /* make sure nbmand is allowed on the file */ 6937c478bd9Sstevel@tonic-gate if (!vp->v_vfsp || 6947c478bd9Sstevel@tonic-gate !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) { 6957c478bd9Sstevel@tonic-gate return (EINVAL); 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) { 6987c478bd9Sstevel@tonic-gate return (EINVAL); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_WRITER); 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate switch (cmd) { 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate case F_SHARE_NBMAND: 7077c478bd9Sstevel@tonic-gate shr->s_deny |= F_MANDDNY; 7087c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 7097c478bd9Sstevel@tonic-gate case F_SHARE: 7107c478bd9Sstevel@tonic-gate error = add_share(vp, shr); 7117c478bd9Sstevel@tonic-gate break; 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate case F_UNSHARE: 7147c478bd9Sstevel@tonic-gate error = del_share(vp, shr); 7157c478bd9Sstevel@tonic-gate break; 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate case F_HASREMOTELOCKS: 7187c478bd9Sstevel@tonic-gate /* 7197c478bd9Sstevel@tonic-gate * We are overloading this command to refer to remote 7207c478bd9Sstevel@tonic-gate * shares as well as remote locks, despite its name. 7217c478bd9Sstevel@tonic-gate */ 7227c478bd9Sstevel@tonic-gate shr->s_access = shr_has_remote_shares(vp, shr->s_sysid); 7237c478bd9Sstevel@tonic-gate error = 0; 7247c478bd9Sstevel@tonic-gate break; 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate default: 7277c478bd9Sstevel@tonic-gate error = EINVAL; 7287c478bd9Sstevel@tonic-gate break; 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 7327c478bd9Sstevel@tonic-gate return (error); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 7367c478bd9Sstevel@tonic-gate int 737da6c28aaSamw fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm, 738da6c28aaSamw caller_context_t *ct) 7397c478bd9Sstevel@tonic-gate { 7407c478bd9Sstevel@tonic-gate ASSERT(vp != NULL); 7417c478bd9Sstevel@tonic-gate return (ENOTSUP); 7427c478bd9Sstevel@tonic-gate } 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 7457c478bd9Sstevel@tonic-gate int 746da6c28aaSamw fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm, 747da6c28aaSamw caller_context_t *ct) 7487c478bd9Sstevel@tonic-gate { 7497c478bd9Sstevel@tonic-gate ASSERT(vp != NULL); 7507c478bd9Sstevel@tonic-gate return (0); 7517c478bd9Sstevel@tonic-gate } 752fa9e4066Sahrens 753fa9e4066Sahrens /* 754fa9e4066Sahrens * return 1 for non-trivial ACL. 755fa9e4066Sahrens * 756fa9e4066Sahrens * NB: It is not necessary for the caller to VOP_RWLOCK since 757fa9e4066Sahrens * we only issue VOP_GETSECATTR. 758fa9e4066Sahrens * 759fa9e4066Sahrens * Returns 0 == trivial 760fa9e4066Sahrens * 1 == NOT Trivial 761fa9e4066Sahrens * <0 could not determine. 762fa9e4066Sahrens */ 763fa9e4066Sahrens int 764fa9e4066Sahrens fs_acl_nontrivial(vnode_t *vp, cred_t *cr) 765fa9e4066Sahrens { 766fa9e4066Sahrens ulong_t acl_styles; 767fa9e4066Sahrens ulong_t acl_flavor; 768fa9e4066Sahrens vsecattr_t vsecattr; 769fa9e4066Sahrens int error; 770fa9e4066Sahrens int isnontrivial; 771fa9e4066Sahrens 772fa9e4066Sahrens /* determine the forms of ACLs maintained */ 773da6c28aaSamw error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &acl_styles, cr, NULL); 774fa9e4066Sahrens 775fa9e4066Sahrens /* clear bits we don't understand and establish default acl_style */ 776fa9e4066Sahrens acl_styles &= (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED); 777fa9e4066Sahrens if (error || (acl_styles == 0)) 778fa9e4066Sahrens acl_styles = _ACL_ACLENT_ENABLED; 779fa9e4066Sahrens 780fa9e4066Sahrens vsecattr.vsa_aclentp = NULL; 781fa9e4066Sahrens vsecattr.vsa_dfaclentp = NULL; 782fa9e4066Sahrens vsecattr.vsa_aclcnt = 0; 783fa9e4066Sahrens vsecattr.vsa_dfaclcnt = 0; 784fa9e4066Sahrens 785fa9e4066Sahrens while (acl_styles) { 786fa9e4066Sahrens /* select one of the styles as current flavor */ 787fa9e4066Sahrens acl_flavor = 0; 788fa9e4066Sahrens if (acl_styles & _ACL_ACLENT_ENABLED) { 789fa9e4066Sahrens acl_flavor = _ACL_ACLENT_ENABLED; 790fa9e4066Sahrens vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT; 791fa9e4066Sahrens } else if (acl_styles & _ACL_ACE_ENABLED) { 792fa9e4066Sahrens acl_flavor = _ACL_ACE_ENABLED; 793fa9e4066Sahrens vsecattr.vsa_mask = VSA_ACECNT | VSA_ACE; 794fa9e4066Sahrens } 795fa9e4066Sahrens 796fa9e4066Sahrens ASSERT(vsecattr.vsa_mask && acl_flavor); 797da6c28aaSamw error = VOP_GETSECATTR(vp, &vsecattr, 0, cr, NULL); 798fa9e4066Sahrens if (error == 0) 799fa9e4066Sahrens break; 800fa9e4066Sahrens 801fa9e4066Sahrens /* that flavor failed */ 802fa9e4066Sahrens acl_styles &= ~acl_flavor; 803fa9e4066Sahrens } 804fa9e4066Sahrens 805fa9e4066Sahrens /* if all styles fail then assume trivial */ 806fa9e4066Sahrens if (acl_styles == 0) 807fa9e4066Sahrens return (0); 808fa9e4066Sahrens 809fa9e4066Sahrens /* process the flavor that worked */ 810fa9e4066Sahrens isnontrivial = 0; 811fa9e4066Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) { 812fa9e4066Sahrens if (vsecattr.vsa_aclcnt > MIN_ACL_ENTRIES) 813fa9e4066Sahrens isnontrivial = 1; 814fa9e4066Sahrens if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL) 815fa9e4066Sahrens kmem_free(vsecattr.vsa_aclentp, 816fa9e4066Sahrens vsecattr.vsa_aclcnt * sizeof (aclent_t)); 817fa9e4066Sahrens if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp != NULL) 818fa9e4066Sahrens kmem_free(vsecattr.vsa_dfaclentp, 819fa9e4066Sahrens vsecattr.vsa_dfaclcnt * sizeof (aclent_t)); 820fa9e4066Sahrens } 821fa9e4066Sahrens if (acl_flavor & _ACL_ACE_ENABLED) { 822fa9e4066Sahrens isnontrivial = ace_trivial(vsecattr.vsa_aclentp, 823fa9e4066Sahrens vsecattr.vsa_aclcnt); 824fa9e4066Sahrens 825fa9e4066Sahrens if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL) 826fa9e4066Sahrens kmem_free(vsecattr.vsa_aclentp, 827fa9e4066Sahrens vsecattr.vsa_aclcnt * sizeof (ace_t)); 828fa9e4066Sahrens /* ACE has no vsecattr.vsa_dfaclcnt */ 829fa9e4066Sahrens } 830fa9e4066Sahrens return (isnontrivial); 831fa9e4066Sahrens } 832dd29fa4aSprabahar 833dd29fa4aSprabahar /* 834dd29fa4aSprabahar * Check whether we need a retry to recover from STALE error. 835dd29fa4aSprabahar */ 836dd29fa4aSprabahar int 837dd29fa4aSprabahar fs_need_estale_retry(int retry_count) 838dd29fa4aSprabahar { 839dd29fa4aSprabahar if (retry_count < fs_estale_retry) 840dd29fa4aSprabahar return (1); 841dd29fa4aSprabahar else 842dd29fa4aSprabahar return (0); 843dd29fa4aSprabahar } 844da6c28aaSamw 845da6c28aaSamw 846da6c28aaSamw static int (*fs_av_scan)(vnode_t *, cred_t *, int) = NULL; 847da6c28aaSamw 848da6c28aaSamw /* 849da6c28aaSamw * Routine for anti-virus scanner to call to register its scanning routine. 850da6c28aaSamw */ 851da6c28aaSamw void 852da6c28aaSamw fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int)) 853da6c28aaSamw { 854da6c28aaSamw fs_av_scan = av_scan; 855da6c28aaSamw } 856da6c28aaSamw 857da6c28aaSamw /* 858da6c28aaSamw * Routine for file systems to call to initiate anti-virus scanning. 859da6c28aaSamw * Scanning will only be done on REGular files (currently). 860da6c28aaSamw */ 861da6c28aaSamw int 862da6c28aaSamw fs_vscan(vnode_t *vp, cred_t *cr, int async) 863da6c28aaSamw { 864da6c28aaSamw int ret = 0; 865da6c28aaSamw 866da6c28aaSamw if (fs_av_scan && vp->v_type == VREG) 867da6c28aaSamw ret = (*fs_av_scan)(vp, cr, async); 868da6c28aaSamw 869da6c28aaSamw return (ret); 870da6c28aaSamw } 8717a286c47SDai Ngo 8727a286c47SDai Ngo /* 8737a286c47SDai Ngo * support functions for reparse point 8747a286c47SDai Ngo */ 8757a286c47SDai Ngo /* 8767a286c47SDai Ngo * reparse_vnode_parse 8777a286c47SDai Ngo * 8787a286c47SDai Ngo * Read the symlink data of a reparse point specified by the vnode 8797a286c47SDai Ngo * and return the reparse data as name-value pair in the nvlist. 8807a286c47SDai Ngo */ 8817a286c47SDai Ngo int 8827a286c47SDai Ngo reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl) 8837a286c47SDai Ngo { 8847a286c47SDai Ngo int err; 8857a286c47SDai Ngo char *lkdata; 8867a286c47SDai Ngo struct uio uio; 8877a286c47SDai Ngo struct iovec iov; 8887a286c47SDai Ngo 8897a286c47SDai Ngo if (vp == NULL || nvl == NULL) 8907a286c47SDai Ngo return (EINVAL); 8917a286c47SDai Ngo 8927a286c47SDai Ngo lkdata = kmem_alloc(MAXREPARSELEN, KM_SLEEP); 8937a286c47SDai Ngo 8947a286c47SDai Ngo /* 8957a286c47SDai Ngo * Set up io vector to read sym link data 8967a286c47SDai Ngo */ 8977a286c47SDai Ngo iov.iov_base = lkdata; 8987a286c47SDai Ngo iov.iov_len = MAXREPARSELEN; 8997a286c47SDai Ngo uio.uio_iov = &iov; 9007a286c47SDai Ngo uio.uio_iovcnt = 1; 9017a286c47SDai Ngo uio.uio_segflg = UIO_SYSSPACE; 9027a286c47SDai Ngo uio.uio_extflg = UIO_COPY_CACHED; 9037a286c47SDai Ngo uio.uio_loffset = (offset_t)0; 9047a286c47SDai Ngo uio.uio_resid = MAXREPARSELEN; 9057a286c47SDai Ngo 9067a286c47SDai Ngo if ((err = VOP_READLINK(vp, &uio, kcred, NULL)) == 0) { 9077a286c47SDai Ngo *(lkdata + MAXREPARSELEN - uio.uio_resid) = '\0'; 9087a286c47SDai Ngo err = reparse_parse(lkdata, nvl); 9097a286c47SDai Ngo } 9107a286c47SDai Ngo kmem_free(lkdata, MAXREPARSELEN); /* done with lkdata */ 9117a286c47SDai Ngo 9127a286c47SDai Ngo return (err); 9137a286c47SDai Ngo } 9147a286c47SDai Ngo 9157a286c47SDai Ngo void 9167a286c47SDai Ngo reparse_point_init() 9177a286c47SDai Ngo { 9187a286c47SDai Ngo mutex_init(&reparsed_door_lock, NULL, MUTEX_DEFAULT, NULL); 9197a286c47SDai Ngo } 9207a286c47SDai Ngo 9217a286c47SDai Ngo static door_handle_t 9227a286c47SDai Ngo reparse_door_get_handle() 9237a286c47SDai Ngo { 9247a286c47SDai Ngo door_handle_t dh; 9257a286c47SDai Ngo 9267a286c47SDai Ngo mutex_enter(&reparsed_door_lock); 9277a286c47SDai Ngo if ((dh = reparsed_door) == NULL) { 9287a286c47SDai Ngo if (door_ki_open(REPARSED_DOOR, &reparsed_door) != 0) { 9297a286c47SDai Ngo reparsed_door = NULL; 9307a286c47SDai Ngo dh = NULL; 9317a286c47SDai Ngo } else 9327a286c47SDai Ngo dh = reparsed_door; 9337a286c47SDai Ngo } 9347a286c47SDai Ngo mutex_exit(&reparsed_door_lock); 9357a286c47SDai Ngo return (dh); 9367a286c47SDai Ngo } 9377a286c47SDai Ngo 9387a286c47SDai Ngo static void 9397a286c47SDai Ngo reparse_door_reset_handle() 9407a286c47SDai Ngo { 9417a286c47SDai Ngo mutex_enter(&reparsed_door_lock); 9427a286c47SDai Ngo reparsed_door = NULL; 9437a286c47SDai Ngo mutex_exit(&reparsed_door_lock); 9447a286c47SDai Ngo } 9457a286c47SDai Ngo 9467a286c47SDai Ngo /* 9477a286c47SDai Ngo * reparse_kderef 9487a286c47SDai Ngo * 9497a286c47SDai Ngo * Accepts the service-specific item from the reparse point and returns 9507a286c47SDai Ngo * the service-specific data requested. The caller specifies the size of 9517a286c47SDai Ngo * the buffer provided via *bufsz; the routine will fail with EOVERFLOW 9527a286c47SDai Ngo * if the results will not fit in the buffer, in which case, *bufsz will 9537a286c47SDai Ngo * contain the number of bytes needed to hold the results. 9547a286c47SDai Ngo * 9557a286c47SDai Ngo * if ok return 0 and update *bufsize with length of actual result 9567a286c47SDai Ngo * else return error code. 9577a286c47SDai Ngo */ 9587a286c47SDai Ngo int 9597a286c47SDai Ngo reparse_kderef(const char *svc_type, const char *svc_data, char *buf, 9607a286c47SDai Ngo size_t *bufsize) 9617a286c47SDai Ngo { 9622f172c55SRobert Thurlow int err, retries, need_free, retried_doorhd; 9637a286c47SDai Ngo size_t dlen, res_len; 9647a286c47SDai Ngo char *darg; 9657a286c47SDai Ngo door_arg_t door_args; 9667a286c47SDai Ngo reparsed_door_res_t *resp; 9677a286c47SDai Ngo door_handle_t rp_door; 9687a286c47SDai Ngo 9697a286c47SDai Ngo if (svc_type == NULL || svc_data == NULL || buf == NULL || 9707a286c47SDai Ngo bufsize == NULL) 9717a286c47SDai Ngo return (EINVAL); 9727a286c47SDai Ngo 9737a286c47SDai Ngo /* get reparsed's door handle */ 9747a286c47SDai Ngo if ((rp_door = reparse_door_get_handle()) == NULL) 9757a286c47SDai Ngo return (EBADF); 9767a286c47SDai Ngo 9777a286c47SDai Ngo /* setup buffer for door_call args and results */ 9787a286c47SDai Ngo dlen = strlen(svc_type) + strlen(svc_data) + 2; 9797a286c47SDai Ngo if (*bufsize < dlen) { 9807a286c47SDai Ngo darg = kmem_alloc(dlen, KM_SLEEP); 9817a286c47SDai Ngo need_free = 1; 9827a286c47SDai Ngo } else { 9837a286c47SDai Ngo darg = buf; /* use same buffer for door's args & results */ 9847a286c47SDai Ngo need_free = 0; 9857a286c47SDai Ngo } 9867a286c47SDai Ngo 9877a286c47SDai Ngo /* build argument string of door call */ 9887a286c47SDai Ngo (void) snprintf(darg, dlen, "%s:%s", svc_type, svc_data); 9897a286c47SDai Ngo 9907a286c47SDai Ngo /* setup args for door call */ 9917a286c47SDai Ngo door_args.data_ptr = darg; 9927a286c47SDai Ngo door_args.data_size = dlen; 9937a286c47SDai Ngo door_args.desc_ptr = NULL; 9947a286c47SDai Ngo door_args.desc_num = 0; 9957a286c47SDai Ngo door_args.rbuf = buf; 9967a286c47SDai Ngo door_args.rsize = *bufsize; 9977a286c47SDai Ngo 9987a286c47SDai Ngo /* do the door_call */ 9992f172c55SRobert Thurlow retried_doorhd = 0; 10007a286c47SDai Ngo retries = 0; 10017a286c47SDai Ngo door_ki_hold(rp_door); 10027a286c47SDai Ngo while ((err = door_ki_upcall_limited(rp_door, &door_args, 10037a286c47SDai Ngo NULL, SIZE_MAX, 0)) != 0) { 10047a286c47SDai Ngo if (err == EAGAIN || err == EINTR) { 10057a286c47SDai Ngo if (++retries < REPARSED_DOORCALL_MAX_RETRY) { 10067a286c47SDai Ngo delay(SEC_TO_TICK(1)); 10077a286c47SDai Ngo continue; 10087a286c47SDai Ngo } 10097a286c47SDai Ngo } else if (err == EBADF) { 10107a286c47SDai Ngo /* door server goes away... */ 10117a286c47SDai Ngo reparse_door_reset_handle(); 10122f172c55SRobert Thurlow 10132f172c55SRobert Thurlow if (retried_doorhd == 0) { 10142f172c55SRobert Thurlow door_ki_rele(rp_door); 10152f172c55SRobert Thurlow retried_doorhd++; 10162f172c55SRobert Thurlow rp_door = reparse_door_get_handle(); 10172f172c55SRobert Thurlow if (rp_door != NULL) { 10182f172c55SRobert Thurlow door_ki_hold(rp_door); 10192f172c55SRobert Thurlow continue; 10202f172c55SRobert Thurlow } 10212f172c55SRobert Thurlow } 10227a286c47SDai Ngo } 10237a286c47SDai Ngo break; 10247a286c47SDai Ngo } 10252f172c55SRobert Thurlow 10262f172c55SRobert Thurlow if (rp_door) 10272f172c55SRobert Thurlow door_ki_rele(rp_door); 10282f172c55SRobert Thurlow 10297a286c47SDai Ngo if (need_free) 10307a286c47SDai Ngo kmem_free(darg, dlen); /* done with args buffer */ 10317a286c47SDai Ngo 10327a286c47SDai Ngo if (err != 0) 10337a286c47SDai Ngo return (err); 10347a286c47SDai Ngo 10357a286c47SDai Ngo resp = (reparsed_door_res_t *)door_args.rbuf; 10367a286c47SDai Ngo if ((err = resp->res_status) == 0) { 10377a286c47SDai Ngo /* 10387a286c47SDai Ngo * have to save the length of the results before the 10397a286c47SDai Ngo * bcopy below since it's can be an overlap copy that 10407a286c47SDai Ngo * overwrites the reparsed_door_res_t structure at 10417a286c47SDai Ngo * the beginning of the buffer. 10427a286c47SDai Ngo */ 10437a286c47SDai Ngo res_len = (size_t)resp->res_len; 10447a286c47SDai Ngo 10457a286c47SDai Ngo /* deref call is ok */ 10467a286c47SDai Ngo if (res_len > *bufsize) 10477a286c47SDai Ngo err = EOVERFLOW; 10487a286c47SDai Ngo else 10497a286c47SDai Ngo bcopy(resp->res_data, buf, res_len); 10507a286c47SDai Ngo *bufsize = res_len; 10517a286c47SDai Ngo } 10527a286c47SDai Ngo if (door_args.rbuf != buf) 10537a286c47SDai Ngo kmem_free(door_args.rbuf, door_args.rsize); 10547a286c47SDai Ngo 10557a286c47SDai Ngo return (err); 10567a286c47SDai Ngo } 1057