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.
287a5aac98SJerry 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
657c478bd9Sstevel@tonic-gate /*
66dd29fa4aSprabahar * Tunable to limit the number of retry to recover from STALE error.
67dd29fa4aSprabahar */
68dd29fa4aSprabahar int fs_estale_retry = 5;
69dd29fa4aSprabahar
70dd29fa4aSprabahar /*
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
767a286c47SDai Ngo /*
777c478bd9Sstevel@tonic-gate * The associated operation is not supported by the file system.
787c478bd9Sstevel@tonic-gate */
797c478bd9Sstevel@tonic-gate int
fs_nosys()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
fs_inval()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
fs_notdir()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
fs_freevfs(vfs_t * vfsp)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
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)116*74a91888SMarcel Telka fs_nosys_map(struct vnode *vp, offset_t off, struct as *as, caddr_t *addrp,
117*74a91888SMarcel Telka size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr,
118da6c28aaSamw caller_context_t *ct)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate return (ENOSYS);
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate /* ARGSUSED */
1247c478bd9Sstevel@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)125*74a91888SMarcel Telka fs_nosys_addmap(struct vnode *vp, offset_t off, struct as *as, caddr_t addr,
126*74a91888SMarcel Telka size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr,
127da6c28aaSamw caller_context_t *ct)
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate return (ENOSYS);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate /* ARGSUSED */
1337c478bd9Sstevel@tonic-gate int
fs_nosys_poll(vnode_t * vp,short events,int anyyet,short * reventsp,struct pollhead ** phpp,caller_context_t * ct)134*74a91888SMarcel Telka fs_nosys_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
135*74a91888SMarcel Telka struct pollhead **phpp, caller_context_t *ct)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate return (ENOSYS);
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate * The file system has nothing to sync to disk. However, the
1437c478bd9Sstevel@tonic-gate * VFS_SYNC operation must not fail.
1447c478bd9Sstevel@tonic-gate */
1457c478bd9Sstevel@tonic-gate /* ARGSUSED */
1467c478bd9Sstevel@tonic-gate int
fs_sync(struct vfs * vfspp,short flag,cred_t * cr)1477c478bd9Sstevel@tonic-gate fs_sync(struct vfs *vfspp, short flag, cred_t *cr)
1487c478bd9Sstevel@tonic-gate {
1497c478bd9Sstevel@tonic-gate return (0);
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate /*
153da6c28aaSamw * Does nothing but VOP_FSYNC must not fail.
154da6c28aaSamw */
155da6c28aaSamw /* ARGSUSED */
156da6c28aaSamw int
fs_fsync(vnode_t * vp,int syncflag,cred_t * cr,caller_context_t * ct)157da6c28aaSamw fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
158da6c28aaSamw {
159da6c28aaSamw return (0);
160da6c28aaSamw }
161da6c28aaSamw
162da6c28aaSamw /*
163da6c28aaSamw * Does nothing but VOP_PUTPAGE must not fail.
164da6c28aaSamw */
165da6c28aaSamw /* ARGSUSED */
166da6c28aaSamw int
fs_putpage(vnode_t * vp,offset_t off,size_t len,int flags,cred_t * cr,caller_context_t * ctp)167da6c28aaSamw fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
168da6c28aaSamw caller_context_t *ctp)
169da6c28aaSamw {
170da6c28aaSamw return (0);
171da6c28aaSamw }
172da6c28aaSamw
173da6c28aaSamw /*
174da6c28aaSamw * Does nothing but VOP_IOCTL must not fail.
175da6c28aaSamw */
176da6c28aaSamw /* ARGSUSED */
177da6c28aaSamw int
fs_ioctl(vnode_t * vp,int com,intptr_t data,int flag,cred_t * cred,int * rvalp)178da6c28aaSamw fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
179da6c28aaSamw int *rvalp)
180da6c28aaSamw {
181da6c28aaSamw return (0);
182da6c28aaSamw }
183da6c28aaSamw
184da6c28aaSamw /*
1857c478bd9Sstevel@tonic-gate * Read/write lock/unlock. Does nothing.
1867c478bd9Sstevel@tonic-gate */
1877c478bd9Sstevel@tonic-gate /* ARGSUSED */
1887c478bd9Sstevel@tonic-gate int
fs_rwlock(vnode_t * vp,int write_lock,caller_context_t * ctp)1897c478bd9Sstevel@tonic-gate fs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate return (-1);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate /* ARGSUSED */
1957c478bd9Sstevel@tonic-gate void
fs_rwunlock(vnode_t * vp,int write_lock,caller_context_t * ctp)1967c478bd9Sstevel@tonic-gate fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate * Compare two vnodes.
2027c478bd9Sstevel@tonic-gate */
203da6c28aaSamw /*ARGSUSED2*/
2047c478bd9Sstevel@tonic-gate int
fs_cmp(vnode_t * vp1,vnode_t * vp2,caller_context_t * ct)205da6c28aaSamw fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate return (vp1 == vp2);
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate /*
2117c478bd9Sstevel@tonic-gate * No-op seek operation.
2127c478bd9Sstevel@tonic-gate */
2137c478bd9Sstevel@tonic-gate /* ARGSUSED */
2147c478bd9Sstevel@tonic-gate int
fs_seek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)215da6c28aaSamw fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
2167c478bd9Sstevel@tonic-gate {
2177c478bd9Sstevel@tonic-gate return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate /*
2217c478bd9Sstevel@tonic-gate * File and record locking.
2227c478bd9Sstevel@tonic-gate */
2237c478bd9Sstevel@tonic-gate /* ARGSUSED */
2247c478bd9Sstevel@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)225*74a91888SMarcel Telka fs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, offset_t offset,
226*74a91888SMarcel Telka flk_callback_t *flk_cbp, cred_t *cr, caller_context_t *ct)
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate int frcmd;
2297c478bd9Sstevel@tonic-gate int nlmid;
2307c478bd9Sstevel@tonic-gate int error = 0;
2317a5aac98SJerry Jelinek boolean_t skip_lock = B_FALSE;
2327c478bd9Sstevel@tonic-gate flk_callback_t serialize_callback;
2337c478bd9Sstevel@tonic-gate int serialize = 0;
234da6c28aaSamw v_mode_t mode;
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate switch (cmd) {
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate case F_GETLK:
2397c478bd9Sstevel@tonic-gate case F_O_GETLK:
2407c478bd9Sstevel@tonic-gate if (flag & F_REMOTELOCK) {
2417c478bd9Sstevel@tonic-gate frcmd = RCMDLCK;
242da6c28aaSamw } else if (flag & F_PXFSLOCK) {
2437c478bd9Sstevel@tonic-gate frcmd = PCMDLCK;
244da6c28aaSamw } else {
245da6c28aaSamw frcmd = 0;
2467c478bd9Sstevel@tonic-gate bfp->l_pid = ttoproc(curthread)->p_pid;
2477c478bd9Sstevel@tonic-gate bfp->l_sysid = 0;
248da6c28aaSamw }
2497c478bd9Sstevel@tonic-gate break;
2507c478bd9Sstevel@tonic-gate
2517a5aac98SJerry Jelinek case F_OFD_GETLK:
2527a5aac98SJerry Jelinek /*
2537a5aac98SJerry Jelinek * TBD we do not support remote OFD locks at this time.
2547a5aac98SJerry Jelinek */
2557a5aac98SJerry Jelinek if (flag & (F_REMOTELOCK | F_PXFSLOCK)) {
2567a5aac98SJerry Jelinek error = EINVAL;
2577a5aac98SJerry Jelinek goto done;
2587a5aac98SJerry Jelinek }
2597a5aac98SJerry Jelinek skip_lock = B_TRUE;
2607a5aac98SJerry Jelinek break;
2617a5aac98SJerry Jelinek
2627c478bd9Sstevel@tonic-gate case F_SETLK_NBMAND:
2637c478bd9Sstevel@tonic-gate /*
2647c478bd9Sstevel@tonic-gate * Are NBMAND locks allowed on this file?
2657c478bd9Sstevel@tonic-gate */
2667c478bd9Sstevel@tonic-gate if (!vp->v_vfsp ||
2677c478bd9Sstevel@tonic-gate !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) {
2687c478bd9Sstevel@tonic-gate error = EINVAL;
2697c478bd9Sstevel@tonic-gate goto done;
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) {
2727c478bd9Sstevel@tonic-gate error = EINVAL;
2737c478bd9Sstevel@tonic-gate goto done;
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate case F_SETLK:
278da6c28aaSamw if (flag & F_REMOTELOCK) {
279da6c28aaSamw frcmd = SETFLCK|RCMDLCK;
280da6c28aaSamw } else if (flag & F_PXFSLOCK) {
281da6c28aaSamw frcmd = SETFLCK|PCMDLCK;
282da6c28aaSamw } else {
283da6c28aaSamw frcmd = SETFLCK;
284da6c28aaSamw bfp->l_pid = ttoproc(curthread)->p_pid;
285da6c28aaSamw bfp->l_sysid = 0;
286da6c28aaSamw }
287da6c28aaSamw if (cmd == F_SETLK_NBMAND &&
288da6c28aaSamw (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) {
289da6c28aaSamw frcmd |= NBMLCK;
290da6c28aaSamw }
291b89a8333Snatalie li - Sun Microsystems - Irvine United States
2927c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) {
2937c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_WRITER);
2947c478bd9Sstevel@tonic-gate serialize = 1;
295da6c28aaSamw if (frcmd & NBMLCK) {
296da6c28aaSamw mode = (bfp->l_type == F_RDLCK) ?
297da6c28aaSamw V_READ : V_RDANDWR;
298da6c28aaSamw if (vn_is_mapped(vp, mode)) {
299da6c28aaSamw error = EAGAIN;
300da6c28aaSamw goto done;
301da6c28aaSamw }
302da6c28aaSamw }
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate break;
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate case F_SETLKW:
307da6c28aaSamw if (flag & F_REMOTELOCK) {
308da6c28aaSamw frcmd = SETFLCK|SLPFLCK|RCMDLCK;
309da6c28aaSamw } else if (flag & F_PXFSLOCK) {
310da6c28aaSamw frcmd = SETFLCK|SLPFLCK|PCMDLCK;
311da6c28aaSamw } else {
312da6c28aaSamw frcmd = SETFLCK|SLPFLCK;
313da6c28aaSamw bfp->l_pid = ttoproc(curthread)->p_pid;
314da6c28aaSamw bfp->l_sysid = 0;
315da6c28aaSamw }
316b89a8333Snatalie li - Sun Microsystems - Irvine United States
3177c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) {
3187c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_WRITER);
3197c478bd9Sstevel@tonic-gate serialize = 1;
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate break;
3227c478bd9Sstevel@tonic-gate
3237a5aac98SJerry Jelinek case F_OFD_SETLK:
3247a5aac98SJerry Jelinek case F_OFD_SETLKW:
3257a5aac98SJerry Jelinek case F_FLOCK:
3267a5aac98SJerry Jelinek case F_FLOCKW:
3277a5aac98SJerry Jelinek /*
3287a5aac98SJerry Jelinek * TBD we do not support remote OFD locks at this time.
3297a5aac98SJerry Jelinek */
3307a5aac98SJerry Jelinek if (flag & (F_REMOTELOCK | F_PXFSLOCK)) {
3317a5aac98SJerry Jelinek error = EINVAL;
3327a5aac98SJerry Jelinek goto done;
3337a5aac98SJerry Jelinek }
3347a5aac98SJerry Jelinek skip_lock = B_TRUE;
3357a5aac98SJerry Jelinek break;
3367a5aac98SJerry Jelinek
3377c478bd9Sstevel@tonic-gate case F_HASREMOTELOCKS:
3387c478bd9Sstevel@tonic-gate nlmid = GETNLMID(bfp->l_sysid);
3397c478bd9Sstevel@tonic-gate if (nlmid != 0) { /* booted as a cluster */
3407c478bd9Sstevel@tonic-gate l_has_rmt(bfp) =
3417c478bd9Sstevel@tonic-gate cl_flk_has_remote_locks_for_nlmid(vp, nlmid);
3427c478bd9Sstevel@tonic-gate } else { /* not booted as a cluster */
3437c478bd9Sstevel@tonic-gate l_has_rmt(bfp) = flk_has_remote_locks(vp);
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate goto done;
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate default:
3497c478bd9Sstevel@tonic-gate error = EINVAL;
3507c478bd9Sstevel@tonic-gate goto done;
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate /*
3547c478bd9Sstevel@tonic-gate * If this is a blocking lock request and we're serializing lock
3557c478bd9Sstevel@tonic-gate * requests, modify the callback list to leave the critical region
3567c478bd9Sstevel@tonic-gate * while we're waiting for the lock.
3577c478bd9Sstevel@tonic-gate */
3587c478bd9Sstevel@tonic-gate
3597c478bd9Sstevel@tonic-gate if (serialize && (frcmd & SLPFLCK) != 0) {
3607c478bd9Sstevel@tonic-gate flk_add_callback(&serialize_callback,
3617c478bd9Sstevel@tonic-gate frlock_serialize_blocked, vp, flk_cbp);
3627c478bd9Sstevel@tonic-gate flk_cbp = &serialize_callback;
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate
3657a5aac98SJerry Jelinek if (!skip_lock)
3667c478bd9Sstevel@tonic-gate error = reclock(vp, bfp, frcmd, flag, offset, flk_cbp);
3677c478bd9Sstevel@tonic-gate
368*74a91888SMarcel Telka if (serialize && (frcmd & SLPFLCK) != 0)
369*74a91888SMarcel Telka flk_del_callback(&serialize_callback);
370*74a91888SMarcel Telka
3717c478bd9Sstevel@tonic-gate done:
3727c478bd9Sstevel@tonic-gate if (serialize)
3737c478bd9Sstevel@tonic-gate nbl_end_crit(vp);
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate return (error);
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate /*
3797c478bd9Sstevel@tonic-gate * Callback when a lock request blocks and we are serializing requests. If
3807c478bd9Sstevel@tonic-gate * before sleeping, leave the critical region. If after wakeup, reenter
3817c478bd9Sstevel@tonic-gate * the critical region.
3827c478bd9Sstevel@tonic-gate */
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate static callb_cpr_t *
frlock_serialize_blocked(flk_cb_when_t when,void * infop)3857c478bd9Sstevel@tonic-gate frlock_serialize_blocked(flk_cb_when_t when, void *infop)
3867c478bd9Sstevel@tonic-gate {
3877c478bd9Sstevel@tonic-gate vnode_t *vp = (vnode_t *)infop;
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate if (when == FLK_BEFORE_SLEEP)
3907c478bd9Sstevel@tonic-gate nbl_end_crit(vp);
3917c478bd9Sstevel@tonic-gate else {
3927c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_WRITER);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate return (NULL);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gate /*
3997c478bd9Sstevel@tonic-gate * Allow any flags.
4007c478bd9Sstevel@tonic-gate */
4017c478bd9Sstevel@tonic-gate /* ARGSUSED */
4027c478bd9Sstevel@tonic-gate int
fs_setfl(vnode_t * vp,int oflags,int nflags,cred_t * cr,caller_context_t * ct)403*74a91888SMarcel Telka fs_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct)
4047c478bd9Sstevel@tonic-gate {
4057c478bd9Sstevel@tonic-gate return (0);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate
4087c478bd9Sstevel@tonic-gate /*
4097c478bd9Sstevel@tonic-gate * Return the answer requested to poll() for non-device files.
4107c478bd9Sstevel@tonic-gate * Only POLLIN, POLLRDNORM, and POLLOUT are recognized.
4117c478bd9Sstevel@tonic-gate */
4127c478bd9Sstevel@tonic-gate struct pollhead fs_pollhd;
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate /* ARGSUSED */
4157c478bd9Sstevel@tonic-gate int
fs_poll(vnode_t * vp,short events,int anyyet,short * reventsp,struct pollhead ** phpp,caller_context_t * ct)416*74a91888SMarcel Telka fs_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
417*74a91888SMarcel Telka struct pollhead **phpp, caller_context_t *ct)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate *reventsp = 0;
4207c478bd9Sstevel@tonic-gate if (events & POLLIN)
4217c478bd9Sstevel@tonic-gate *reventsp |= POLLIN;
4227c478bd9Sstevel@tonic-gate if (events & POLLRDNORM)
4237c478bd9Sstevel@tonic-gate *reventsp |= POLLRDNORM;
4247c478bd9Sstevel@tonic-gate if (events & POLLRDBAND)
4257c478bd9Sstevel@tonic-gate *reventsp |= POLLRDBAND;
4267c478bd9Sstevel@tonic-gate if (events & POLLOUT)
4277c478bd9Sstevel@tonic-gate *reventsp |= POLLOUT;
4287c478bd9Sstevel@tonic-gate if (events & POLLWRBAND)
4297c478bd9Sstevel@tonic-gate *reventsp |= POLLWRBAND;
4307c478bd9Sstevel@tonic-gate *phpp = !anyyet && !*reventsp ? &fs_pollhd : (struct pollhead *)NULL;
4317c478bd9Sstevel@tonic-gate return (0);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate /*
4357c478bd9Sstevel@tonic-gate * POSIX pathconf() support.
4367c478bd9Sstevel@tonic-gate */
4377c478bd9Sstevel@tonic-gate /* ARGSUSED */
4387c478bd9Sstevel@tonic-gate int
fs_pathconf(vnode_t * vp,int cmd,ulong_t * valp,cred_t * cr,caller_context_t * ct)439*74a91888SMarcel Telka fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
440da6c28aaSamw caller_context_t *ct)
4417c478bd9Sstevel@tonic-gate {
442*74a91888SMarcel Telka ulong_t val;
443*74a91888SMarcel Telka int error = 0;
4447c478bd9Sstevel@tonic-gate struct statvfs64 vfsbuf;
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate switch (cmd) {
4477c478bd9Sstevel@tonic-gate
4487c478bd9Sstevel@tonic-gate case _PC_LINK_MAX:
4497c478bd9Sstevel@tonic-gate val = MAXLINK;
4507c478bd9Sstevel@tonic-gate break;
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate case _PC_MAX_CANON:
4537c478bd9Sstevel@tonic-gate val = MAX_CANON;
4547c478bd9Sstevel@tonic-gate break;
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate case _PC_MAX_INPUT:
4577c478bd9Sstevel@tonic-gate val = MAX_INPUT;
4587c478bd9Sstevel@tonic-gate break;
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate case _PC_NAME_MAX:
4617c478bd9Sstevel@tonic-gate bzero(&vfsbuf, sizeof (vfsbuf));
4627c478bd9Sstevel@tonic-gate if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf))
4637c478bd9Sstevel@tonic-gate break;
4647c478bd9Sstevel@tonic-gate val = vfsbuf.f_namemax;
4657c478bd9Sstevel@tonic-gate break;
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate case _PC_PATH_MAX:
4687c478bd9Sstevel@tonic-gate case _PC_SYMLINK_MAX:
4697c478bd9Sstevel@tonic-gate val = MAXPATHLEN;
4707c478bd9Sstevel@tonic-gate break;
4717c478bd9Sstevel@tonic-gate
4727c478bd9Sstevel@tonic-gate case _PC_PIPE_BUF:
4737c478bd9Sstevel@tonic-gate val = PIPE_BUF;
4747c478bd9Sstevel@tonic-gate break;
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate case _PC_NO_TRUNC:
4777c478bd9Sstevel@tonic-gate if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC)
4787c478bd9Sstevel@tonic-gate val = 1; /* NOTRUNC is enabled for vp */
4797c478bd9Sstevel@tonic-gate else
4807c478bd9Sstevel@tonic-gate val = (ulong_t)-1;
4817c478bd9Sstevel@tonic-gate break;
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate case _PC_VDISABLE:
4847c478bd9Sstevel@tonic-gate val = _POSIX_VDISABLE;
4857c478bd9Sstevel@tonic-gate break;
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate case _PC_CHOWN_RESTRICTED:
4887c478bd9Sstevel@tonic-gate if (rstchown)
4897c478bd9Sstevel@tonic-gate val = rstchown; /* chown restricted enabled */
4907c478bd9Sstevel@tonic-gate else
4917c478bd9Sstevel@tonic-gate val = (ulong_t)-1;
4927c478bd9Sstevel@tonic-gate break;
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate case _PC_FILESIZEBITS:
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate /*
4977c478bd9Sstevel@tonic-gate * If ever we come here it means that underlying file system
4987c478bd9Sstevel@tonic-gate * does not recognise the command and therefore this
4997c478bd9Sstevel@tonic-gate * configurable limit cannot be determined. We return -1
5007c478bd9Sstevel@tonic-gate * and don't change errno.
5017c478bd9Sstevel@tonic-gate */
5027c478bd9Sstevel@tonic-gate
5037c478bd9Sstevel@tonic-gate val = (ulong_t)-1; /* large file support */
5047c478bd9Sstevel@tonic-gate break;
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate case _PC_ACL_ENABLED:
5077c478bd9Sstevel@tonic-gate val = 0;
5087c478bd9Sstevel@tonic-gate break;
5097c478bd9Sstevel@tonic-gate
510da6c28aaSamw case _PC_CASE_BEHAVIOR:
511da6c28aaSamw val = _CASE_SENSITIVE;
512da6c28aaSamw if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1)
513da6c28aaSamw val |= _CASE_INSENSITIVE;
514da6c28aaSamw if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1)
515da6c28aaSamw val &= ~_CASE_SENSITIVE;
516da6c28aaSamw break;
517da6c28aaSamw
518da6c28aaSamw case _PC_SATTR_ENABLED:
519da6c28aaSamw case _PC_SATTR_EXISTS:
520da6c28aaSamw val = 0;
521da6c28aaSamw break;
522da6c28aaSamw
523e802abbdSTim Haley case _PC_ACCESS_FILTERING:
524e802abbdSTim Haley val = 0;
525e802abbdSTim Haley break;
526e802abbdSTim Haley
5277c478bd9Sstevel@tonic-gate default:
5287c478bd9Sstevel@tonic-gate error = EINVAL;
5297c478bd9Sstevel@tonic-gate break;
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate if (error == 0)
5337c478bd9Sstevel@tonic-gate *valp = val;
5347c478bd9Sstevel@tonic-gate return (error);
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate /*
5387c478bd9Sstevel@tonic-gate * Dispose of a page.
5397c478bd9Sstevel@tonic-gate */
5407c478bd9Sstevel@tonic-gate /* ARGSUSED */
5417c478bd9Sstevel@tonic-gate void
fs_dispose(struct vnode * vp,page_t * pp,int fl,int dn,struct cred * cr,caller_context_t * ct)542*74a91888SMarcel Telka fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
543da6c28aaSamw caller_context_t *ct)
5447c478bd9Sstevel@tonic-gate {
5457c478bd9Sstevel@tonic-gate
5467c478bd9Sstevel@tonic-gate ASSERT(fl == B_FREE || fl == B_INVAL);
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate if (fl == B_FREE)
5497c478bd9Sstevel@tonic-gate page_free(pp, dn);
5507c478bd9Sstevel@tonic-gate else
5517c478bd9Sstevel@tonic-gate page_destroy(pp, dn);
5527c478bd9Sstevel@tonic-gate }
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate /* ARGSUSED */
5557c478bd9Sstevel@tonic-gate void
fs_nodispose(struct vnode * vp,page_t * pp,int fl,int dn,struct cred * cr,caller_context_t * ct)556*74a91888SMarcel Telka fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
557da6c28aaSamw caller_context_t *ct)
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "fs_nodispose invoked");
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate /*
5637c478bd9Sstevel@tonic-gate * fabricate acls for file systems that do not support acls.
5647c478bd9Sstevel@tonic-gate */
5657c478bd9Sstevel@tonic-gate /* ARGSUSED */
5667c478bd9Sstevel@tonic-gate int
fs_fab_acl(vnode_t * vp,vsecattr_t * vsecattr,int flag,cred_t * cr,caller_context_t * ct)567*74a91888SMarcel Telka fs_fab_acl(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
568da6c28aaSamw caller_context_t *ct)
5697c478bd9Sstevel@tonic-gate {
5707c478bd9Sstevel@tonic-gate aclent_t *aclentp;
5717c478bd9Sstevel@tonic-gate struct vattr vattr;
5727c478bd9Sstevel@tonic-gate int error;
573da6c28aaSamw size_t aclsize;
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate vsecattr->vsa_aclcnt = 0;
576da6c28aaSamw vsecattr->vsa_aclentsz = 0;
5777c478bd9Sstevel@tonic-gate vsecattr->vsa_aclentp = NULL;
5787c478bd9Sstevel@tonic-gate vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */
5797c478bd9Sstevel@tonic-gate vsecattr->vsa_dfaclentp = NULL;
5807c478bd9Sstevel@tonic-gate
5817b3700d1Sszhou vattr.va_mask = AT_MODE | AT_UID | AT_GID;
582da6c28aaSamw if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct))
5837b3700d1Sszhou return (error);
5847c478bd9Sstevel@tonic-gate
585cf53598eSmarks if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
586da6c28aaSamw aclsize = 4 * sizeof (aclent_t);
5877b3700d1Sszhou vsecattr->vsa_aclcnt = 4; /* USER, GROUP, OTHER, and CLASS */
588da6c28aaSamw vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP);
5897c478bd9Sstevel@tonic-gate aclentp = vsecattr->vsa_aclentp;
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate aclentp->a_type = USER_OBJ; /* Owner */
5927c478bd9Sstevel@tonic-gate aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0700)) >> 6;
5937c478bd9Sstevel@tonic-gate aclentp->a_id = vattr.va_uid; /* Really undefined */
5947c478bd9Sstevel@tonic-gate aclentp++;
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate aclentp->a_type = GROUP_OBJ; /* Group */
5977c478bd9Sstevel@tonic-gate aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0070)) >> 3;
5987c478bd9Sstevel@tonic-gate aclentp->a_id = vattr.va_gid; /* Really undefined */
5997c478bd9Sstevel@tonic-gate aclentp++;
6007c478bd9Sstevel@tonic-gate
6017c478bd9Sstevel@tonic-gate aclentp->a_type = OTHER_OBJ; /* Other */
6027c478bd9Sstevel@tonic-gate aclentp->a_perm = vattr.va_mode & 0007;
603f48205beScasper aclentp->a_id = (gid_t)-1; /* Really undefined */
6047c478bd9Sstevel@tonic-gate aclentp++;
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate aclentp->a_type = CLASS_OBJ; /* Class */
6077b3700d1Sszhou aclentp->a_perm = (ushort_t)(0007);
608f48205beScasper aclentp->a_id = (gid_t)-1; /* Really undefined */
609cf53598eSmarks } else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
61027dd1e87SMark Shellenbaum VERIFY(0 == acl_trivial_create(vattr.va_mode,
611a3c49ce1SAlbert Lee (vp->v_type == VDIR), (ace_t **)&vsecattr->vsa_aclentp,
612a3c49ce1SAlbert Lee &vsecattr->vsa_aclcnt));
61327dd1e87SMark Shellenbaum vsecattr->vsa_aclentsz = vsecattr->vsa_aclcnt * sizeof (ace_t);
614cf53598eSmarks }
6157c478bd9Sstevel@tonic-gate
61627dd1e87SMark Shellenbaum return (error);
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate /*
6207c478bd9Sstevel@tonic-gate * Common code for implementing DOS share reservations
6217c478bd9Sstevel@tonic-gate */
6227c478bd9Sstevel@tonic-gate /* ARGSUSED4 */
6237c478bd9Sstevel@tonic-gate int
fs_shrlock(struct vnode * vp,int cmd,struct shrlock * shr,int flag,cred_t * cr,caller_context_t * ct)624*74a91888SMarcel Telka fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
625da6c28aaSamw caller_context_t *ct)
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate int error;
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate /*
6307c478bd9Sstevel@tonic-gate * Make sure that the file was opened with permissions appropriate
6317c478bd9Sstevel@tonic-gate * for the request, and make sure the caller isn't trying to sneak
6327c478bd9Sstevel@tonic-gate * in an NBMAND request.
6337c478bd9Sstevel@tonic-gate */
6347c478bd9Sstevel@tonic-gate if (cmd == F_SHARE) {
6357c478bd9Sstevel@tonic-gate if (((shr->s_access & F_RDACC) && (flag & FREAD) == 0) ||
6367c478bd9Sstevel@tonic-gate ((shr->s_access & F_WRACC) && (flag & FWRITE) == 0))
6377c478bd9Sstevel@tonic-gate return (EBADF);
638da6c28aaSamw if (shr->s_access & (F_RMACC | F_MDACC))
639da6c28aaSamw return (EINVAL);
640da6c28aaSamw if (shr->s_deny & (F_MANDDNY | F_RMDNY))
6417c478bd9Sstevel@tonic-gate return (EINVAL);
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate if (cmd == F_SHARE_NBMAND) {
6447c478bd9Sstevel@tonic-gate /* make sure nbmand is allowed on the file */
6457c478bd9Sstevel@tonic-gate if (!vp->v_vfsp ||
6467c478bd9Sstevel@tonic-gate !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) {
6477c478bd9Sstevel@tonic-gate return (EINVAL);
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) {
6507c478bd9Sstevel@tonic-gate return (EINVAL);
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_WRITER);
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate switch (cmd) {
6577c478bd9Sstevel@tonic-gate
6587c478bd9Sstevel@tonic-gate case F_SHARE_NBMAND:
6597c478bd9Sstevel@tonic-gate shr->s_deny |= F_MANDDNY;
6607c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
6617c478bd9Sstevel@tonic-gate case F_SHARE:
6627c478bd9Sstevel@tonic-gate error = add_share(vp, shr);
6637c478bd9Sstevel@tonic-gate break;
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate case F_UNSHARE:
6667c478bd9Sstevel@tonic-gate error = del_share(vp, shr);
6677c478bd9Sstevel@tonic-gate break;
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate case F_HASREMOTELOCKS:
6707c478bd9Sstevel@tonic-gate /*
6717c478bd9Sstevel@tonic-gate * We are overloading this command to refer to remote
6727c478bd9Sstevel@tonic-gate * shares as well as remote locks, despite its name.
6737c478bd9Sstevel@tonic-gate */
6747c478bd9Sstevel@tonic-gate shr->s_access = shr_has_remote_shares(vp, shr->s_sysid);
6757c478bd9Sstevel@tonic-gate error = 0;
6767c478bd9Sstevel@tonic-gate break;
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate default:
6797c478bd9Sstevel@tonic-gate error = EINVAL;
6807c478bd9Sstevel@tonic-gate break;
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate nbl_end_crit(vp);
6847c478bd9Sstevel@tonic-gate return (error);
6857c478bd9Sstevel@tonic-gate }
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
6887c478bd9Sstevel@tonic-gate int
fs_vnevent_nosupport(vnode_t * vp,vnevent_t e,vnode_t * dvp,char * fnm,caller_context_t * ct)689da6c28aaSamw fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
690da6c28aaSamw caller_context_t *ct)
6917c478bd9Sstevel@tonic-gate {
6927c478bd9Sstevel@tonic-gate ASSERT(vp != NULL);
6937c478bd9Sstevel@tonic-gate return (ENOTSUP);
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
6977c478bd9Sstevel@tonic-gate int
fs_vnevent_support(vnode_t * vp,vnevent_t e,vnode_t * dvp,char * fnm,caller_context_t * ct)698da6c28aaSamw fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
699da6c28aaSamw caller_context_t *ct)
7007c478bd9Sstevel@tonic-gate {
7017c478bd9Sstevel@tonic-gate ASSERT(vp != NULL);
7027c478bd9Sstevel@tonic-gate return (0);
7037c478bd9Sstevel@tonic-gate }
704fa9e4066Sahrens
705fa9e4066Sahrens /*
706fa9e4066Sahrens * return 1 for non-trivial ACL.
707fa9e4066Sahrens *
708fa9e4066Sahrens * NB: It is not necessary for the caller to VOP_RWLOCK since
709fa9e4066Sahrens * we only issue VOP_GETSECATTR.
710fa9e4066Sahrens *
711fa9e4066Sahrens * Returns 0 == trivial
712fa9e4066Sahrens * 1 == NOT Trivial
713fa9e4066Sahrens * <0 could not determine.
714fa9e4066Sahrens */
715fa9e4066Sahrens int
fs_acl_nontrivial(vnode_t * vp,cred_t * cr)716fa9e4066Sahrens fs_acl_nontrivial(vnode_t *vp, cred_t *cr)
717fa9e4066Sahrens {
718fa9e4066Sahrens ulong_t acl_styles;
719fa9e4066Sahrens ulong_t acl_flavor;
720fa9e4066Sahrens vsecattr_t vsecattr;
721fa9e4066Sahrens int error;
722fa9e4066Sahrens int isnontrivial;
723fa9e4066Sahrens
724fa9e4066Sahrens /* determine the forms of ACLs maintained */
725da6c28aaSamw error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &acl_styles, cr, NULL);
726fa9e4066Sahrens
727fa9e4066Sahrens /* clear bits we don't understand and establish default acl_style */
728fa9e4066Sahrens acl_styles &= (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED);
729fa9e4066Sahrens if (error || (acl_styles == 0))
730fa9e4066Sahrens acl_styles = _ACL_ACLENT_ENABLED;
731fa9e4066Sahrens
732fa9e4066Sahrens vsecattr.vsa_aclentp = NULL;
733fa9e4066Sahrens vsecattr.vsa_dfaclentp = NULL;
734fa9e4066Sahrens vsecattr.vsa_aclcnt = 0;
735fa9e4066Sahrens vsecattr.vsa_dfaclcnt = 0;
736fa9e4066Sahrens
737fa9e4066Sahrens while (acl_styles) {
738fa9e4066Sahrens /* select one of the styles as current flavor */
739fa9e4066Sahrens acl_flavor = 0;
740fa9e4066Sahrens if (acl_styles & _ACL_ACLENT_ENABLED) {
741fa9e4066Sahrens acl_flavor = _ACL_ACLENT_ENABLED;
742fa9e4066Sahrens vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT;
743fa9e4066Sahrens } else if (acl_styles & _ACL_ACE_ENABLED) {
744fa9e4066Sahrens acl_flavor = _ACL_ACE_ENABLED;
745fa9e4066Sahrens vsecattr.vsa_mask = VSA_ACECNT | VSA_ACE;
746fa9e4066Sahrens }
747fa9e4066Sahrens
748fa9e4066Sahrens ASSERT(vsecattr.vsa_mask && acl_flavor);
749da6c28aaSamw error = VOP_GETSECATTR(vp, &vsecattr, 0, cr, NULL);
750fa9e4066Sahrens if (error == 0)
751fa9e4066Sahrens break;
752fa9e4066Sahrens
753fa9e4066Sahrens /* that flavor failed */
754fa9e4066Sahrens acl_styles &= ~acl_flavor;
755fa9e4066Sahrens }
756fa9e4066Sahrens
757fa9e4066Sahrens /* if all styles fail then assume trivial */
758fa9e4066Sahrens if (acl_styles == 0)
759fa9e4066Sahrens return (0);
760fa9e4066Sahrens
761fa9e4066Sahrens /* process the flavor that worked */
762fa9e4066Sahrens isnontrivial = 0;
763fa9e4066Sahrens if (acl_flavor & _ACL_ACLENT_ENABLED) {
764fa9e4066Sahrens if (vsecattr.vsa_aclcnt > MIN_ACL_ENTRIES)
765fa9e4066Sahrens isnontrivial = 1;
766fa9e4066Sahrens if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL)
767fa9e4066Sahrens kmem_free(vsecattr.vsa_aclentp,
768fa9e4066Sahrens vsecattr.vsa_aclcnt * sizeof (aclent_t));
769fa9e4066Sahrens if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp != NULL)
770fa9e4066Sahrens kmem_free(vsecattr.vsa_dfaclentp,
771fa9e4066Sahrens vsecattr.vsa_dfaclcnt * sizeof (aclent_t));
772fa9e4066Sahrens }
773fa9e4066Sahrens if (acl_flavor & _ACL_ACE_ENABLED) {
774fa9e4066Sahrens isnontrivial = ace_trivial(vsecattr.vsa_aclentp,
775fa9e4066Sahrens vsecattr.vsa_aclcnt);
776fa9e4066Sahrens
777fa9e4066Sahrens if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL)
778fa9e4066Sahrens kmem_free(vsecattr.vsa_aclentp,
779fa9e4066Sahrens vsecattr.vsa_aclcnt * sizeof (ace_t));
780fa9e4066Sahrens /* ACE has no vsecattr.vsa_dfaclcnt */
781fa9e4066Sahrens }
782fa9e4066Sahrens return (isnontrivial);
783fa9e4066Sahrens }
784dd29fa4aSprabahar
785dd29fa4aSprabahar /*
786dd29fa4aSprabahar * Check whether we need a retry to recover from STALE error.
787dd29fa4aSprabahar */
788dd29fa4aSprabahar int
fs_need_estale_retry(int retry_count)789dd29fa4aSprabahar fs_need_estale_retry(int retry_count)
790dd29fa4aSprabahar {
791dd29fa4aSprabahar if (retry_count < fs_estale_retry)
792dd29fa4aSprabahar return (1);
793dd29fa4aSprabahar else
794dd29fa4aSprabahar return (0);
795dd29fa4aSprabahar }
796da6c28aaSamw
797da6c28aaSamw
798da6c28aaSamw static int (*fs_av_scan)(vnode_t *, cred_t *, int) = NULL;
799da6c28aaSamw
800da6c28aaSamw /*
801da6c28aaSamw * Routine for anti-virus scanner to call to register its scanning routine.
802da6c28aaSamw */
803da6c28aaSamw void
fs_vscan_register(int (* av_scan)(vnode_t *,cred_t *,int))804da6c28aaSamw fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int))
805da6c28aaSamw {
806da6c28aaSamw fs_av_scan = av_scan;
807da6c28aaSamw }
808da6c28aaSamw
809da6c28aaSamw /*
810da6c28aaSamw * Routine for file systems to call to initiate anti-virus scanning.
811da6c28aaSamw * Scanning will only be done on REGular files (currently).
812da6c28aaSamw */
813da6c28aaSamw int
fs_vscan(vnode_t * vp,cred_t * cr,int async)814da6c28aaSamw fs_vscan(vnode_t *vp, cred_t *cr, int async)
815da6c28aaSamw {
816da6c28aaSamw int ret = 0;
817da6c28aaSamw
818da6c28aaSamw if (fs_av_scan && vp->v_type == VREG)
819da6c28aaSamw ret = (*fs_av_scan)(vp, cr, async);
820da6c28aaSamw
821da6c28aaSamw return (ret);
822da6c28aaSamw }
8237a286c47SDai Ngo
8247a286c47SDai Ngo /*
8257a286c47SDai Ngo * support functions for reparse point
8267a286c47SDai Ngo */
8277a286c47SDai Ngo /*
8287a286c47SDai Ngo * reparse_vnode_parse
8297a286c47SDai Ngo *
8307a286c47SDai Ngo * Read the symlink data of a reparse point specified by the vnode
8317a286c47SDai Ngo * and return the reparse data as name-value pair in the nvlist.
8327a286c47SDai Ngo */
8337a286c47SDai Ngo int
reparse_vnode_parse(vnode_t * vp,nvlist_t * nvl)8347a286c47SDai Ngo reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl)
8357a286c47SDai Ngo {
8367a286c47SDai Ngo int err;
8377a286c47SDai Ngo char *lkdata;
8387a286c47SDai Ngo struct uio uio;
8397a286c47SDai Ngo struct iovec iov;
8407a286c47SDai Ngo
8417a286c47SDai Ngo if (vp == NULL || nvl == NULL)
8427a286c47SDai Ngo return (EINVAL);
8437a286c47SDai Ngo
8447a286c47SDai Ngo lkdata = kmem_alloc(MAXREPARSELEN, KM_SLEEP);
8457a286c47SDai Ngo
8467a286c47SDai Ngo /*
8477a286c47SDai Ngo * Set up io vector to read sym link data
8487a286c47SDai Ngo */
8497a286c47SDai Ngo iov.iov_base = lkdata;
8507a286c47SDai Ngo iov.iov_len = MAXREPARSELEN;
8517a286c47SDai Ngo uio.uio_iov = &iov;
8527a286c47SDai Ngo uio.uio_iovcnt = 1;
8537a286c47SDai Ngo uio.uio_segflg = UIO_SYSSPACE;
8547a286c47SDai Ngo uio.uio_extflg = UIO_COPY_CACHED;
8557a286c47SDai Ngo uio.uio_loffset = (offset_t)0;
8567a286c47SDai Ngo uio.uio_resid = MAXREPARSELEN;
8577a286c47SDai Ngo
8587a286c47SDai Ngo if ((err = VOP_READLINK(vp, &uio, kcred, NULL)) == 0) {
8597a286c47SDai Ngo *(lkdata + MAXREPARSELEN - uio.uio_resid) = '\0';
8607a286c47SDai Ngo err = reparse_parse(lkdata, nvl);
8617a286c47SDai Ngo }
8627a286c47SDai Ngo kmem_free(lkdata, MAXREPARSELEN); /* done with lkdata */
8637a286c47SDai Ngo
8647a286c47SDai Ngo return (err);
8657a286c47SDai Ngo }
8667a286c47SDai Ngo
8677a286c47SDai Ngo void
reparse_point_init()8687a286c47SDai Ngo reparse_point_init()
8697a286c47SDai Ngo {
8707a286c47SDai Ngo mutex_init(&reparsed_door_lock, NULL, MUTEX_DEFAULT, NULL);
8717a286c47SDai Ngo }
8727a286c47SDai Ngo
8737a286c47SDai Ngo static door_handle_t
reparse_door_get_handle()8747a286c47SDai Ngo reparse_door_get_handle()
8757a286c47SDai Ngo {
8767a286c47SDai Ngo door_handle_t dh;
8777a286c47SDai Ngo
8787a286c47SDai Ngo mutex_enter(&reparsed_door_lock);
8797a286c47SDai Ngo if ((dh = reparsed_door) == NULL) {
8807a286c47SDai Ngo if (door_ki_open(REPARSED_DOOR, &reparsed_door) != 0) {
8817a286c47SDai Ngo reparsed_door = NULL;
8827a286c47SDai Ngo dh = NULL;
8837a286c47SDai Ngo } else
8847a286c47SDai Ngo dh = reparsed_door;
8857a286c47SDai Ngo }
8867a286c47SDai Ngo mutex_exit(&reparsed_door_lock);
8877a286c47SDai Ngo return (dh);
8887a286c47SDai Ngo }
8897a286c47SDai Ngo
8907a286c47SDai Ngo static void
reparse_door_reset_handle()8917a286c47SDai Ngo reparse_door_reset_handle()
8927a286c47SDai Ngo {
8937a286c47SDai Ngo mutex_enter(&reparsed_door_lock);
8947a286c47SDai Ngo reparsed_door = NULL;
8957a286c47SDai Ngo mutex_exit(&reparsed_door_lock);
8967a286c47SDai Ngo }
8977a286c47SDai Ngo
8987a286c47SDai Ngo /*
8997a286c47SDai Ngo * reparse_kderef
9007a286c47SDai Ngo *
9017a286c47SDai Ngo * Accepts the service-specific item from the reparse point and returns
9027a286c47SDai Ngo * the service-specific data requested. The caller specifies the size of
9037a286c47SDai Ngo * the buffer provided via *bufsz; the routine will fail with EOVERFLOW
9047a286c47SDai Ngo * if the results will not fit in the buffer, in which case, *bufsz will
9057a286c47SDai Ngo * contain the number of bytes needed to hold the results.
9067a286c47SDai Ngo *
9077a286c47SDai Ngo * if ok return 0 and update *bufsize with length of actual result
9087a286c47SDai Ngo * else return error code.
9097a286c47SDai Ngo */
9107a286c47SDai Ngo int
reparse_kderef(const char * svc_type,const char * svc_data,char * buf,size_t * bufsize)9117a286c47SDai Ngo reparse_kderef(const char *svc_type, const char *svc_data, char *buf,
9127a286c47SDai Ngo size_t *bufsize)
9137a286c47SDai Ngo {
9142f172c55SRobert Thurlow int err, retries, need_free, retried_doorhd;
9157a286c47SDai Ngo size_t dlen, res_len;
9167a286c47SDai Ngo char *darg;
9177a286c47SDai Ngo door_arg_t door_args;
9187a286c47SDai Ngo reparsed_door_res_t *resp;
9197a286c47SDai Ngo door_handle_t rp_door;
9207a286c47SDai Ngo
9217a286c47SDai Ngo if (svc_type == NULL || svc_data == NULL || buf == NULL ||
9227a286c47SDai Ngo bufsize == NULL)
9237a286c47SDai Ngo return (EINVAL);
9247a286c47SDai Ngo
9257a286c47SDai Ngo /* get reparsed's door handle */
9267a286c47SDai Ngo if ((rp_door = reparse_door_get_handle()) == NULL)
9277a286c47SDai Ngo return (EBADF);
9287a286c47SDai Ngo
9297a286c47SDai Ngo /* setup buffer for door_call args and results */
9307a286c47SDai Ngo dlen = strlen(svc_type) + strlen(svc_data) + 2;
9317a286c47SDai Ngo if (*bufsize < dlen) {
9327a286c47SDai Ngo darg = kmem_alloc(dlen, KM_SLEEP);
9337a286c47SDai Ngo need_free = 1;
9347a286c47SDai Ngo } else {
9357a286c47SDai Ngo darg = buf; /* use same buffer for door's args & results */
9367a286c47SDai Ngo need_free = 0;
9377a286c47SDai Ngo }
9387a286c47SDai Ngo
9397a286c47SDai Ngo /* build argument string of door call */
9407a286c47SDai Ngo (void) snprintf(darg, dlen, "%s:%s", svc_type, svc_data);
9417a286c47SDai Ngo
9427a286c47SDai Ngo /* setup args for door call */
9437a286c47SDai Ngo door_args.data_ptr = darg;
9447a286c47SDai Ngo door_args.data_size = dlen;
9457a286c47SDai Ngo door_args.desc_ptr = NULL;
9467a286c47SDai Ngo door_args.desc_num = 0;
9477a286c47SDai Ngo door_args.rbuf = buf;
9487a286c47SDai Ngo door_args.rsize = *bufsize;
9497a286c47SDai Ngo
9507a286c47SDai Ngo /* do the door_call */
9512f172c55SRobert Thurlow retried_doorhd = 0;
9527a286c47SDai Ngo retries = 0;
9537a286c47SDai Ngo door_ki_hold(rp_door);
9547a286c47SDai Ngo while ((err = door_ki_upcall_limited(rp_door, &door_args,
9557a286c47SDai Ngo NULL, SIZE_MAX, 0)) != 0) {
9567a286c47SDai Ngo if (err == EAGAIN || err == EINTR) {
9577a286c47SDai Ngo if (++retries < REPARSED_DOORCALL_MAX_RETRY) {
9587a286c47SDai Ngo delay(SEC_TO_TICK(1));
9597a286c47SDai Ngo continue;
9607a286c47SDai Ngo }
9617a286c47SDai Ngo } else if (err == EBADF) {
9627a286c47SDai Ngo /* door server goes away... */
9637a286c47SDai Ngo reparse_door_reset_handle();
9642f172c55SRobert Thurlow
9652f172c55SRobert Thurlow if (retried_doorhd == 0) {
9662f172c55SRobert Thurlow door_ki_rele(rp_door);
9672f172c55SRobert Thurlow retried_doorhd++;
9682f172c55SRobert Thurlow rp_door = reparse_door_get_handle();
9692f172c55SRobert Thurlow if (rp_door != NULL) {
9702f172c55SRobert Thurlow door_ki_hold(rp_door);
9712f172c55SRobert Thurlow continue;
9722f172c55SRobert Thurlow }
9732f172c55SRobert Thurlow }
9747a286c47SDai Ngo }
9757a286c47SDai Ngo break;
9767a286c47SDai Ngo }
9772f172c55SRobert Thurlow
9782f172c55SRobert Thurlow if (rp_door)
9797a286c47SDai Ngo door_ki_rele(rp_door);
9802f172c55SRobert Thurlow
9817a286c47SDai Ngo if (need_free)
9827a286c47SDai Ngo kmem_free(darg, dlen); /* done with args buffer */
9837a286c47SDai Ngo
9847a286c47SDai Ngo if (err != 0)
9857a286c47SDai Ngo return (err);
9867a286c47SDai Ngo
9877a286c47SDai Ngo resp = (reparsed_door_res_t *)door_args.rbuf;
9887a286c47SDai Ngo if ((err = resp->res_status) == 0) {
9897a286c47SDai Ngo /*
9907a286c47SDai Ngo * have to save the length of the results before the
9917a286c47SDai Ngo * bcopy below since it's can be an overlap copy that
9927a286c47SDai Ngo * overwrites the reparsed_door_res_t structure at
9937a286c47SDai Ngo * the beginning of the buffer.
9947a286c47SDai Ngo */
9957a286c47SDai Ngo res_len = (size_t)resp->res_len;
9967a286c47SDai Ngo
9977a286c47SDai Ngo /* deref call is ok */
9987a286c47SDai Ngo if (res_len > *bufsize)
9997a286c47SDai Ngo err = EOVERFLOW;
10007a286c47SDai Ngo else
10017a286c47SDai Ngo bcopy(resp->res_data, buf, res_len);
10027a286c47SDai Ngo *bufsize = res_len;
10037a286c47SDai Ngo }
10047a286c47SDai Ngo if (door_args.rbuf != buf)
10057a286c47SDai Ngo kmem_free(door_args.rbuf, door_args.rsize);
10067a286c47SDai Ngo
10077a286c47SDai Ngo return (err);
10087a286c47SDai Ngo }
1009