xref: /illumos-gate/usr/src/uts/common/fs/fs_subr.c (revision b8af4a89)
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	*/
22*b8af4a89SLuqman Aden /*	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.
2880d5689fSPatrick Mooney  * Copyright 2017 Joyent, Inc.
29*b8af4a89SLuqman Aden  * Copyright 2022 Oxide Computer Company
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * Generic vnode operations.
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <sys/param.h>
377c478bd9Sstevel@tonic-gate #include <sys/systm.h>
387c478bd9Sstevel@tonic-gate #include <sys/errno.h>
397c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
407c478bd9Sstevel@tonic-gate #include <sys/flock.h>
417c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
427c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
437c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
447c478bd9Sstevel@tonic-gate #include <sys/proc.h>
457c478bd9Sstevel@tonic-gate #include <sys/user.h>
467c478bd9Sstevel@tonic-gate #include <sys/unistd.h>
477c478bd9Sstevel@tonic-gate #include <sys/cred.h>
487c478bd9Sstevel@tonic-gate #include <sys/poll.h>
497c478bd9Sstevel@tonic-gate #include <sys/debug.h>
507c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
517c478bd9Sstevel@tonic-gate #include <sys/stream.h>
527c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
537a286c47SDai Ngo #include <fs/fs_reparse.h>
547a286c47SDai Ngo #include <sys/door.h>
557c478bd9Sstevel@tonic-gate #include <sys/acl.h>
567c478bd9Sstevel@tonic-gate #include <sys/share.h>
577c478bd9Sstevel@tonic-gate #include <sys/file.h>
587c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
597c478bd9Sstevel@tonic-gate #include <sys/file.h>
607c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h>
61fa9e4066Sahrens #include <acl/acl_common.h>
627a286c47SDai Ngo #include <sys/pathname.h>
637c478bd9Sstevel@tonic-gate 
6487bfe94cSPatrick Mooney /* required for fs_reject_epoll */
6587bfe94cSPatrick Mooney #include <sys/poll_impl.h>
6687bfe94cSPatrick Mooney 
677c478bd9Sstevel@tonic-gate static callb_cpr_t *frlock_serialize_blocked(flk_cb_when_t, void *);
687c478bd9Sstevel@tonic-gate 
69dd29fa4aSprabahar /*
70dd29fa4aSprabahar  * Tunable to limit the number of retry to recover from STALE error.
71dd29fa4aSprabahar  */
72dd29fa4aSprabahar int fs_estale_retry = 5;
73dd29fa4aSprabahar 
747a286c47SDai Ngo /*
757a286c47SDai Ngo  * supports for reparse point door upcall
767a286c47SDai Ngo  */
777a286c47SDai Ngo static door_handle_t reparsed_door;
787a286c47SDai Ngo static kmutex_t reparsed_door_lock;
797a286c47SDai Ngo 
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate  * The associated operation is not supported by the file system.
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate int
fs_nosys()847c478bd9Sstevel@tonic-gate fs_nosys()
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	return (ENOSYS);
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate  * The associated operation is invalid (on this vnode).
917c478bd9Sstevel@tonic-gate  */
927c478bd9Sstevel@tonic-gate int
fs_inval()937c478bd9Sstevel@tonic-gate fs_inval()
947c478bd9Sstevel@tonic-gate {
957c478bd9Sstevel@tonic-gate 	return (EINVAL);
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * The associated operation is valid only for directories.
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate int
fs_notdir()1027c478bd9Sstevel@tonic-gate fs_notdir()
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate 	return (ENOTDIR);
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * Free the file system specific resources. For the file systems that
1097c478bd9Sstevel@tonic-gate  * do not support the forced unmount, it will be a nop function.
1107c478bd9Sstevel@tonic-gate  */
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1137c478bd9Sstevel@tonic-gate void
fs_freevfs(vfs_t * vfsp)1147c478bd9Sstevel@tonic-gate fs_freevfs(vfs_t *vfsp)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /* ARGSUSED */
1197c478bd9Sstevel@tonic-gate int
fs_nosys_map(struct vnode * vp,offset_t off,struct as * as,caddr_t * addrp,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)12066848735SMarcel Telka fs_nosys_map(struct vnode *vp, offset_t off, struct as *as, caddr_t *addrp,
12166848735SMarcel Telka     size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr,
12266848735SMarcel Telka     caller_context_t *ct)
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate 	return (ENOSYS);
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /* ARGSUSED */
1287c478bd9Sstevel@tonic-gate int
fs_nosys_addmap(struct vnode * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)12966848735SMarcel Telka fs_nosys_addmap(struct vnode *vp, offset_t off, struct as *as, caddr_t addr,
13066848735SMarcel Telka     size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr,
13166848735SMarcel Telka     caller_context_t *ct)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	return (ENOSYS);
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate /* ARGSUSED */
1377c478bd9Sstevel@tonic-gate int
fs_nosys_poll(vnode_t * vp,short events,int anyyet,short * reventsp,struct pollhead ** phpp,caller_context_t * ct)13866848735SMarcel Telka fs_nosys_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
13966848735SMarcel Telka     struct pollhead **phpp, caller_context_t *ct)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	return (ENOSYS);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate  * The file system has nothing to sync to disk.  However, the
1477c478bd9Sstevel@tonic-gate  * VFS_SYNC operation must not fail.
1487c478bd9Sstevel@tonic-gate  */
1497c478bd9Sstevel@tonic-gate /* ARGSUSED */
1507c478bd9Sstevel@tonic-gate int
fs_sync(struct vfs * vfspp,short flag,cred_t * cr)1517c478bd9Sstevel@tonic-gate fs_sync(struct vfs *vfspp, short flag, cred_t *cr)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	return (0);
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate 
156da6c28aaSamw /*
157da6c28aaSamw  * Does nothing but VOP_FSYNC must not fail.
158da6c28aaSamw  */
159da6c28aaSamw /* ARGSUSED */
160da6c28aaSamw int
fs_fsync(vnode_t * vp,int syncflag,cred_t * cr,caller_context_t * ct)161da6c28aaSamw fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
162da6c28aaSamw {
163da6c28aaSamw 	return (0);
164da6c28aaSamw }
165da6c28aaSamw 
166da6c28aaSamw /*
167da6c28aaSamw  * Does nothing but VOP_PUTPAGE must not fail.
168da6c28aaSamw  */
169da6c28aaSamw /* ARGSUSED */
170da6c28aaSamw int
fs_putpage(vnode_t * vp,offset_t off,size_t len,int flags,cred_t * cr,caller_context_t * ctp)171da6c28aaSamw fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
17266848735SMarcel Telka     caller_context_t *ctp)
173da6c28aaSamw {
174da6c28aaSamw 	return (0);
175da6c28aaSamw }
176da6c28aaSamw 
177da6c28aaSamw /*
178da6c28aaSamw  * Does nothing but VOP_IOCTL must not fail.
179da6c28aaSamw  */
180da6c28aaSamw /* ARGSUSED */
181da6c28aaSamw int
fs_ioctl(vnode_t * vp,int com,intptr_t data,int flag,cred_t * cred,int * rvalp)182da6c28aaSamw fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
18366848735SMarcel Telka     int *rvalp)
184da6c28aaSamw {
185da6c28aaSamw 	return (0);
186da6c28aaSamw }
187da6c28aaSamw 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * Read/write lock/unlock.  Does nothing.
1907c478bd9Sstevel@tonic-gate  */
1917c478bd9Sstevel@tonic-gate /* ARGSUSED */
1927c478bd9Sstevel@tonic-gate int
fs_rwlock(vnode_t * vp,int write_lock,caller_context_t * ctp)1937c478bd9Sstevel@tonic-gate fs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	return (-1);
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate /* ARGSUSED */
1997c478bd9Sstevel@tonic-gate void
fs_rwunlock(vnode_t * vp,int write_lock,caller_context_t * ctp)2007c478bd9Sstevel@tonic-gate fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate /*
2057c478bd9Sstevel@tonic-gate  * Compare two vnodes.
2067c478bd9Sstevel@tonic-gate  */
207da6c28aaSamw /*ARGSUSED2*/
2087c478bd9Sstevel@tonic-gate int
fs_cmp(vnode_t * vp1,vnode_t * vp2,caller_context_t * ct)209da6c28aaSamw fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
2107c478bd9Sstevel@tonic-gate {
2117c478bd9Sstevel@tonic-gate 	return (vp1 == vp2);
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate /*
2157c478bd9Sstevel@tonic-gate  * No-op seek operation.
2167c478bd9Sstevel@tonic-gate  */
2177c478bd9Sstevel@tonic-gate /* ARGSUSED */
2187c478bd9Sstevel@tonic-gate int
fs_seek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)219da6c28aaSamw fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate /*
2257c478bd9Sstevel@tonic-gate  * File and record locking.
2267c478bd9Sstevel@tonic-gate  */
2277c478bd9Sstevel@tonic-gate /* ARGSUSED */
2287c478bd9Sstevel@tonic-gate int
fs_frlock(vnode_t * vp,int cmd,struct flock64 * bfp,int flag,offset_t offset,flk_callback_t * flk_cbp,cred_t * cr,caller_context_t * ct)22966848735SMarcel Telka fs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, offset_t offset,
23066848735SMarcel Telka     flk_callback_t *flk_cbp, cred_t *cr, caller_context_t *ct)
2317c478bd9Sstevel@tonic-gate {
2327c478bd9Sstevel@tonic-gate 	int frcmd;
2337c478bd9Sstevel@tonic-gate 	int nlmid;
2347c478bd9Sstevel@tonic-gate 	int error = 0;
2357a5aac98SJerry Jelinek 	boolean_t skip_lock = B_FALSE;
2367c478bd9Sstevel@tonic-gate 	flk_callback_t serialize_callback;
2377c478bd9Sstevel@tonic-gate 	int serialize = 0;
238da6c28aaSamw 	v_mode_t mode;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	switch (cmd) {
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	case F_GETLK:
2437c478bd9Sstevel@tonic-gate 	case F_O_GETLK:
2447c478bd9Sstevel@tonic-gate 		if (flag & F_REMOTELOCK) {
2457c478bd9Sstevel@tonic-gate 			frcmd = RCMDLCK;
246da6c28aaSamw 		} else if (flag & F_PXFSLOCK) {
2477c478bd9Sstevel@tonic-gate 			frcmd = PCMDLCK;
248da6c28aaSamw 		} else {
249da6c28aaSamw 			frcmd = 0;
250da6c28aaSamw 			bfp->l_pid = ttoproc(curthread)->p_pid;
251da6c28aaSamw 			bfp->l_sysid = 0;
2527c478bd9Sstevel@tonic-gate 		}
2537c478bd9Sstevel@tonic-gate 		break;
2547c478bd9Sstevel@tonic-gate 
2557a5aac98SJerry Jelinek 	case F_OFD_GETLK:
2567a5aac98SJerry Jelinek 		/*
2577a5aac98SJerry Jelinek 		 * TBD we do not support remote OFD locks at this time.
2587a5aac98SJerry Jelinek 		 */
2597a5aac98SJerry Jelinek 		if (flag & (F_REMOTELOCK | F_PXFSLOCK)) {
260*b8af4a89SLuqman Aden 			error = EOPNOTSUPP;
2617a5aac98SJerry Jelinek 			goto done;
2627a5aac98SJerry Jelinek 		}
2637a5aac98SJerry Jelinek 		skip_lock = B_TRUE;
2647a5aac98SJerry Jelinek 		break;
2657a5aac98SJerry Jelinek 
2667c478bd9Sstevel@tonic-gate 	case F_SETLK_NBMAND:
2677c478bd9Sstevel@tonic-gate 		/*
2687c478bd9Sstevel@tonic-gate 		 * Are NBMAND locks allowed on this file?
2697c478bd9Sstevel@tonic-gate 		 */
2707c478bd9Sstevel@tonic-gate 		if (!vp->v_vfsp ||
2717c478bd9Sstevel@tonic-gate 		    !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) {
2727c478bd9Sstevel@tonic-gate 			error = EINVAL;
2737c478bd9Sstevel@tonic-gate 			goto done;
2747c478bd9Sstevel@tonic-gate 		}
2757c478bd9Sstevel@tonic-gate 		if (vp->v_type != VREG) {
2767c478bd9Sstevel@tonic-gate 			error = EINVAL;
2777c478bd9Sstevel@tonic-gate 			goto done;
2787c478bd9Sstevel@tonic-gate 		}
2797c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	case F_SETLK:
282da6c28aaSamw 		if (flag & F_REMOTELOCK) {
283da6c28aaSamw 			frcmd = SETFLCK|RCMDLCK;
284da6c28aaSamw 		} else if (flag & F_PXFSLOCK) {
285da6c28aaSamw 			frcmd = SETFLCK|PCMDLCK;
286da6c28aaSamw 		} else {
287da6c28aaSamw 			frcmd = SETFLCK;
288da6c28aaSamw 			bfp->l_pid = ttoproc(curthread)->p_pid;
289da6c28aaSamw 			bfp->l_sysid = 0;
290da6c28aaSamw 		}
291da6c28aaSamw 		if (cmd == F_SETLK_NBMAND &&
292da6c28aaSamw 		    (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) {
293da6c28aaSamw 			frcmd |= NBMLCK;
294da6c28aaSamw 		}
295b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2967c478bd9Sstevel@tonic-gate 		if (nbl_need_check(vp)) {
2977c478bd9Sstevel@tonic-gate 			nbl_start_crit(vp, RW_WRITER);
2987c478bd9Sstevel@tonic-gate 			serialize = 1;
299da6c28aaSamw 			if (frcmd & NBMLCK) {
300da6c28aaSamw 				mode = (bfp->l_type == F_RDLCK) ?
301da6c28aaSamw 				    V_READ : V_RDANDWR;
302da6c28aaSamw 				if (vn_is_mapped(vp, mode)) {
303da6c28aaSamw 					error = EAGAIN;
304da6c28aaSamw 					goto done;
305da6c28aaSamw 				}
306da6c28aaSamw 			}
3077c478bd9Sstevel@tonic-gate 		}
3087c478bd9Sstevel@tonic-gate 		break;
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	case F_SETLKW:
311da6c28aaSamw 		if (flag & F_REMOTELOCK) {
312da6c28aaSamw 			frcmd = SETFLCK|SLPFLCK|RCMDLCK;
313da6c28aaSamw 		} else if (flag & F_PXFSLOCK) {
314da6c28aaSamw 			frcmd = SETFLCK|SLPFLCK|PCMDLCK;
315da6c28aaSamw 		} else {
316da6c28aaSamw 			frcmd = SETFLCK|SLPFLCK;
317da6c28aaSamw 			bfp->l_pid = ttoproc(curthread)->p_pid;
318da6c28aaSamw 			bfp->l_sysid = 0;
319da6c28aaSamw 		}
320b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3217c478bd9Sstevel@tonic-gate 		if (nbl_need_check(vp)) {
3227c478bd9Sstevel@tonic-gate 			nbl_start_crit(vp, RW_WRITER);
3237c478bd9Sstevel@tonic-gate 			serialize = 1;
3247c478bd9Sstevel@tonic-gate 		}
3257c478bd9Sstevel@tonic-gate 		break;
3267c478bd9Sstevel@tonic-gate 
3277a5aac98SJerry Jelinek 	case F_OFD_SETLK:
3287a5aac98SJerry Jelinek 	case F_OFD_SETLKW:
3297a5aac98SJerry Jelinek 	case F_FLOCK:
3307a5aac98SJerry Jelinek 	case F_FLOCKW:
3317a5aac98SJerry Jelinek 		/*
3327a5aac98SJerry Jelinek 		 * TBD we do not support remote OFD locks at this time.
3337a5aac98SJerry Jelinek 		 */
3347a5aac98SJerry Jelinek 		if (flag & (F_REMOTELOCK | F_PXFSLOCK)) {
335*b8af4a89SLuqman Aden 			error = EOPNOTSUPP;
3367a5aac98SJerry Jelinek 			goto done;
3377a5aac98SJerry Jelinek 		}
3387a5aac98SJerry Jelinek 		skip_lock = B_TRUE;
3397a5aac98SJerry Jelinek 		break;
3407a5aac98SJerry Jelinek 
3417c478bd9Sstevel@tonic-gate 	case F_HASREMOTELOCKS:
3427c478bd9Sstevel@tonic-gate 		nlmid = GETNLMID(bfp->l_sysid);
3437c478bd9Sstevel@tonic-gate 		if (nlmid != 0) {	/* booted as a cluster */
3447c478bd9Sstevel@tonic-gate 			l_has_rmt(bfp) =
345da6c28aaSamw 			    cl_flk_has_remote_locks_for_nlmid(vp, nlmid);
3467c478bd9Sstevel@tonic-gate 		} else {		/* not booted as a cluster */
3477c478bd9Sstevel@tonic-gate 			l_has_rmt(bfp) = flk_has_remote_locks(vp);
3487c478bd9Sstevel@tonic-gate 		}
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 		goto done;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	default:
3537c478bd9Sstevel@tonic-gate 		error = EINVAL;
3547c478bd9Sstevel@tonic-gate 		goto done;
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	/*
3587c478bd9Sstevel@tonic-gate 	 * If this is a blocking lock request and we're serializing lock
3597c478bd9Sstevel@tonic-gate 	 * requests, modify the callback list to leave the critical region
3607c478bd9Sstevel@tonic-gate 	 * while we're waiting for the lock.
3617c478bd9Sstevel@tonic-gate 	 */
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	if (serialize && (frcmd & SLPFLCK) != 0) {
3647c478bd9Sstevel@tonic-gate 		flk_add_callback(&serialize_callback,
365da6c28aaSamw 		    frlock_serialize_blocked, vp, flk_cbp);
3667c478bd9Sstevel@tonic-gate 		flk_cbp = &serialize_callback;
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
3697a5aac98SJerry Jelinek 	if (!skip_lock)
3707a5aac98SJerry Jelinek 		error = reclock(vp, bfp, frcmd, flag, offset, flk_cbp);
3717c478bd9Sstevel@tonic-gate 
37266848735SMarcel Telka 	if (serialize && (frcmd & SLPFLCK) != 0)
37366848735SMarcel Telka 		flk_del_callback(&serialize_callback);
37466848735SMarcel Telka 
3757c478bd9Sstevel@tonic-gate done:
3767c478bd9Sstevel@tonic-gate 	if (serialize)
3777c478bd9Sstevel@tonic-gate 		nbl_end_crit(vp);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	return (error);
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate /*
3837c478bd9Sstevel@tonic-gate  * Callback when a lock request blocks and we are serializing requests.  If
3847c478bd9Sstevel@tonic-gate  * before sleeping, leave the critical region.  If after wakeup, reenter
3857c478bd9Sstevel@tonic-gate  * the critical region.
3867c478bd9Sstevel@tonic-gate  */
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate static callb_cpr_t *
frlock_serialize_blocked(flk_cb_when_t when,void * infop)3897c478bd9Sstevel@tonic-gate frlock_serialize_blocked(flk_cb_when_t when, void *infop)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	vnode_t *vp = (vnode_t *)infop;
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	if (when == FLK_BEFORE_SLEEP)
3947c478bd9Sstevel@tonic-gate 		nbl_end_crit(vp);
3957c478bd9Sstevel@tonic-gate 	else {
3967c478bd9Sstevel@tonic-gate 		nbl_start_crit(vp, RW_WRITER);
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	return (NULL);
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate  * Allow any flags.
4047c478bd9Sstevel@tonic-gate  */
4057c478bd9Sstevel@tonic-gate /* ARGSUSED */
4067c478bd9Sstevel@tonic-gate int
fs_setfl(vnode_t * vp,int oflags,int nflags,cred_t * cr,caller_context_t * ct)40766848735SMarcel Telka fs_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct)
4087c478bd9Sstevel@tonic-gate {
4097c478bd9Sstevel@tonic-gate 	return (0);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate /*
41387bfe94cSPatrick Mooney  * Unlike poll(2), epoll should reject attempts to add normal files or
41487bfe94cSPatrick Mooney  * directories to a given handle.  Most non-pseudo filesystems rely on
41587bfe94cSPatrick Mooney  * fs_poll() as their implementation of polling behavior.  Exceptions to that
41687bfe94cSPatrick Mooney  * rule (ufs) can use fs_reject_epoll(), so they don't require access to the
41787bfe94cSPatrick Mooney  * inner details of poll.  Potential race conditions related to the poll module
41887bfe94cSPatrick Mooney  * being loaded are avoided by implementing the check here in genunix.
4197c478bd9Sstevel@tonic-gate  */
42087bfe94cSPatrick Mooney boolean_t
fs_reject_epoll()42187bfe94cSPatrick Mooney fs_reject_epoll()
42287bfe94cSPatrick Mooney {
42387bfe94cSPatrick Mooney 	/* Check if the currently-active pollcache is epoll-enabled. */
42487bfe94cSPatrick Mooney 	return (curthread->t_pollcache != NULL &&
42587bfe94cSPatrick Mooney 	    (curthread->t_pollcache->pc_flag & PC_EPOLL) != 0);
42687bfe94cSPatrick Mooney }
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate /* ARGSUSED */
4297c478bd9Sstevel@tonic-gate int
fs_poll(vnode_t * vp,short events,int anyyet,short * reventsp,struct pollhead ** phpp,caller_context_t * ct)43066848735SMarcel Telka fs_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
43166848735SMarcel Telka     struct pollhead **phpp, caller_context_t *ct)
4327c478bd9Sstevel@tonic-gate {
43380d5689fSPatrick Mooney 	/*
43487bfe94cSPatrick Mooney 	 * Regular filesystems should reject epollers.  On the off chance that
43587bfe94cSPatrick Mooney 	 * a non-epoll consumer expresses the desire for edge-triggered
43687bfe94cSPatrick Mooney 	 * polling, we reject them too.  Yes, the expected error for this
43787bfe94cSPatrick Mooney 	 * really is EPERM.
43880d5689fSPatrick Mooney 	 */
43987bfe94cSPatrick Mooney 	if (fs_reject_epoll() || (events & POLLET) != 0) {
44080d5689fSPatrick Mooney 		return (EPERM);
44180d5689fSPatrick Mooney 	}
44280d5689fSPatrick Mooney 
4437c478bd9Sstevel@tonic-gate 	*reventsp = 0;
4447c478bd9Sstevel@tonic-gate 	if (events & POLLIN)
4457c478bd9Sstevel@tonic-gate 		*reventsp |= POLLIN;
4467c478bd9Sstevel@tonic-gate 	if (events & POLLRDNORM)
4477c478bd9Sstevel@tonic-gate 		*reventsp |= POLLRDNORM;
4487c478bd9Sstevel@tonic-gate 	if (events & POLLRDBAND)
4497c478bd9Sstevel@tonic-gate 		*reventsp |= POLLRDBAND;
4507c478bd9Sstevel@tonic-gate 	if (events & POLLOUT)
4517c478bd9Sstevel@tonic-gate 		*reventsp |= POLLOUT;
4527c478bd9Sstevel@tonic-gate 	if (events & POLLWRBAND)
4537c478bd9Sstevel@tonic-gate 		*reventsp |= POLLWRBAND;
45487bfe94cSPatrick Mooney 
4557c478bd9Sstevel@tonic-gate 	return (0);
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate /*
4597c478bd9Sstevel@tonic-gate  * POSIX pathconf() support.
4607c478bd9Sstevel@tonic-gate  */
4617c478bd9Sstevel@tonic-gate /* ARGSUSED */
4627c478bd9Sstevel@tonic-gate int
fs_pathconf(vnode_t * vp,int cmd,ulong_t * valp,cred_t * cr,caller_context_t * ct)46366848735SMarcel Telka fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
46466848735SMarcel Telka     caller_context_t *ct)
4657c478bd9Sstevel@tonic-gate {
46666848735SMarcel Telka 	ulong_t val;
46766848735SMarcel Telka 	int error = 0;
4687c478bd9Sstevel@tonic-gate 	struct statvfs64 vfsbuf;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	switch (cmd) {
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	case _PC_LINK_MAX:
4737c478bd9Sstevel@tonic-gate 		val = MAXLINK;
4747c478bd9Sstevel@tonic-gate 		break;
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	case _PC_MAX_CANON:
4777c478bd9Sstevel@tonic-gate 		val = MAX_CANON;
4787c478bd9Sstevel@tonic-gate 		break;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	case _PC_MAX_INPUT:
4817c478bd9Sstevel@tonic-gate 		val = MAX_INPUT;
4827c478bd9Sstevel@tonic-gate 		break;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	case _PC_NAME_MAX:
4857c478bd9Sstevel@tonic-gate 		bzero(&vfsbuf, sizeof (vfsbuf));
4867c478bd9Sstevel@tonic-gate 		if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf))
4877c478bd9Sstevel@tonic-gate 			break;
4887c478bd9Sstevel@tonic-gate 		val = vfsbuf.f_namemax;
4897c478bd9Sstevel@tonic-gate 		break;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	case _PC_PATH_MAX:
4927c478bd9Sstevel@tonic-gate 	case _PC_SYMLINK_MAX:
4937c478bd9Sstevel@tonic-gate 		val = MAXPATHLEN;
4947c478bd9Sstevel@tonic-gate 		break;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	case _PC_PIPE_BUF:
4977c478bd9Sstevel@tonic-gate 		val = PIPE_BUF;
4987c478bd9Sstevel@tonic-gate 		break;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	case _PC_NO_TRUNC:
5017c478bd9Sstevel@tonic-gate 		if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC)
5027c478bd9Sstevel@tonic-gate 			val = 1;	/* NOTRUNC is enabled for vp */
5037c478bd9Sstevel@tonic-gate 		else
5047c478bd9Sstevel@tonic-gate 			val = (ulong_t)-1;
5057c478bd9Sstevel@tonic-gate 		break;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	case _PC_VDISABLE:
5087c478bd9Sstevel@tonic-gate 		val = _POSIX_VDISABLE;
5097c478bd9Sstevel@tonic-gate 		break;
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	case _PC_CHOWN_RESTRICTED:
5127c478bd9Sstevel@tonic-gate 		if (rstchown)
5137c478bd9Sstevel@tonic-gate 			val = rstchown; /* chown restricted enabled */
5147c478bd9Sstevel@tonic-gate 		else
5157c478bd9Sstevel@tonic-gate 			val = (ulong_t)-1;
5167c478bd9Sstevel@tonic-gate 		break;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	case _PC_FILESIZEBITS:
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 		/*
5217c478bd9Sstevel@tonic-gate 		 * If ever we come here it means that underlying file system
5227c478bd9Sstevel@tonic-gate 		 * does not recognise the command and therefore this
5237c478bd9Sstevel@tonic-gate 		 * configurable limit cannot be determined. We return -1
5247c478bd9Sstevel@tonic-gate 		 * and don't change errno.
5257c478bd9Sstevel@tonic-gate 		 */
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 		val = (ulong_t)-1;    /* large file support */
5287c478bd9Sstevel@tonic-gate 		break;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	case _PC_ACL_ENABLED:
5317c478bd9Sstevel@tonic-gate 		val = 0;
5327c478bd9Sstevel@tonic-gate 		break;
5337c478bd9Sstevel@tonic-gate 
534da6c28aaSamw 	case _PC_CASE_BEHAVIOR:
535da6c28aaSamw 		val = _CASE_SENSITIVE;
536da6c28aaSamw 		if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1)
537da6c28aaSamw 			val |= _CASE_INSENSITIVE;
538da6c28aaSamw 		if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1)
539da6c28aaSamw 			val &= ~_CASE_SENSITIVE;
540da6c28aaSamw 		break;
541da6c28aaSamw 
542da6c28aaSamw 	case _PC_SATTR_ENABLED:
543da6c28aaSamw 	case _PC_SATTR_EXISTS:
544da6c28aaSamw 		val = 0;
545e802abbdSTim Haley 		break;
546e802abbdSTim Haley 
547e802abbdSTim Haley 	case _PC_ACCESS_FILTERING:
548e802abbdSTim Haley 		val = 0;
549da6c28aaSamw 		break;
550da6c28aaSamw 
5517c478bd9Sstevel@tonic-gate 	default:
5527c478bd9Sstevel@tonic-gate 		error = EINVAL;
5537c478bd9Sstevel@tonic-gate 		break;
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	if (error == 0)
5577c478bd9Sstevel@tonic-gate 		*valp = val;
5587c478bd9Sstevel@tonic-gate 	return (error);
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate /*
5627c478bd9Sstevel@tonic-gate  * Dispose of a page.
5637c478bd9Sstevel@tonic-gate  */
5647c478bd9Sstevel@tonic-gate /* ARGSUSED */
5657c478bd9Sstevel@tonic-gate void
fs_dispose(struct vnode * vp,page_t * pp,int fl,int dn,struct cred * cr,caller_context_t * ct)56666848735SMarcel Telka fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
56766848735SMarcel Telka     caller_context_t *ct)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	ASSERT(fl == B_FREE || fl == B_INVAL);
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	if (fl == B_FREE)
5737c478bd9Sstevel@tonic-gate 		page_free(pp, dn);
5747c478bd9Sstevel@tonic-gate 	else
5757c478bd9Sstevel@tonic-gate 		page_destroy(pp, dn);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate /* ARGSUSED */
5797c478bd9Sstevel@tonic-gate void
fs_nodispose(struct vnode * vp,page_t * pp,int fl,int dn,struct cred * cr,caller_context_t * ct)58066848735SMarcel Telka fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
58166848735SMarcel Telka     caller_context_t *ct)
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate 	cmn_err(CE_PANIC, "fs_nodispose invoked");
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate /*
5877c478bd9Sstevel@tonic-gate  * fabricate acls for file systems that do not support acls.
5887c478bd9Sstevel@tonic-gate  */
5897c478bd9Sstevel@tonic-gate /* ARGSUSED */
5907c478bd9Sstevel@tonic-gate int
fs_fab_acl(vnode_t * vp,vsecattr_t * vsecattr,int flag,cred_t * cr,caller_context_t * ct)59166848735SMarcel Telka fs_fab_acl(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
59266848735SMarcel Telka     caller_context_t *ct)
5937c478bd9Sstevel@tonic-gate {
5947c478bd9Sstevel@tonic-gate 	aclent_t	*aclentp;
5957c478bd9Sstevel@tonic-gate 	struct vattr	vattr;
5967c478bd9Sstevel@tonic-gate 	int		error;
597da6c28aaSamw 	size_t		aclsize;
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	vsecattr->vsa_aclcnt	= 0;
600da6c28aaSamw 	vsecattr->vsa_aclentsz	= 0;
6017c478bd9Sstevel@tonic-gate 	vsecattr->vsa_aclentp	= NULL;
6027c478bd9Sstevel@tonic-gate 	vsecattr->vsa_dfaclcnt	= 0;	/* Default ACLs are not fabricated */
6037c478bd9Sstevel@tonic-gate 	vsecattr->vsa_dfaclentp	= NULL;
6047c478bd9Sstevel@tonic-gate 
6057b3700d1Sszhou 	vattr.va_mask = AT_MODE | AT_UID | AT_GID;
606da6c28aaSamw 	if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct))
6077b3700d1Sszhou 		return (error);
6087b3700d1Sszhou 
609cf53598eSmarks 	if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
610da6c28aaSamw 		aclsize = 4 * sizeof (aclent_t);
6117b3700d1Sszhou 		vsecattr->vsa_aclcnt	= 4; /* USER, GROUP, OTHER, and CLASS */
612da6c28aaSamw 		vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP);
6137c478bd9Sstevel@tonic-gate 		aclentp = vsecattr->vsa_aclentp;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 		aclentp->a_type = USER_OBJ;	/* Owner */
6167c478bd9Sstevel@tonic-gate 		aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0700)) >> 6;
6177c478bd9Sstevel@tonic-gate 		aclentp->a_id = vattr.va_uid;   /* Really undefined */
6187c478bd9Sstevel@tonic-gate 		aclentp++;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 		aclentp->a_type = GROUP_OBJ;    /* Group */
6217c478bd9Sstevel@tonic-gate 		aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0070)) >> 3;
6227c478bd9Sstevel@tonic-gate 		aclentp->a_id = vattr.va_gid;   /* Really undefined */
6237c478bd9Sstevel@tonic-gate 		aclentp++;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 		aclentp->a_type = OTHER_OBJ;    /* Other */
6267c478bd9Sstevel@tonic-gate 		aclentp->a_perm = vattr.va_mode & 0007;
627f48205beScasper 		aclentp->a_id = (gid_t)-1;	/* Really undefined */
6287c478bd9Sstevel@tonic-gate 		aclentp++;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 		aclentp->a_type = CLASS_OBJ;    /* Class */
6317b3700d1Sszhou 		aclentp->a_perm = (ushort_t)(0007);
632f48205beScasper 		aclentp->a_id = (gid_t)-1;	/* Really undefined */
633cf53598eSmarks 	} else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
63427dd1e87SMark Shellenbaum 		VERIFY(0 == acl_trivial_create(vattr.va_mode,
635a3c49ce1SAlbert Lee 		    (vp->v_type == VDIR), (ace_t **)&vsecattr->vsa_aclentp,
636a3c49ce1SAlbert Lee 		    &vsecattr->vsa_aclcnt));
63727dd1e87SMark Shellenbaum 		vsecattr->vsa_aclentsz = vsecattr->vsa_aclcnt * sizeof (ace_t);
638cf53598eSmarks 	}
6397c478bd9Sstevel@tonic-gate 
64027dd1e87SMark Shellenbaum 	return (error);
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate /*
6447c478bd9Sstevel@tonic-gate  * Common code for implementing DOS share reservations
6457c478bd9Sstevel@tonic-gate  */
6467c478bd9Sstevel@tonic-gate /* ARGSUSED4 */
6477c478bd9Sstevel@tonic-gate int
fs_shrlock(struct vnode * vp,int cmd,struct shrlock * shr,int flag,cred_t * cr,caller_context_t * ct)64866848735SMarcel Telka fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
64966848735SMarcel Telka     caller_context_t *ct)
6507c478bd9Sstevel@tonic-gate {
6517c478bd9Sstevel@tonic-gate 	int error;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	/*
6547c478bd9Sstevel@tonic-gate 	 * Make sure that the file was opened with permissions appropriate
6557c478bd9Sstevel@tonic-gate 	 * for the request, and make sure the caller isn't trying to sneak
6567c478bd9Sstevel@tonic-gate 	 * in an NBMAND request.
6577c478bd9Sstevel@tonic-gate 	 */
6587c478bd9Sstevel@tonic-gate 	if (cmd == F_SHARE) {
6597c478bd9Sstevel@tonic-gate 		if (((shr->s_access & F_RDACC) && (flag & FREAD) == 0) ||
6607c478bd9Sstevel@tonic-gate 		    ((shr->s_access & F_WRACC) && (flag & FWRITE) == 0))
6617c478bd9Sstevel@tonic-gate 			return (EBADF);
662da6c28aaSamw 		if (shr->s_access & (F_RMACC | F_MDACC))
663da6c28aaSamw 			return (EINVAL);
664da6c28aaSamw 		if (shr->s_deny & (F_MANDDNY | F_RMDNY))
6657c478bd9Sstevel@tonic-gate 			return (EINVAL);
6667c478bd9Sstevel@tonic-gate 	}
6677c478bd9Sstevel@tonic-gate 	if (cmd == F_SHARE_NBMAND) {
6687c478bd9Sstevel@tonic-gate 		/* make sure nbmand is allowed on the file */
6697c478bd9Sstevel@tonic-gate 		if (!vp->v_vfsp ||
6707c478bd9Sstevel@tonic-gate 		    !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) {
6717c478bd9Sstevel@tonic-gate 			return (EINVAL);
6727c478bd9Sstevel@tonic-gate 		}
6737c478bd9Sstevel@tonic-gate 		if (vp->v_type != VREG) {
6747c478bd9Sstevel@tonic-gate 			return (EINVAL);
6757c478bd9Sstevel@tonic-gate 		}
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	nbl_start_crit(vp, RW_WRITER);
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	switch (cmd) {
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	case F_SHARE_NBMAND:
6837c478bd9Sstevel@tonic-gate 		shr->s_deny |= F_MANDDNY;
6847c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
6857c478bd9Sstevel@tonic-gate 	case F_SHARE:
6867c478bd9Sstevel@tonic-gate 		error = add_share(vp, shr);
6877c478bd9Sstevel@tonic-gate 		break;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	case F_UNSHARE:
6907c478bd9Sstevel@tonic-gate 		error = del_share(vp, shr);
6917c478bd9Sstevel@tonic-gate 		break;
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	case F_HASREMOTELOCKS:
6947c478bd9Sstevel@tonic-gate 		/*
6957c478bd9Sstevel@tonic-gate 		 * We are overloading this command to refer to remote
6967c478bd9Sstevel@tonic-gate 		 * shares as well as remote locks, despite its name.
6977c478bd9Sstevel@tonic-gate 		 */
6987c478bd9Sstevel@tonic-gate 		shr->s_access = shr_has_remote_shares(vp, shr->s_sysid);
6997c478bd9Sstevel@tonic-gate 		error = 0;
7007c478bd9Sstevel@tonic-gate 		break;
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	default:
7037c478bd9Sstevel@tonic-gate 		error = EINVAL;
7047c478bd9Sstevel@tonic-gate 		break;
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	nbl_end_crit(vp);
7087c478bd9Sstevel@tonic-gate 	return (error);
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
7127c478bd9Sstevel@tonic-gate int
fs_vnevent_nosupport(vnode_t * vp,vnevent_t e,vnode_t * dvp,char * fnm,caller_context_t * ct)713da6c28aaSamw fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
714da6c28aaSamw     caller_context_t *ct)
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate 	ASSERT(vp != NULL);
7177c478bd9Sstevel@tonic-gate 	return (ENOTSUP);
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
7217c478bd9Sstevel@tonic-gate int
fs_vnevent_support(vnode_t * vp,vnevent_t e,vnode_t * dvp,char * fnm,caller_context_t * ct)722da6c28aaSamw fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
723da6c28aaSamw     caller_context_t *ct)
7247c478bd9Sstevel@tonic-gate {
7257c478bd9Sstevel@tonic-gate 	ASSERT(vp != NULL);
7267c478bd9Sstevel@tonic-gate 	return (0);
7277c478bd9Sstevel@tonic-gate }
728fa9e4066Sahrens 
729fa9e4066Sahrens /*
730fa9e4066Sahrens  * return 1 for non-trivial ACL.
731fa9e4066Sahrens  *
732fa9e4066Sahrens  * NB: It is not necessary for the caller to VOP_RWLOCK since
733fa9e4066Sahrens  *	we only issue VOP_GETSECATTR.
734fa9e4066Sahrens  *
735fa9e4066Sahrens  * Returns 0 == trivial
736fa9e4066Sahrens  *         1 == NOT Trivial
737fa9e4066Sahrens  *	   <0 could not determine.
738fa9e4066Sahrens  */
739fa9e4066Sahrens int
fs_acl_nontrivial(vnode_t * vp,cred_t * cr)740fa9e4066Sahrens fs_acl_nontrivial(vnode_t *vp, cred_t *cr)
741fa9e4066Sahrens {
742fa9e4066Sahrens 	ulong_t		acl_styles;
743fa9e4066Sahrens 	ulong_t		acl_flavor;
744*b8af4a89SLuqman Aden 	vsecattr_t	vsecattr;
745*b8af4a89SLuqman Aden 	int		error;
746fa9e4066Sahrens 	int		isnontrivial;
747fa9e4066Sahrens 
748fa9e4066Sahrens 	/* determine the forms of ACLs maintained */
749da6c28aaSamw 	error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &acl_styles, cr, NULL);
750fa9e4066Sahrens 
751fa9e4066Sahrens 	/* clear bits we don't understand and establish default acl_style */
752fa9e4066Sahrens 	acl_styles &= (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED);
753fa9e4066Sahrens 	if (error || (acl_styles == 0))
754fa9e4066Sahrens 		acl_styles = _ACL_ACLENT_ENABLED;
755fa9e4066Sahrens 
756fa9e4066Sahrens 	vsecattr.vsa_aclentp = NULL;
757fa9e4066Sahrens 	vsecattr.vsa_dfaclentp = NULL;
758fa9e4066Sahrens 	vsecattr.vsa_aclcnt = 0;
759fa9e4066Sahrens 	vsecattr.vsa_dfaclcnt = 0;
760fa9e4066Sahrens 
761fa9e4066Sahrens 	while (acl_styles) {
762fa9e4066Sahrens 		/* select one of the styles as current flavor */
763fa9e4066Sahrens 		acl_flavor = 0;
764fa9e4066Sahrens 		if (acl_styles & _ACL_ACLENT_ENABLED) {
765fa9e4066Sahrens 			acl_flavor = _ACL_ACLENT_ENABLED;
766fa9e4066Sahrens 			vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT;
767fa9e4066Sahrens 		} else if (acl_styles & _ACL_ACE_ENABLED) {
768fa9e4066Sahrens 			acl_flavor = _ACL_ACE_ENABLED;
769fa9e4066Sahrens 			vsecattr.vsa_mask = VSA_ACECNT | VSA_ACE;
770fa9e4066Sahrens 		}
771fa9e4066Sahrens 
772fa9e4066Sahrens 		ASSERT(vsecattr.vsa_mask && acl_flavor);
773da6c28aaSamw 		error = VOP_GETSECATTR(vp, &vsecattr, 0, cr, NULL);
774fa9e4066Sahrens 		if (error == 0)
775fa9e4066Sahrens 			break;
776fa9e4066Sahrens 
777fa9e4066Sahrens 		/* that flavor failed */
778fa9e4066Sahrens 		acl_styles &= ~acl_flavor;
779fa9e4066Sahrens 	}
780fa9e4066Sahrens 
781fa9e4066Sahrens 	/* if all styles fail then assume trivial */
782fa9e4066Sahrens 	if (acl_styles == 0)
783fa9e4066Sahrens 		return (0);
784fa9e4066Sahrens 
785fa9e4066Sahrens 	/* process the flavor that worked */
786fa9e4066Sahrens 	isnontrivial = 0;
787fa9e4066Sahrens 	if (acl_flavor & _ACL_ACLENT_ENABLED) {
788fa9e4066Sahrens 		if (vsecattr.vsa_aclcnt > MIN_ACL_ENTRIES)
789fa9e4066Sahrens 			isnontrivial = 1;
790fa9e4066Sahrens 		if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL)
791fa9e4066Sahrens 			kmem_free(vsecattr.vsa_aclentp,
792fa9e4066Sahrens 			    vsecattr.vsa_aclcnt * sizeof (aclent_t));
793fa9e4066Sahrens 		if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp != NULL)
794fa9e4066Sahrens 			kmem_free(vsecattr.vsa_dfaclentp,
795fa9e4066Sahrens 			    vsecattr.vsa_dfaclcnt * sizeof (aclent_t));
796fa9e4066Sahrens 	}
797fa9e4066Sahrens 	if (acl_flavor & _ACL_ACE_ENABLED) {
798fa9e4066Sahrens 		isnontrivial = ace_trivial(vsecattr.vsa_aclentp,
799fa9e4066Sahrens 		    vsecattr.vsa_aclcnt);
800fa9e4066Sahrens 
801fa9e4066Sahrens 		if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL)
802fa9e4066Sahrens 			kmem_free(vsecattr.vsa_aclentp,
803fa9e4066Sahrens 			    vsecattr.vsa_aclcnt * sizeof (ace_t));
804fa9e4066Sahrens 		/* ACE has no vsecattr.vsa_dfaclcnt */
805fa9e4066Sahrens 	}
806fa9e4066Sahrens 	return (isnontrivial);
807fa9e4066Sahrens }
808dd29fa4aSprabahar 
809dd29fa4aSprabahar /*
810dd29fa4aSprabahar  * Check whether we need a retry to recover from STALE error.
811dd29fa4aSprabahar  */
812dd29fa4aSprabahar int
fs_need_estale_retry(int retry_count)813dd29fa4aSprabahar fs_need_estale_retry(int retry_count)
814dd29fa4aSprabahar {
815dd29fa4aSprabahar 	if (retry_count < fs_estale_retry)
816dd29fa4aSprabahar 		return (1);
817dd29fa4aSprabahar 	else
818dd29fa4aSprabahar 		return (0);
819dd29fa4aSprabahar }
820da6c28aaSamw 
821da6c28aaSamw 
822da6c28aaSamw static int (*fs_av_scan)(vnode_t *, cred_t *, int) = NULL;
823da6c28aaSamw 
824da6c28aaSamw /*
825da6c28aaSamw  * Routine for anti-virus scanner to call to register its scanning routine.
826da6c28aaSamw  */
827da6c28aaSamw void
fs_vscan_register(int (* av_scan)(vnode_t *,cred_t *,int))828da6c28aaSamw fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int))
829da6c28aaSamw {
830da6c28aaSamw 	fs_av_scan = av_scan;
831da6c28aaSamw }
832da6c28aaSamw 
833da6c28aaSamw /*
834da6c28aaSamw  * Routine for file systems to call to initiate anti-virus scanning.
835da6c28aaSamw  * Scanning will only be done on REGular files (currently).
836da6c28aaSamw  */
837da6c28aaSamw int
fs_vscan(vnode_t * vp,cred_t * cr,int async)838da6c28aaSamw fs_vscan(vnode_t *vp, cred_t *cr, int async)
839da6c28aaSamw {
840da6c28aaSamw 	int ret = 0;
841da6c28aaSamw 
842da6c28aaSamw 	if (fs_av_scan && vp->v_type == VREG)
843da6c28aaSamw 		ret = (*fs_av_scan)(vp, cr, async);
844da6c28aaSamw 
845da6c28aaSamw 	return (ret);
846da6c28aaSamw }
8477a286c47SDai Ngo 
8487a286c47SDai Ngo /*
8497a286c47SDai Ngo  * support functions for reparse point
8507a286c47SDai Ngo  */
8517a286c47SDai Ngo /*
8527a286c47SDai Ngo  * reparse_vnode_parse
8537a286c47SDai Ngo  *
8547a286c47SDai Ngo  * Read the symlink data of a reparse point specified by the vnode
8557a286c47SDai Ngo  * and return the reparse data as name-value pair in the nvlist.
8567a286c47SDai Ngo  */
8577a286c47SDai Ngo int
reparse_vnode_parse(vnode_t * vp,nvlist_t * nvl)8587a286c47SDai Ngo reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl)
8597a286c47SDai Ngo {
8607a286c47SDai Ngo 	int err;
8617a286c47SDai Ngo 	char *lkdata;
8627a286c47SDai Ngo 	struct uio uio;
8637a286c47SDai Ngo 	struct iovec iov;
8647a286c47SDai Ngo 
8657a286c47SDai Ngo 	if (vp == NULL || nvl == NULL)
8667a286c47SDai Ngo 		return (EINVAL);
8677a286c47SDai Ngo 
8687a286c47SDai Ngo 	lkdata = kmem_alloc(MAXREPARSELEN, KM_SLEEP);
8697a286c47SDai Ngo 
8707a286c47SDai Ngo 	/*
8717a286c47SDai Ngo 	 * Set up io vector to read sym link data
8727a286c47SDai Ngo 	 */
8737a286c47SDai Ngo 	iov.iov_base = lkdata;
8747a286c47SDai Ngo 	iov.iov_len = MAXREPARSELEN;
8757a286c47SDai Ngo 	uio.uio_iov = &iov;
8767a286c47SDai Ngo 	uio.uio_iovcnt = 1;
8777a286c47SDai Ngo 	uio.uio_segflg = UIO_SYSSPACE;
8787a286c47SDai Ngo 	uio.uio_extflg = UIO_COPY_CACHED;
8797a286c47SDai Ngo 	uio.uio_loffset = (offset_t)0;
8807a286c47SDai Ngo 	uio.uio_resid = MAXREPARSELEN;
8817a286c47SDai Ngo 
8827a286c47SDai Ngo 	if ((err = VOP_READLINK(vp, &uio, kcred, NULL)) == 0) {
8837a286c47SDai Ngo 		*(lkdata + MAXREPARSELEN - uio.uio_resid) = '\0';
8847a286c47SDai Ngo 		err = reparse_parse(lkdata, nvl);
8857a286c47SDai Ngo 	}
8867a286c47SDai Ngo 	kmem_free(lkdata, MAXREPARSELEN);	/* done with lkdata */
8877a286c47SDai Ngo 
8887a286c47SDai Ngo 	return (err);
8897a286c47SDai Ngo }
8907a286c47SDai Ngo 
8917a286c47SDai Ngo void
reparse_point_init()8927a286c47SDai Ngo reparse_point_init()
8937a286c47SDai Ngo {
8947a286c47SDai Ngo 	mutex_init(&reparsed_door_lock, NULL, MUTEX_DEFAULT, NULL);
8957a286c47SDai Ngo }
8967a286c47SDai Ngo 
8977a286c47SDai Ngo static door_handle_t
reparse_door_get_handle()8987a286c47SDai Ngo reparse_door_get_handle()
8997a286c47SDai Ngo {
9007a286c47SDai Ngo 	door_handle_t dh;
9017a286c47SDai Ngo 
9027a286c47SDai Ngo 	mutex_enter(&reparsed_door_lock);
9037a286c47SDai Ngo 	if ((dh = reparsed_door) == NULL) {
9047a286c47SDai Ngo 		if (door_ki_open(REPARSED_DOOR, &reparsed_door) != 0) {
9057a286c47SDai Ngo 			reparsed_door = NULL;
9067a286c47SDai Ngo 			dh = NULL;
9077a286c47SDai Ngo 		} else
9087a286c47SDai Ngo 			dh = reparsed_door;
9097a286c47SDai Ngo 	}
9107a286c47SDai Ngo 	mutex_exit(&reparsed_door_lock);
9117a286c47SDai Ngo 	return (dh);
9127a286c47SDai Ngo }
9137a286c47SDai Ngo 
9147a286c47SDai Ngo static void
reparse_door_reset_handle()9157a286c47SDai Ngo reparse_door_reset_handle()
9167a286c47SDai Ngo {
9177a286c47SDai Ngo 	mutex_enter(&reparsed_door_lock);
9187a286c47SDai Ngo 	reparsed_door = NULL;
9197a286c47SDai Ngo 	mutex_exit(&reparsed_door_lock);
9207a286c47SDai Ngo }
9217a286c47SDai Ngo 
9227a286c47SDai Ngo /*
9237a286c47SDai Ngo  * reparse_kderef
9247a286c47SDai Ngo  *
9257a286c47SDai Ngo  * Accepts the service-specific item from the reparse point and returns
9267a286c47SDai Ngo  * the service-specific data requested.  The caller specifies the size of
9277a286c47SDai Ngo  * the buffer provided via *bufsz; the routine will fail with EOVERFLOW
9287a286c47SDai Ngo  * if the results will not fit in the buffer, in which case, *bufsz will
9297a286c47SDai Ngo  * contain the number of bytes needed to hold the results.
9307a286c47SDai Ngo  *
9317a286c47SDai Ngo  * if ok return 0 and update *bufsize with length of actual result
9327a286c47SDai Ngo  * else return error code.
9337a286c47SDai Ngo  */
9347a286c47SDai Ngo int
reparse_kderef(const char * svc_type,const char * svc_data,char * buf,size_t * bufsize)9357a286c47SDai Ngo reparse_kderef(const char *svc_type, const char *svc_data, char *buf,
9367a286c47SDai Ngo     size_t *bufsize)
9377a286c47SDai Ngo {
9382f172c55SRobert Thurlow 	int err, retries, need_free, retried_doorhd;
9397a286c47SDai Ngo 	size_t dlen, res_len;
9407a286c47SDai Ngo 	char *darg;
9417a286c47SDai Ngo 	door_arg_t door_args;
9427a286c47SDai Ngo 	reparsed_door_res_t *resp;
9437a286c47SDai Ngo 	door_handle_t rp_door;
9447a286c47SDai Ngo 
9457a286c47SDai Ngo 	if (svc_type == NULL || svc_data == NULL || buf == NULL ||
9467a286c47SDai Ngo 	    bufsize == NULL)
9477a286c47SDai Ngo 		return (EINVAL);
9487a286c47SDai Ngo 
9497a286c47SDai Ngo 	/* get reparsed's door handle */
9507a286c47SDai Ngo 	if ((rp_door = reparse_door_get_handle()) == NULL)
9517a286c47SDai Ngo 		return (EBADF);
9527a286c47SDai Ngo 
9537a286c47SDai Ngo 	/* setup buffer for door_call args and results */
9547a286c47SDai Ngo 	dlen = strlen(svc_type) + strlen(svc_data) + 2;
9557a286c47SDai Ngo 	if (*bufsize < dlen) {
9567a286c47SDai Ngo 		darg = kmem_alloc(dlen, KM_SLEEP);
9577a286c47SDai Ngo 		need_free = 1;
9587a286c47SDai Ngo 	} else {
9597a286c47SDai Ngo 		darg = buf;	/* use same buffer for door's args & results */
9607a286c47SDai Ngo 		need_free = 0;
9617a286c47SDai Ngo 	}
9627a286c47SDai Ngo 
9637a286c47SDai Ngo 	/* build argument string of door call */
9647a286c47SDai Ngo 	(void) snprintf(darg, dlen, "%s:%s", svc_type, svc_data);
9657a286c47SDai Ngo 
9667a286c47SDai Ngo 	/* setup args for door call */
9677a286c47SDai Ngo 	door_args.data_ptr = darg;
9687a286c47SDai Ngo 	door_args.data_size = dlen;
9697a286c47SDai Ngo 	door_args.desc_ptr = NULL;
9707a286c47SDai Ngo 	door_args.desc_num = 0;
9717a286c47SDai Ngo 	door_args.rbuf = buf;
9727a286c47SDai Ngo 	door_args.rsize = *bufsize;
9737a286c47SDai Ngo 
9747a286c47SDai Ngo 	/* do the door_call */
9752f172c55SRobert Thurlow 	retried_doorhd = 0;
9767a286c47SDai Ngo 	retries = 0;
9777a286c47SDai Ngo 	door_ki_hold(rp_door);
9787a286c47SDai Ngo 	while ((err = door_ki_upcall_limited(rp_door, &door_args,
9797a286c47SDai Ngo 	    NULL, SIZE_MAX, 0)) != 0) {
9807a286c47SDai Ngo 		if (err == EAGAIN || err == EINTR) {
9817a286c47SDai Ngo 			if (++retries < REPARSED_DOORCALL_MAX_RETRY) {
9827a286c47SDai Ngo 				delay(SEC_TO_TICK(1));
9837a286c47SDai Ngo 				continue;
9847a286c47SDai Ngo 			}
9857a286c47SDai Ngo 		} else if (err == EBADF) {
9867a286c47SDai Ngo 			/* door server goes away... */
9877a286c47SDai Ngo 			reparse_door_reset_handle();
9882f172c55SRobert Thurlow 
9892f172c55SRobert Thurlow 			if (retried_doorhd == 0) {
9902f172c55SRobert Thurlow 				door_ki_rele(rp_door);
9912f172c55SRobert Thurlow 				retried_doorhd++;
9922f172c55SRobert Thurlow 				rp_door = reparse_door_get_handle();
9932f172c55SRobert Thurlow 				if (rp_door != NULL) {
9942f172c55SRobert Thurlow 					door_ki_hold(rp_door);
9952f172c55SRobert Thurlow 					continue;
9962f172c55SRobert Thurlow 				}
9972f172c55SRobert Thurlow 			}
9987a286c47SDai Ngo 		}
9997a286c47SDai Ngo 		break;
10007a286c47SDai Ngo 	}
10012f172c55SRobert Thurlow 
10022f172c55SRobert Thurlow 	if (rp_door)
10032f172c55SRobert Thurlow 		door_ki_rele(rp_door);
10042f172c55SRobert Thurlow 
10057a286c47SDai Ngo 	if (need_free)
10067a286c47SDai Ngo 		kmem_free(darg, dlen);		/* done with args buffer */
10077a286c47SDai Ngo 
10087a286c47SDai Ngo 	if (err != 0)
10097a286c47SDai Ngo 		return (err);
10107a286c47SDai Ngo 
10117a286c47SDai Ngo 	resp = (reparsed_door_res_t *)door_args.rbuf;
10127a286c47SDai Ngo 	if ((err = resp->res_status) == 0) {
10137a286c47SDai Ngo 		/*
10147a286c47SDai Ngo 		 * have to save the length of the results before the
10157a286c47SDai Ngo 		 * bcopy below since it's can be an overlap copy that
10167a286c47SDai Ngo 		 * overwrites the reparsed_door_res_t structure at
10177a286c47SDai Ngo 		 * the beginning of the buffer.
10187a286c47SDai Ngo 		 */
10197a286c47SDai Ngo 		res_len = (size_t)resp->res_len;
10207a286c47SDai Ngo 
10217a286c47SDai Ngo 		/* deref call is ok */
10227a286c47SDai Ngo 		if (res_len > *bufsize)
10237a286c47SDai Ngo 			err = EOVERFLOW;
10247a286c47SDai Ngo 		else
10257a286c47SDai Ngo 			bcopy(resp->res_data, buf, res_len);
10267a286c47SDai Ngo 		*bufsize = res_len;
10277a286c47SDai Ngo 	}
10287a286c47SDai Ngo 	if (door_args.rbuf != buf)
10297a286c47SDai Ngo 		kmem_free(door_args.rbuf, door_args.rsize);
10307a286c47SDai Ngo 
10317a286c47SDai Ngo 	return (err);
10327a286c47SDai Ngo }
1033