xref: /titanic_53/usr/src/uts/common/fs/vnode.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
32*7c478bd9Sstevel@tonic-gate  * The Regents of the University of California
33*7c478bd9Sstevel@tonic-gate  * All Rights Reserved
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
36*7c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
37*7c478bd9Sstevel@tonic-gate  * contributors.
38*7c478bd9Sstevel@tonic-gate  */
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/user.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/uio.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/rwstlock.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/fem.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/mode.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
64*7c478bd9Sstevel@tonic-gate #include <c2/audit.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/acl.h>
66*7c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h>
67*7c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
68*7c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate /* Determine if this vnode is a file that is read-only */
71*7c478bd9Sstevel@tonic-gate #define	ISROFILE(vp)	\
72*7c478bd9Sstevel@tonic-gate 	((vp)->v_type != VCHR && (vp)->v_type != VBLK && \
73*7c478bd9Sstevel@tonic-gate 	    (vp)->v_type != VFIFO && vn_is_readonly(vp))
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate /*
76*7c478bd9Sstevel@tonic-gate  * Convert stat(2) formats to vnode types and vice versa.  (Knows about
77*7c478bd9Sstevel@tonic-gate  * numerical order of S_IFMT and vnode types.)
78*7c478bd9Sstevel@tonic-gate  */
79*7c478bd9Sstevel@tonic-gate enum vtype iftovt_tab[] = {
80*7c478bd9Sstevel@tonic-gate 	VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
81*7c478bd9Sstevel@tonic-gate 	VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON
82*7c478bd9Sstevel@tonic-gate };
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate ushort_t vttoif_tab[] = {
85*7c478bd9Sstevel@tonic-gate 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO,
86*7c478bd9Sstevel@tonic-gate 	S_IFDOOR, 0, S_IFSOCK, S_IFPORT, 0
87*7c478bd9Sstevel@tonic-gate };
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate /*
90*7c478bd9Sstevel@tonic-gate  * The system vnode cache.
91*7c478bd9Sstevel@tonic-gate  */
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate kmem_cache_t *vn_cache;
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate /*
97*7c478bd9Sstevel@tonic-gate  * Vnode operations vector.
98*7c478bd9Sstevel@tonic-gate  */
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate static const fs_operation_trans_def_t vn_ops_table[] = {
101*7c478bd9Sstevel@tonic-gate 	VOPNAME_OPEN, offsetof(struct vnodeops, vop_open),
102*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	VOPNAME_CLOSE, offsetof(struct vnodeops, vop_close),
105*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	VOPNAME_READ, offsetof(struct vnodeops, vop_read),
108*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	VOPNAME_WRITE, offsetof(struct vnodeops, vop_write),
111*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	VOPNAME_IOCTL, offsetof(struct vnodeops, vop_ioctl),
114*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	VOPNAME_SETFL, offsetof(struct vnodeops, vop_setfl),
117*7c478bd9Sstevel@tonic-gate 	    fs_setfl, fs_nosys,
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate 	VOPNAME_GETATTR, offsetof(struct vnodeops, vop_getattr),
120*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 	VOPNAME_SETATTR, offsetof(struct vnodeops, vop_setattr),
123*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	VOPNAME_ACCESS, offsetof(struct vnodeops, vop_access),
126*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	VOPNAME_LOOKUP, offsetof(struct vnodeops, vop_lookup),
129*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	VOPNAME_CREATE, offsetof(struct vnodeops, vop_create),
132*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	VOPNAME_REMOVE, offsetof(struct vnodeops, vop_remove),
135*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	VOPNAME_LINK, offsetof(struct vnodeops, vop_link),
138*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	VOPNAME_RENAME, offsetof(struct vnodeops, vop_rename),
141*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	VOPNAME_MKDIR, offsetof(struct vnodeops, vop_mkdir),
144*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	VOPNAME_RMDIR, offsetof(struct vnodeops, vop_rmdir),
147*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	VOPNAME_READDIR, offsetof(struct vnodeops, vop_readdir),
150*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	VOPNAME_SYMLINK, offsetof(struct vnodeops, vop_symlink),
153*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	VOPNAME_READLINK, offsetof(struct vnodeops, vop_readlink),
156*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	VOPNAME_FSYNC, offsetof(struct vnodeops, vop_fsync),
159*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	VOPNAME_INACTIVE, offsetof(struct vnodeops, vop_inactive),
162*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	VOPNAME_FID, offsetof(struct vnodeops, vop_fid),
165*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	VOPNAME_RWLOCK, offsetof(struct vnodeops, vop_rwlock),
168*7c478bd9Sstevel@tonic-gate 	    fs_rwlock, fs_rwlock,
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	VOPNAME_RWUNLOCK, offsetof(struct vnodeops, vop_rwunlock),
171*7c478bd9Sstevel@tonic-gate 	    (fs_generic_func_p) fs_rwunlock,
172*7c478bd9Sstevel@tonic-gate 	    (fs_generic_func_p) fs_rwunlock,	/* no errors allowed */
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	VOPNAME_SEEK, offsetof(struct vnodeops, vop_seek),
175*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	VOPNAME_CMP, offsetof(struct vnodeops, vop_cmp),
178*7c478bd9Sstevel@tonic-gate 	    fs_cmp, fs_cmp,		/* no errors allowed */
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	VOPNAME_FRLOCK, offsetof(struct vnodeops, vop_frlock),
181*7c478bd9Sstevel@tonic-gate 	    fs_frlock, fs_nosys,
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	VOPNAME_SPACE, offsetof(struct vnodeops, vop_space),
184*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	VOPNAME_REALVP, offsetof(struct vnodeops, vop_realvp),
187*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	VOPNAME_GETPAGE, offsetof(struct vnodeops, vop_getpage),
190*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	VOPNAME_PUTPAGE, offsetof(struct vnodeops, vop_putpage),
193*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	VOPNAME_MAP, offsetof(struct vnodeops, vop_map),
196*7c478bd9Sstevel@tonic-gate 	    (fs_generic_func_p) fs_nosys_map,
197*7c478bd9Sstevel@tonic-gate 	    (fs_generic_func_p) fs_nosys_map,
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 	VOPNAME_ADDMAP, offsetof(struct vnodeops, vop_addmap),
200*7c478bd9Sstevel@tonic-gate 	    (fs_generic_func_p) fs_nosys_addmap,
201*7c478bd9Sstevel@tonic-gate 	    (fs_generic_func_p) fs_nosys_addmap,
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	VOPNAME_DELMAP, offsetof(struct vnodeops, vop_delmap),
204*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	VOPNAME_POLL, offsetof(struct vnodeops, vop_poll),
207*7c478bd9Sstevel@tonic-gate 	    (fs_generic_func_p) fs_poll, (fs_generic_func_p) fs_nosys_poll,
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	VOPNAME_DUMP, offsetof(struct vnodeops, vop_dump),
210*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	VOPNAME_PATHCONF, offsetof(struct vnodeops, vop_pathconf),
213*7c478bd9Sstevel@tonic-gate 	    fs_pathconf, fs_nosys,
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	VOPNAME_PAGEIO, offsetof(struct vnodeops, vop_pageio),
216*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	VOPNAME_DUMPCTL, offsetof(struct vnodeops, vop_dumpctl),
219*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	VOPNAME_DISPOSE, offsetof(struct vnodeops, vop_dispose),
222*7c478bd9Sstevel@tonic-gate 	    (fs_generic_func_p) fs_dispose,
223*7c478bd9Sstevel@tonic-gate 	    (fs_generic_func_p) fs_nodispose,
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	VOPNAME_SETSECATTR, offsetof(struct vnodeops, vop_setsecattr),
226*7c478bd9Sstevel@tonic-gate 	    fs_nosys, fs_nosys,
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	VOPNAME_GETSECATTR, offsetof(struct vnodeops, vop_getsecattr),
229*7c478bd9Sstevel@tonic-gate 	    fs_fab_acl, fs_nosys,
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	VOPNAME_SHRLOCK, offsetof(struct vnodeops, vop_shrlock),
232*7c478bd9Sstevel@tonic-gate 	    fs_shrlock, fs_nosys,
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	VOPNAME_VNEVENT, offsetof(struct vnodeops, vop_vnevent),
235*7c478bd9Sstevel@tonic-gate 	    (fs_generic_func_p) fs_vnevent_nosupport,
236*7c478bd9Sstevel@tonic-gate 	    (fs_generic_func_p) fs_vnevent_nosupport,
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	NULL, 0, NULL, NULL
239*7c478bd9Sstevel@tonic-gate };
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate /*
243*7c478bd9Sstevel@tonic-gate  * Read or write a vnode.  Called from kernel code.
244*7c478bd9Sstevel@tonic-gate  */
245*7c478bd9Sstevel@tonic-gate int
246*7c478bd9Sstevel@tonic-gate vn_rdwr(
247*7c478bd9Sstevel@tonic-gate 	enum uio_rw rw,
248*7c478bd9Sstevel@tonic-gate 	struct vnode *vp,
249*7c478bd9Sstevel@tonic-gate 	caddr_t base,
250*7c478bd9Sstevel@tonic-gate 	ssize_t len,
251*7c478bd9Sstevel@tonic-gate 	offset_t offset,
252*7c478bd9Sstevel@tonic-gate 	enum uio_seg seg,
253*7c478bd9Sstevel@tonic-gate 	int ioflag,
254*7c478bd9Sstevel@tonic-gate 	rlim64_t ulimit,	/* meaningful only if rw is UIO_WRITE */
255*7c478bd9Sstevel@tonic-gate 	cred_t *cr,
256*7c478bd9Sstevel@tonic-gate 	ssize_t *residp)
257*7c478bd9Sstevel@tonic-gate {
258*7c478bd9Sstevel@tonic-gate 	struct uio uio;
259*7c478bd9Sstevel@tonic-gate 	struct iovec iov;
260*7c478bd9Sstevel@tonic-gate 	int error;
261*7c478bd9Sstevel@tonic-gate 	int in_crit = 0;
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	if (rw == UIO_WRITE && ISROFILE(vp))
264*7c478bd9Sstevel@tonic-gate 		return (EROFS);
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	if (len < 0)
267*7c478bd9Sstevel@tonic-gate 		return (EIO);
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	iov.iov_base = base;
270*7c478bd9Sstevel@tonic-gate 	iov.iov_len = len;
271*7c478bd9Sstevel@tonic-gate 	uio.uio_iov = &iov;
272*7c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = 1;
273*7c478bd9Sstevel@tonic-gate 	uio.uio_loffset = offset;
274*7c478bd9Sstevel@tonic-gate 	uio.uio_segflg = (short)seg;
275*7c478bd9Sstevel@tonic-gate 	uio.uio_resid = len;
276*7c478bd9Sstevel@tonic-gate 	uio.uio_llimit = ulimit;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	/*
279*7c478bd9Sstevel@tonic-gate 	 * We have to enter the critical region before calling VOP_RWLOCK
280*7c478bd9Sstevel@tonic-gate 	 * to avoid a deadlock with ufs.
281*7c478bd9Sstevel@tonic-gate 	 */
282*7c478bd9Sstevel@tonic-gate 	if (nbl_need_check(vp)) {
283*7c478bd9Sstevel@tonic-gate 		int svmand;
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 		nbl_start_crit(vp, RW_READER);
286*7c478bd9Sstevel@tonic-gate 		in_crit = 1;
287*7c478bd9Sstevel@tonic-gate 		error = nbl_svmand(vp, cr, &svmand);
288*7c478bd9Sstevel@tonic-gate 		if (error != 0)
289*7c478bd9Sstevel@tonic-gate 			goto done;
290*7c478bd9Sstevel@tonic-gate 		if (nbl_conflict(vp, rw == UIO_WRITE ? NBL_WRITE : NBL_READ,
291*7c478bd9Sstevel@tonic-gate 		    uio.uio_offset, uio.uio_resid, svmand)) {
292*7c478bd9Sstevel@tonic-gate 			error = EACCES;
293*7c478bd9Sstevel@tonic-gate 			goto done;
294*7c478bd9Sstevel@tonic-gate 		}
295*7c478bd9Sstevel@tonic-gate 	}
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp,
298*7c478bd9Sstevel@tonic-gate 		rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE, NULL);
299*7c478bd9Sstevel@tonic-gate 	if (rw == UIO_WRITE) {
300*7c478bd9Sstevel@tonic-gate 		uio.uio_fmode = FWRITE;
301*7c478bd9Sstevel@tonic-gate 		uio.uio_extflg = UIO_COPY_DEFAULT;
302*7c478bd9Sstevel@tonic-gate 		error = VOP_WRITE(vp, &uio, ioflag, cr, NULL);
303*7c478bd9Sstevel@tonic-gate 	} else {
304*7c478bd9Sstevel@tonic-gate 		uio.uio_fmode = FREAD;
305*7c478bd9Sstevel@tonic-gate 		uio.uio_extflg = UIO_COPY_CACHED;
306*7c478bd9Sstevel@tonic-gate 		error = VOP_READ(vp, &uio, ioflag, cr, NULL);
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE,
309*7c478bd9Sstevel@tonic-gate 									NULL);
310*7c478bd9Sstevel@tonic-gate 	if (residp)
311*7c478bd9Sstevel@tonic-gate 		*residp = uio.uio_resid;
312*7c478bd9Sstevel@tonic-gate 	else if (uio.uio_resid)
313*7c478bd9Sstevel@tonic-gate 		error = EIO;
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate done:
316*7c478bd9Sstevel@tonic-gate 	if (in_crit)
317*7c478bd9Sstevel@tonic-gate 		nbl_end_crit(vp);
318*7c478bd9Sstevel@tonic-gate 	return (error);
319*7c478bd9Sstevel@tonic-gate }
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate /*
322*7c478bd9Sstevel@tonic-gate  * Release a vnode.  Call VOP_INACTIVE on last reference or
323*7c478bd9Sstevel@tonic-gate  * decrement reference count.
324*7c478bd9Sstevel@tonic-gate  *
325*7c478bd9Sstevel@tonic-gate  * To avoid race conditions, the v_count is left at 1 for
326*7c478bd9Sstevel@tonic-gate  * the call to VOP_INACTIVE. This prevents another thread
327*7c478bd9Sstevel@tonic-gate  * from reclaiming and releasing the vnode *before* the
328*7c478bd9Sstevel@tonic-gate  * VOP_INACTIVE routine has a chance to destroy the vnode.
329*7c478bd9Sstevel@tonic-gate  * We can't have more than 1 thread calling VOP_INACTIVE
330*7c478bd9Sstevel@tonic-gate  * on a vnode.
331*7c478bd9Sstevel@tonic-gate  */
332*7c478bd9Sstevel@tonic-gate void
333*7c478bd9Sstevel@tonic-gate vn_rele(vnode_t *vp)
334*7c478bd9Sstevel@tonic-gate {
335*7c478bd9Sstevel@tonic-gate 	if (vp->v_count == 0)
336*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "vn_rele: vnode ref count 0");
337*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
338*7c478bd9Sstevel@tonic-gate 	if (vp->v_count == 1) {
339*7c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
340*7c478bd9Sstevel@tonic-gate 		VOP_INACTIVE(vp, CRED());
341*7c478bd9Sstevel@tonic-gate 	} else {
342*7c478bd9Sstevel@tonic-gate 		vp->v_count--;
343*7c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
344*7c478bd9Sstevel@tonic-gate 	}
345*7c478bd9Sstevel@tonic-gate }
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate /*
348*7c478bd9Sstevel@tonic-gate  * Like vn_rele() except that it clears v_stream under v_lock.
349*7c478bd9Sstevel@tonic-gate  * This is used by sockfs when it dismantels the association between
350*7c478bd9Sstevel@tonic-gate  * the sockfs node and the vnode in the underlaying file system.
351*7c478bd9Sstevel@tonic-gate  * v_lock has to be held to prevent a thread coming through the lookupname
352*7c478bd9Sstevel@tonic-gate  * path from accessing a stream head that is going away.
353*7c478bd9Sstevel@tonic-gate  */
354*7c478bd9Sstevel@tonic-gate void
355*7c478bd9Sstevel@tonic-gate vn_rele_stream(vnode_t *vp)
356*7c478bd9Sstevel@tonic-gate {
357*7c478bd9Sstevel@tonic-gate 	if (vp->v_count == 0)
358*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "vn_rele: vnode ref count 0");
359*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
360*7c478bd9Sstevel@tonic-gate 	vp->v_stream = NULL;
361*7c478bd9Sstevel@tonic-gate 	if (vp->v_count == 1) {
362*7c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
363*7c478bd9Sstevel@tonic-gate 		VOP_INACTIVE(vp, CRED());
364*7c478bd9Sstevel@tonic-gate 	} else {
365*7c478bd9Sstevel@tonic-gate 		vp->v_count--;
366*7c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
367*7c478bd9Sstevel@tonic-gate 	}
368*7c478bd9Sstevel@tonic-gate }
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate int
371*7c478bd9Sstevel@tonic-gate vn_open(
372*7c478bd9Sstevel@tonic-gate 	char *pnamep,
373*7c478bd9Sstevel@tonic-gate 	enum uio_seg seg,
374*7c478bd9Sstevel@tonic-gate 	int filemode,
375*7c478bd9Sstevel@tonic-gate 	int createmode,
376*7c478bd9Sstevel@tonic-gate 	struct vnode **vpp,
377*7c478bd9Sstevel@tonic-gate 	enum create crwhy,
378*7c478bd9Sstevel@tonic-gate 	mode_t umask)
379*7c478bd9Sstevel@tonic-gate {
380*7c478bd9Sstevel@tonic-gate 	return (vn_openat(pnamep, seg, filemode,
381*7c478bd9Sstevel@tonic-gate 			createmode, vpp, crwhy, umask, NULL));
382*7c478bd9Sstevel@tonic-gate }
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate /*
386*7c478bd9Sstevel@tonic-gate  * Open/create a vnode.
387*7c478bd9Sstevel@tonic-gate  * This may be callable by the kernel, the only known use
388*7c478bd9Sstevel@tonic-gate  * of user context being that the current user credentials
389*7c478bd9Sstevel@tonic-gate  * are used for permissions.  crwhy is defined iff filemode & FCREAT.
390*7c478bd9Sstevel@tonic-gate  */
391*7c478bd9Sstevel@tonic-gate int
392*7c478bd9Sstevel@tonic-gate vn_openat(
393*7c478bd9Sstevel@tonic-gate 	char *pnamep,
394*7c478bd9Sstevel@tonic-gate 	enum uio_seg seg,
395*7c478bd9Sstevel@tonic-gate 	int filemode,
396*7c478bd9Sstevel@tonic-gate 	int createmode,
397*7c478bd9Sstevel@tonic-gate 	struct vnode **vpp,
398*7c478bd9Sstevel@tonic-gate 	enum create crwhy,
399*7c478bd9Sstevel@tonic-gate 	mode_t umask,
400*7c478bd9Sstevel@tonic-gate 	struct vnode *startvp)
401*7c478bd9Sstevel@tonic-gate {
402*7c478bd9Sstevel@tonic-gate 	struct vnode *vp;
403*7c478bd9Sstevel@tonic-gate 	int mode;
404*7c478bd9Sstevel@tonic-gate 	int error;
405*7c478bd9Sstevel@tonic-gate 	int in_crit = 0;
406*7c478bd9Sstevel@tonic-gate 	struct vattr vattr;
407*7c478bd9Sstevel@tonic-gate 	enum symfollow follow;
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	mode = 0;
410*7c478bd9Sstevel@tonic-gate 	if (filemode & FREAD)
411*7c478bd9Sstevel@tonic-gate 		mode |= VREAD;
412*7c478bd9Sstevel@tonic-gate 	if (filemode & (FWRITE|FTRUNC))
413*7c478bd9Sstevel@tonic-gate 		mode |= VWRITE;
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	/* symlink interpretation */
416*7c478bd9Sstevel@tonic-gate 	if (filemode & FNOFOLLOW)
417*7c478bd9Sstevel@tonic-gate 		follow = NO_FOLLOW;
418*7c478bd9Sstevel@tonic-gate 	else
419*7c478bd9Sstevel@tonic-gate 		follow = FOLLOW;
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate top:
422*7c478bd9Sstevel@tonic-gate 	if (filemode & FCREAT) {
423*7c478bd9Sstevel@tonic-gate 		enum vcexcl excl;
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 		/*
426*7c478bd9Sstevel@tonic-gate 		 * Wish to create a file.
427*7c478bd9Sstevel@tonic-gate 		 */
428*7c478bd9Sstevel@tonic-gate 		vattr.va_type = VREG;
429*7c478bd9Sstevel@tonic-gate 		vattr.va_mode = createmode;
430*7c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_TYPE|AT_MODE;
431*7c478bd9Sstevel@tonic-gate 		if (filemode & FTRUNC) {
432*7c478bd9Sstevel@tonic-gate 			vattr.va_size = 0;
433*7c478bd9Sstevel@tonic-gate 			vattr.va_mask |= AT_SIZE;
434*7c478bd9Sstevel@tonic-gate 		}
435*7c478bd9Sstevel@tonic-gate 		if (filemode & FEXCL)
436*7c478bd9Sstevel@tonic-gate 			excl = EXCL;
437*7c478bd9Sstevel@tonic-gate 		else
438*7c478bd9Sstevel@tonic-gate 			excl = NONEXCL;
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 		if (error =
441*7c478bd9Sstevel@tonic-gate 		    vn_createat(pnamep, seg, &vattr, excl, mode, &vp, crwhy,
442*7c478bd9Sstevel@tonic-gate 					(filemode & ~(FTRUNC|FEXCL)),
443*7c478bd9Sstevel@tonic-gate 						umask, startvp))
444*7c478bd9Sstevel@tonic-gate 			return (error);
445*7c478bd9Sstevel@tonic-gate 	} else {
446*7c478bd9Sstevel@tonic-gate 		/*
447*7c478bd9Sstevel@tonic-gate 		 * Wish to open a file.  Just look it up.
448*7c478bd9Sstevel@tonic-gate 		 */
449*7c478bd9Sstevel@tonic-gate 		if (error = lookupnameat(pnamep, seg, follow,
450*7c478bd9Sstevel@tonic-gate 		    NULLVPP, &vp, startvp)) {
451*7c478bd9Sstevel@tonic-gate 			if (error == ESTALE)
452*7c478bd9Sstevel@tonic-gate 				goto top;
453*7c478bd9Sstevel@tonic-gate 			return (error);
454*7c478bd9Sstevel@tonic-gate 		}
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 		/*
457*7c478bd9Sstevel@tonic-gate 		 * Get the attributes to check whether file is large.
458*7c478bd9Sstevel@tonic-gate 		 * We do this only if the FOFFMAX flag is not set and
459*7c478bd9Sstevel@tonic-gate 		 * only for regular files.
460*7c478bd9Sstevel@tonic-gate 		 */
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 		if (!(filemode & FOFFMAX) && (vp->v_type == VREG)) {
463*7c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_SIZE;
464*7c478bd9Sstevel@tonic-gate 			if ((error = VOP_GETATTR(vp, &vattr, 0, CRED()))) {
465*7c478bd9Sstevel@tonic-gate 				goto out;
466*7c478bd9Sstevel@tonic-gate 			}
467*7c478bd9Sstevel@tonic-gate 			if (vattr.va_size > (u_offset_t)MAXOFF32_T) {
468*7c478bd9Sstevel@tonic-gate 				/*
469*7c478bd9Sstevel@tonic-gate 				 * Large File API - regular open fails
470*7c478bd9Sstevel@tonic-gate 				 * if FOFFMAX flag is set in file mode
471*7c478bd9Sstevel@tonic-gate 				 */
472*7c478bd9Sstevel@tonic-gate 				error = EOVERFLOW;
473*7c478bd9Sstevel@tonic-gate 				goto out;
474*7c478bd9Sstevel@tonic-gate 			}
475*7c478bd9Sstevel@tonic-gate 		}
476*7c478bd9Sstevel@tonic-gate 		/*
477*7c478bd9Sstevel@tonic-gate 		 * Can't write directories, active texts, or
478*7c478bd9Sstevel@tonic-gate 		 * read-only filesystems.  Can't truncate files
479*7c478bd9Sstevel@tonic-gate 		 * on which mandatory locking is in effect.
480*7c478bd9Sstevel@tonic-gate 		 */
481*7c478bd9Sstevel@tonic-gate 		if (filemode & (FWRITE|FTRUNC)) {
482*7c478bd9Sstevel@tonic-gate 			/*
483*7c478bd9Sstevel@tonic-gate 			 * Allow writable directory if VDIROPEN flag is set.
484*7c478bd9Sstevel@tonic-gate 			 */
485*7c478bd9Sstevel@tonic-gate 			if (vp->v_type == VDIR && !(vp->v_flag & VDIROPEN)) {
486*7c478bd9Sstevel@tonic-gate 				error = EISDIR;
487*7c478bd9Sstevel@tonic-gate 				goto out;
488*7c478bd9Sstevel@tonic-gate 			}
489*7c478bd9Sstevel@tonic-gate 			if (ISROFILE(vp)) {
490*7c478bd9Sstevel@tonic-gate 				error = EROFS;
491*7c478bd9Sstevel@tonic-gate 				goto out;
492*7c478bd9Sstevel@tonic-gate 			}
493*7c478bd9Sstevel@tonic-gate 			/*
494*7c478bd9Sstevel@tonic-gate 			 * Can't truncate files on which mandatory locking
495*7c478bd9Sstevel@tonic-gate 			 * or non-blocking mandatory locking is in effect.
496*7c478bd9Sstevel@tonic-gate 			 */
497*7c478bd9Sstevel@tonic-gate 			if (filemode & FTRUNC) {
498*7c478bd9Sstevel@tonic-gate 				vnode_t *rvp;
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 				if (VOP_REALVP(vp, &rvp) != 0)
501*7c478bd9Sstevel@tonic-gate 					rvp = vp;
502*7c478bd9Sstevel@tonic-gate 				if (nbl_need_check(vp)) {
503*7c478bd9Sstevel@tonic-gate 					nbl_start_crit(vp, RW_READER);
504*7c478bd9Sstevel@tonic-gate 					in_crit = 1;
505*7c478bd9Sstevel@tonic-gate 					vattr.va_mask = AT_MODE|AT_SIZE;
506*7c478bd9Sstevel@tonic-gate 					if ((error = VOP_GETATTR(vp, &vattr, 0,
507*7c478bd9Sstevel@tonic-gate 					    CRED())) == 0) {
508*7c478bd9Sstevel@tonic-gate 						if (rvp->v_filocks != NULL)
509*7c478bd9Sstevel@tonic-gate 							if (MANDLOCK(vp,
510*7c478bd9Sstevel@tonic-gate 							    vattr.va_mode))
511*7c478bd9Sstevel@tonic-gate 								error = EAGAIN;
512*7c478bd9Sstevel@tonic-gate 						if (!error) {
513*7c478bd9Sstevel@tonic-gate 							if (nbl_conflict(vp,
514*7c478bd9Sstevel@tonic-gate 							    NBL_WRITE, 0,
515*7c478bd9Sstevel@tonic-gate 							    vattr.va_size, 0))
516*7c478bd9Sstevel@tonic-gate 								error = EACCES;
517*7c478bd9Sstevel@tonic-gate 						}
518*7c478bd9Sstevel@tonic-gate 					}
519*7c478bd9Sstevel@tonic-gate 				} else if (rvp->v_filocks != NULL) {
520*7c478bd9Sstevel@tonic-gate 					vattr.va_mask = AT_MODE;
521*7c478bd9Sstevel@tonic-gate 					if ((error = VOP_GETATTR(vp, &vattr,
522*7c478bd9Sstevel@tonic-gate 					    0, CRED())) == 0 && MANDLOCK(vp,
523*7c478bd9Sstevel@tonic-gate 					    vattr.va_mode))
524*7c478bd9Sstevel@tonic-gate 						error = EAGAIN;
525*7c478bd9Sstevel@tonic-gate 				}
526*7c478bd9Sstevel@tonic-gate 			}
527*7c478bd9Sstevel@tonic-gate 			if (error)
528*7c478bd9Sstevel@tonic-gate 				goto out;
529*7c478bd9Sstevel@tonic-gate 		}
530*7c478bd9Sstevel@tonic-gate 		/*
531*7c478bd9Sstevel@tonic-gate 		 * Check permissions.
532*7c478bd9Sstevel@tonic-gate 		 */
533*7c478bd9Sstevel@tonic-gate 		if (error = VOP_ACCESS(vp, mode, 0, CRED()))
534*7c478bd9Sstevel@tonic-gate 			goto out;
535*7c478bd9Sstevel@tonic-gate 	}
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 	/*
538*7c478bd9Sstevel@tonic-gate 	 * Do remaining checks for FNOFOLLOW and FNOLINKS.
539*7c478bd9Sstevel@tonic-gate 	 */
540*7c478bd9Sstevel@tonic-gate 	if ((filemode & FNOFOLLOW) && vp->v_type == VLNK) {
541*7c478bd9Sstevel@tonic-gate 		error = EINVAL;
542*7c478bd9Sstevel@tonic-gate 		goto out;
543*7c478bd9Sstevel@tonic-gate 	}
544*7c478bd9Sstevel@tonic-gate 	if (filemode & FNOLINKS) {
545*7c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_NLINK;
546*7c478bd9Sstevel@tonic-gate 		if ((error = VOP_GETATTR(vp, &vattr, 0, CRED()))) {
547*7c478bd9Sstevel@tonic-gate 			goto out;
548*7c478bd9Sstevel@tonic-gate 		}
549*7c478bd9Sstevel@tonic-gate 		if (vattr.va_nlink != 1) {
550*7c478bd9Sstevel@tonic-gate 			error = EMLINK;
551*7c478bd9Sstevel@tonic-gate 			goto out;
552*7c478bd9Sstevel@tonic-gate 		}
553*7c478bd9Sstevel@tonic-gate 	}
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	/*
556*7c478bd9Sstevel@tonic-gate 	 * Opening a socket corresponding to the AF_UNIX pathname
557*7c478bd9Sstevel@tonic-gate 	 * in the filesystem name space is not supported.
558*7c478bd9Sstevel@tonic-gate 	 * However, VSOCK nodes in namefs are supported in order
559*7c478bd9Sstevel@tonic-gate 	 * to make fattach work for sockets.
560*7c478bd9Sstevel@tonic-gate 	 *
561*7c478bd9Sstevel@tonic-gate 	 * XXX This uses VOP_REALVP to distinguish between
562*7c478bd9Sstevel@tonic-gate 	 * an unopened namefs node (where VOP_REALVP returns a
563*7c478bd9Sstevel@tonic-gate 	 * different VSOCK vnode) and a VSOCK created by vn_create
564*7c478bd9Sstevel@tonic-gate 	 * in some file system (where VOP_REALVP would never return
565*7c478bd9Sstevel@tonic-gate 	 * a different vnode).
566*7c478bd9Sstevel@tonic-gate 	 */
567*7c478bd9Sstevel@tonic-gate 	if (vp->v_type == VSOCK) {
568*7c478bd9Sstevel@tonic-gate 		struct vnode *nvp;
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 		error = VOP_REALVP(vp, &nvp);
571*7c478bd9Sstevel@tonic-gate 		if (error != 0 || nvp == NULL || nvp == vp ||
572*7c478bd9Sstevel@tonic-gate 		    nvp->v_type != VSOCK) {
573*7c478bd9Sstevel@tonic-gate 			error = EOPNOTSUPP;
574*7c478bd9Sstevel@tonic-gate 			goto out;
575*7c478bd9Sstevel@tonic-gate 		}
576*7c478bd9Sstevel@tonic-gate 	}
577*7c478bd9Sstevel@tonic-gate 	/*
578*7c478bd9Sstevel@tonic-gate 	 * Do opening protocol.
579*7c478bd9Sstevel@tonic-gate 	 */
580*7c478bd9Sstevel@tonic-gate 	error = VOP_OPEN(&vp, filemode, CRED());
581*7c478bd9Sstevel@tonic-gate 	/*
582*7c478bd9Sstevel@tonic-gate 	 * Truncate if required.
583*7c478bd9Sstevel@tonic-gate 	 */
584*7c478bd9Sstevel@tonic-gate 	if (error == 0 && (filemode & FTRUNC) && !(filemode & FCREAT)) {
585*7c478bd9Sstevel@tonic-gate 		vattr.va_size = 0;
586*7c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_SIZE;
587*7c478bd9Sstevel@tonic-gate 		if ((error = VOP_SETATTR(vp, &vattr, 0, CRED(), NULL)) != 0)
588*7c478bd9Sstevel@tonic-gate 			(void) VOP_CLOSE(vp, filemode, 1, (offset_t)0, CRED());
589*7c478bd9Sstevel@tonic-gate 	}
590*7c478bd9Sstevel@tonic-gate out:
591*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_count > 0);
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 	if (in_crit) {
594*7c478bd9Sstevel@tonic-gate 		nbl_end_crit(vp);
595*7c478bd9Sstevel@tonic-gate 		in_crit = 0;
596*7c478bd9Sstevel@tonic-gate 	}
597*7c478bd9Sstevel@tonic-gate 	if (error) {
598*7c478bd9Sstevel@tonic-gate 		/*
599*7c478bd9Sstevel@tonic-gate 		 * The following clause was added to handle a problem
600*7c478bd9Sstevel@tonic-gate 		 * with NFS consistency.  It is possible that a lookup
601*7c478bd9Sstevel@tonic-gate 		 * of the file to be opened succeeded, but the file
602*7c478bd9Sstevel@tonic-gate 		 * itself doesn't actually exist on the server.  This
603*7c478bd9Sstevel@tonic-gate 		 * is chiefly due to the DNLC containing an entry for
604*7c478bd9Sstevel@tonic-gate 		 * the file which has been removed on the server.  In
605*7c478bd9Sstevel@tonic-gate 		 * this case, we just start over.  If there was some
606*7c478bd9Sstevel@tonic-gate 		 * other cause for the ESTALE error, then the lookup
607*7c478bd9Sstevel@tonic-gate 		 * of the file will fail and the error will be returned
608*7c478bd9Sstevel@tonic-gate 		 * above instead of looping around from here.
609*7c478bd9Sstevel@tonic-gate 		 */
610*7c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
611*7c478bd9Sstevel@tonic-gate 		if (error == ESTALE)
612*7c478bd9Sstevel@tonic-gate 			goto top;
613*7c478bd9Sstevel@tonic-gate 	} else
614*7c478bd9Sstevel@tonic-gate 		*vpp = vp;
615*7c478bd9Sstevel@tonic-gate 	return (error);
616*7c478bd9Sstevel@tonic-gate }
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate int
619*7c478bd9Sstevel@tonic-gate vn_create(
620*7c478bd9Sstevel@tonic-gate 	char *pnamep,
621*7c478bd9Sstevel@tonic-gate 	enum uio_seg seg,
622*7c478bd9Sstevel@tonic-gate 	struct vattr *vap,
623*7c478bd9Sstevel@tonic-gate 	enum vcexcl excl,
624*7c478bd9Sstevel@tonic-gate 	int mode,
625*7c478bd9Sstevel@tonic-gate 	struct vnode **vpp,
626*7c478bd9Sstevel@tonic-gate 	enum create why,
627*7c478bd9Sstevel@tonic-gate 	int flag,
628*7c478bd9Sstevel@tonic-gate 	mode_t umask)
629*7c478bd9Sstevel@tonic-gate {
630*7c478bd9Sstevel@tonic-gate 	return (vn_createat(pnamep, seg, vap, excl, mode, vpp,
631*7c478bd9Sstevel@tonic-gate 			why, flag, umask, NULL));
632*7c478bd9Sstevel@tonic-gate }
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate /*
635*7c478bd9Sstevel@tonic-gate  * Create a vnode (makenode).
636*7c478bd9Sstevel@tonic-gate  */
637*7c478bd9Sstevel@tonic-gate int
638*7c478bd9Sstevel@tonic-gate vn_createat(
639*7c478bd9Sstevel@tonic-gate 	char *pnamep,
640*7c478bd9Sstevel@tonic-gate 	enum uio_seg seg,
641*7c478bd9Sstevel@tonic-gate 	struct vattr *vap,
642*7c478bd9Sstevel@tonic-gate 	enum vcexcl excl,
643*7c478bd9Sstevel@tonic-gate 	int mode,
644*7c478bd9Sstevel@tonic-gate 	struct vnode **vpp,
645*7c478bd9Sstevel@tonic-gate 	enum create why,
646*7c478bd9Sstevel@tonic-gate 	int flag,
647*7c478bd9Sstevel@tonic-gate 	mode_t umask,
648*7c478bd9Sstevel@tonic-gate 	struct vnode *startvp)
649*7c478bd9Sstevel@tonic-gate {
650*7c478bd9Sstevel@tonic-gate 	struct vnode *dvp;	/* ptr to parent dir vnode */
651*7c478bd9Sstevel@tonic-gate 	struct vnode *vp = NULL;
652*7c478bd9Sstevel@tonic-gate 	struct pathname pn;
653*7c478bd9Sstevel@tonic-gate 	int error;
654*7c478bd9Sstevel@tonic-gate 	int in_crit = 0;
655*7c478bd9Sstevel@tonic-gate 	struct vattr vattr;
656*7c478bd9Sstevel@tonic-gate 	enum symfollow follow;
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	/* symlink interpretation */
661*7c478bd9Sstevel@tonic-gate 	if ((flag & FNOFOLLOW) || excl == EXCL)
662*7c478bd9Sstevel@tonic-gate 		follow = NO_FOLLOW;
663*7c478bd9Sstevel@tonic-gate 	else
664*7c478bd9Sstevel@tonic-gate 		follow = FOLLOW;
665*7c478bd9Sstevel@tonic-gate 	flag &= ~(FNOFOLLOW|FNOLINKS);
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate top:
668*7c478bd9Sstevel@tonic-gate 	/*
669*7c478bd9Sstevel@tonic-gate 	 * Lookup directory.
670*7c478bd9Sstevel@tonic-gate 	 * If new object is a file, call lower level to create it.
671*7c478bd9Sstevel@tonic-gate 	 * Note that it is up to the lower level to enforce exclusive
672*7c478bd9Sstevel@tonic-gate 	 * creation, if the file is already there.
673*7c478bd9Sstevel@tonic-gate 	 * This allows the lower level to do whatever
674*7c478bd9Sstevel@tonic-gate 	 * locking or protocol that is needed to prevent races.
675*7c478bd9Sstevel@tonic-gate 	 * If the new object is directory call lower level to make
676*7c478bd9Sstevel@tonic-gate 	 * the new directory, with "." and "..".
677*7c478bd9Sstevel@tonic-gate 	 */
678*7c478bd9Sstevel@tonic-gate 	if (error = pn_get(pnamep, seg, &pn))
679*7c478bd9Sstevel@tonic-gate 		return (error);
680*7c478bd9Sstevel@tonic-gate #ifdef  C2_AUDIT
681*7c478bd9Sstevel@tonic-gate 	if (audit_active)
682*7c478bd9Sstevel@tonic-gate 		audit_vncreate_start();
683*7c478bd9Sstevel@tonic-gate #endif /* C2_AUDIT */
684*7c478bd9Sstevel@tonic-gate 	dvp = NULL;
685*7c478bd9Sstevel@tonic-gate 	*vpp = NULL;
686*7c478bd9Sstevel@tonic-gate 	/*
687*7c478bd9Sstevel@tonic-gate 	 * lookup will find the parent directory for the vnode.
688*7c478bd9Sstevel@tonic-gate 	 * When it is done the pn holds the name of the entry
689*7c478bd9Sstevel@tonic-gate 	 * in the directory.
690*7c478bd9Sstevel@tonic-gate 	 * If this is a non-exclusive create we also find the node itself.
691*7c478bd9Sstevel@tonic-gate 	 */
692*7c478bd9Sstevel@tonic-gate 	error = lookuppnat(&pn, NULL, follow, &dvp,
693*7c478bd9Sstevel@tonic-gate 	    (excl == EXCL) ? NULLVPP : vpp, startvp);
694*7c478bd9Sstevel@tonic-gate 	if (error) {
695*7c478bd9Sstevel@tonic-gate 		pn_free(&pn);
696*7c478bd9Sstevel@tonic-gate 		if (error == ESTALE)
697*7c478bd9Sstevel@tonic-gate 			goto top;
698*7c478bd9Sstevel@tonic-gate 		if (why == CRMKDIR && error == EINVAL)
699*7c478bd9Sstevel@tonic-gate 			error = EEXIST;		/* SVID */
700*7c478bd9Sstevel@tonic-gate 		return (error);
701*7c478bd9Sstevel@tonic-gate 	}
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 	if (why != CRMKNOD)
704*7c478bd9Sstevel@tonic-gate 		vap->va_mode &= ~VSVTX;
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate 	/*
707*7c478bd9Sstevel@tonic-gate 	 * If default ACLs are defined for the directory don't apply the
708*7c478bd9Sstevel@tonic-gate 	 * umask if umask is passed.
709*7c478bd9Sstevel@tonic-gate 	 */
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 	if (umask) {
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 		vsecattr_t vsec;
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 		vsec.vsa_aclcnt = 0;
716*7c478bd9Sstevel@tonic-gate 		vsec.vsa_aclentp = NULL;
717*7c478bd9Sstevel@tonic-gate 		vsec.vsa_dfaclcnt = 0;
718*7c478bd9Sstevel@tonic-gate 		vsec.vsa_dfaclentp = NULL;
719*7c478bd9Sstevel@tonic-gate 		vsec.vsa_mask = VSA_DFACLCNT;
720*7c478bd9Sstevel@tonic-gate 		if (error = VOP_GETSECATTR(dvp, &vsec, 0, CRED())) {
721*7c478bd9Sstevel@tonic-gate 			if (*vpp != NULL)
722*7c478bd9Sstevel@tonic-gate 				VN_RELE(*vpp);
723*7c478bd9Sstevel@tonic-gate 			goto out;
724*7c478bd9Sstevel@tonic-gate 		}
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 		/*
727*7c478bd9Sstevel@tonic-gate 		 * Apply the umask if no default ACLs.
728*7c478bd9Sstevel@tonic-gate 		 */
729*7c478bd9Sstevel@tonic-gate 		if (vsec.vsa_dfaclcnt == 0)
730*7c478bd9Sstevel@tonic-gate 			vap->va_mode &= ~umask;
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate 		/*
733*7c478bd9Sstevel@tonic-gate 		 * VOP_GETSECATTR() may have allocated memory for ACLs we
734*7c478bd9Sstevel@tonic-gate 		 * didn't request, so double-check and free it if necessary.
735*7c478bd9Sstevel@tonic-gate 		 */
736*7c478bd9Sstevel@tonic-gate 		if (vsec.vsa_aclcnt && vsec.vsa_aclentp != NULL)
737*7c478bd9Sstevel@tonic-gate 			kmem_free((caddr_t)vsec.vsa_aclentp,
738*7c478bd9Sstevel@tonic-gate 				vsec.vsa_aclcnt * sizeof (aclent_t));
739*7c478bd9Sstevel@tonic-gate 		if (vsec.vsa_dfaclcnt && vsec.vsa_dfaclentp != NULL)
740*7c478bd9Sstevel@tonic-gate 			kmem_free((caddr_t)vsec.vsa_dfaclentp,
741*7c478bd9Sstevel@tonic-gate 				vsec.vsa_dfaclcnt * sizeof (aclent_t));
742*7c478bd9Sstevel@tonic-gate 	}
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 	/*
745*7c478bd9Sstevel@tonic-gate 	 * In general we want to generate EROFS if the file system is
746*7c478bd9Sstevel@tonic-gate 	 * readonly.  However, POSIX (IEEE Std. 1003.1) section 5.3.1
747*7c478bd9Sstevel@tonic-gate 	 * documents the open system call, and it says that O_CREAT has no
748*7c478bd9Sstevel@tonic-gate 	 * effect if the file already exists.  Bug 1119649 states
749*7c478bd9Sstevel@tonic-gate 	 * that open(path, O_CREAT, ...) fails when attempting to open an
750*7c478bd9Sstevel@tonic-gate 	 * existing file on a read only file system.  Thus, the first part
751*7c478bd9Sstevel@tonic-gate 	 * of the following if statement has 3 checks:
752*7c478bd9Sstevel@tonic-gate 	 *	if the file exists &&
753*7c478bd9Sstevel@tonic-gate 	 *		it is being open with write access &&
754*7c478bd9Sstevel@tonic-gate 	 *		the file system is read only
755*7c478bd9Sstevel@tonic-gate 	 *	then generate EROFS
756*7c478bd9Sstevel@tonic-gate 	 */
757*7c478bd9Sstevel@tonic-gate 	if ((*vpp != NULL && (mode & VWRITE) && ISROFILE(*vpp)) ||
758*7c478bd9Sstevel@tonic-gate 	    (*vpp == NULL && dvp->v_vfsp->vfs_flag & VFS_RDONLY)) {
759*7c478bd9Sstevel@tonic-gate 		if (*vpp)
760*7c478bd9Sstevel@tonic-gate 			VN_RELE(*vpp);
761*7c478bd9Sstevel@tonic-gate 		error = EROFS;
762*7c478bd9Sstevel@tonic-gate 	} else if (excl == NONEXCL && *vpp != NULL) {
763*7c478bd9Sstevel@tonic-gate 		vnode_t *rvp;
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 		/*
766*7c478bd9Sstevel@tonic-gate 		 * File already exists.  If a mandatory lock has been
767*7c478bd9Sstevel@tonic-gate 		 * applied, return error.
768*7c478bd9Sstevel@tonic-gate 		 */
769*7c478bd9Sstevel@tonic-gate 		vp = *vpp;
770*7c478bd9Sstevel@tonic-gate 		if (VOP_REALVP(vp, &rvp) != 0)
771*7c478bd9Sstevel@tonic-gate 			rvp = vp;
772*7c478bd9Sstevel@tonic-gate 		if ((vap->va_mask & AT_SIZE) && nbl_need_check(vp)) {
773*7c478bd9Sstevel@tonic-gate 			nbl_start_crit(vp, RW_READER);
774*7c478bd9Sstevel@tonic-gate 			in_crit = 1;
775*7c478bd9Sstevel@tonic-gate 		}
776*7c478bd9Sstevel@tonic-gate 		if (rvp->v_filocks != NULL || rvp->v_shrlocks != NULL) {
777*7c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_MODE|AT_SIZE;
778*7c478bd9Sstevel@tonic-gate 			if (error = VOP_GETATTR(vp, &vattr, 0, CRED())) {
779*7c478bd9Sstevel@tonic-gate 				goto out;
780*7c478bd9Sstevel@tonic-gate 			}
781*7c478bd9Sstevel@tonic-gate 			if (MANDLOCK(vp, vattr.va_mode)) {
782*7c478bd9Sstevel@tonic-gate 				error = EAGAIN;
783*7c478bd9Sstevel@tonic-gate 				goto out;
784*7c478bd9Sstevel@tonic-gate 			}
785*7c478bd9Sstevel@tonic-gate 			/*
786*7c478bd9Sstevel@tonic-gate 			 * File cannot be truncated if non-blocking mandatory
787*7c478bd9Sstevel@tonic-gate 			 * locks are currently on the file.
788*7c478bd9Sstevel@tonic-gate 			 */
789*7c478bd9Sstevel@tonic-gate 			if ((vap->va_mask & AT_SIZE) && in_crit) {
790*7c478bd9Sstevel@tonic-gate 				u_offset_t offset;
791*7c478bd9Sstevel@tonic-gate 				ssize_t length;
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 				offset = vap->va_size > vattr.va_size ?
794*7c478bd9Sstevel@tonic-gate 						vattr.va_size : vap->va_size;
795*7c478bd9Sstevel@tonic-gate 				length = vap->va_size > vattr.va_size ?
796*7c478bd9Sstevel@tonic-gate 						vap->va_size - vattr.va_size :
797*7c478bd9Sstevel@tonic-gate 						vattr.va_size - vap->va_size;
798*7c478bd9Sstevel@tonic-gate 				if (nbl_conflict(vp, NBL_WRITE, offset,
799*7c478bd9Sstevel@tonic-gate 						length, 0)) {
800*7c478bd9Sstevel@tonic-gate 					error = EACCES;
801*7c478bd9Sstevel@tonic-gate 					goto out;
802*7c478bd9Sstevel@tonic-gate 				}
803*7c478bd9Sstevel@tonic-gate 			}
804*7c478bd9Sstevel@tonic-gate 		}
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 		/*
807*7c478bd9Sstevel@tonic-gate 		 * If the file is the root of a VFS, we've crossed a
808*7c478bd9Sstevel@tonic-gate 		 * mount point and the "containing" directory that we
809*7c478bd9Sstevel@tonic-gate 		 * acquired above (dvp) is irrelevant because it's in
810*7c478bd9Sstevel@tonic-gate 		 * a different file system.  We apply VOP_CREATE to the
811*7c478bd9Sstevel@tonic-gate 		 * target itself instead of to the containing directory
812*7c478bd9Sstevel@tonic-gate 		 * and supply a null path name to indicate (conventionally)
813*7c478bd9Sstevel@tonic-gate 		 * the node itself as the "component" of interest.
814*7c478bd9Sstevel@tonic-gate 		 *
815*7c478bd9Sstevel@tonic-gate 		 * The intercession of the file system is necessary to
816*7c478bd9Sstevel@tonic-gate 		 * ensure that the appropriate permission checks are
817*7c478bd9Sstevel@tonic-gate 		 * done.
818*7c478bd9Sstevel@tonic-gate 		 */
819*7c478bd9Sstevel@tonic-gate 		if (vp->v_flag & VROOT) {
820*7c478bd9Sstevel@tonic-gate 			ASSERT(why != CRMKDIR);
821*7c478bd9Sstevel@tonic-gate 			error =
822*7c478bd9Sstevel@tonic-gate 			    VOP_CREATE(vp, "", vap, excl, mode, vpp, CRED(),
823*7c478bd9Sstevel@tonic-gate 				    flag);
824*7c478bd9Sstevel@tonic-gate 			/*
825*7c478bd9Sstevel@tonic-gate 			 * If the create succeeded, it will have created
826*7c478bd9Sstevel@tonic-gate 			 * a new reference to the vnode.  Give up the
827*7c478bd9Sstevel@tonic-gate 			 * original reference.  The assertion should not
828*7c478bd9Sstevel@tonic-gate 			 * get triggered because NBMAND locks only apply to
829*7c478bd9Sstevel@tonic-gate 			 * VREG files.  And if in_crit is non-zero for some
830*7c478bd9Sstevel@tonic-gate 			 * reason, detect that here, rather than when we
831*7c478bd9Sstevel@tonic-gate 			 * deference a null vp.
832*7c478bd9Sstevel@tonic-gate 			 */
833*7c478bd9Sstevel@tonic-gate 			ASSERT(in_crit == 0);
834*7c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
835*7c478bd9Sstevel@tonic-gate 			vp = NULL;
836*7c478bd9Sstevel@tonic-gate 			goto out;
837*7c478bd9Sstevel@tonic-gate 		}
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 		/*
840*7c478bd9Sstevel@tonic-gate 		 * Large File API - non-large open (FOFFMAX flag not set)
841*7c478bd9Sstevel@tonic-gate 		 * of regular file fails if the file size exceeds MAXOFF32_T.
842*7c478bd9Sstevel@tonic-gate 		 */
843*7c478bd9Sstevel@tonic-gate 		if (why != CRMKDIR &&
844*7c478bd9Sstevel@tonic-gate 		    !(flag & FOFFMAX) &&
845*7c478bd9Sstevel@tonic-gate 		    (vp->v_type == VREG)) {
846*7c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_SIZE;
847*7c478bd9Sstevel@tonic-gate 			if ((error = VOP_GETATTR(vp, &vattr, 0, CRED()))) {
848*7c478bd9Sstevel@tonic-gate 				goto out;
849*7c478bd9Sstevel@tonic-gate 			}
850*7c478bd9Sstevel@tonic-gate 			if ((vattr.va_size > (u_offset_t)MAXOFF32_T)) {
851*7c478bd9Sstevel@tonic-gate 				error = EOVERFLOW;
852*7c478bd9Sstevel@tonic-gate 				goto out;
853*7c478bd9Sstevel@tonic-gate 			}
854*7c478bd9Sstevel@tonic-gate 		}
855*7c478bd9Sstevel@tonic-gate 	}
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	if (error == 0) {
858*7c478bd9Sstevel@tonic-gate 		/*
859*7c478bd9Sstevel@tonic-gate 		 * Call mkdir() if specified, otherwise create().
860*7c478bd9Sstevel@tonic-gate 		 */
861*7c478bd9Sstevel@tonic-gate 		int must_be_dir = pn_fixslash(&pn);	/* trailing '/'? */
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 		if (why == CRMKDIR)
864*7c478bd9Sstevel@tonic-gate 			error = VOP_MKDIR(dvp, pn.pn_path, vap, vpp, CRED());
865*7c478bd9Sstevel@tonic-gate 		else if (!must_be_dir)
866*7c478bd9Sstevel@tonic-gate 			error = VOP_CREATE(dvp, pn.pn_path, vap,
867*7c478bd9Sstevel@tonic-gate 			    excl, mode, vpp, CRED(), flag);
868*7c478bd9Sstevel@tonic-gate 		else
869*7c478bd9Sstevel@tonic-gate 			error = ENOTDIR;
870*7c478bd9Sstevel@tonic-gate 	}
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate out:
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT
875*7c478bd9Sstevel@tonic-gate 	if (audit_active)
876*7c478bd9Sstevel@tonic-gate 		audit_vncreate_finish(*vpp, error);
877*7c478bd9Sstevel@tonic-gate #endif  /* C2_AUDIT */
878*7c478bd9Sstevel@tonic-gate 	if (in_crit) {
879*7c478bd9Sstevel@tonic-gate 		nbl_end_crit(vp);
880*7c478bd9Sstevel@tonic-gate 		in_crit = 0;
881*7c478bd9Sstevel@tonic-gate 	}
882*7c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
883*7c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
884*7c478bd9Sstevel@tonic-gate 		vp = NULL;
885*7c478bd9Sstevel@tonic-gate 	}
886*7c478bd9Sstevel@tonic-gate 	pn_free(&pn);
887*7c478bd9Sstevel@tonic-gate 	VN_RELE(dvp);
888*7c478bd9Sstevel@tonic-gate 	/*
889*7c478bd9Sstevel@tonic-gate 	 * The following clause was added to handle a problem
890*7c478bd9Sstevel@tonic-gate 	 * with NFS consistency.  It is possible that a lookup
891*7c478bd9Sstevel@tonic-gate 	 * of the file to be created succeeded, but the file
892*7c478bd9Sstevel@tonic-gate 	 * itself doesn't actually exist on the server.  This
893*7c478bd9Sstevel@tonic-gate 	 * is chiefly due to the DNLC containing an entry for
894*7c478bd9Sstevel@tonic-gate 	 * the file which has been removed on the server.  In
895*7c478bd9Sstevel@tonic-gate 	 * this case, we just start over.  If there was some
896*7c478bd9Sstevel@tonic-gate 	 * other cause for the ESTALE error, then the lookup
897*7c478bd9Sstevel@tonic-gate 	 * of the file will fail and the error will be returned
898*7c478bd9Sstevel@tonic-gate 	 * above instead of looping around from here.
899*7c478bd9Sstevel@tonic-gate 	 */
900*7c478bd9Sstevel@tonic-gate 	if (error == ESTALE)
901*7c478bd9Sstevel@tonic-gate 		goto top;
902*7c478bd9Sstevel@tonic-gate 	return (error);
903*7c478bd9Sstevel@tonic-gate }
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate int
906*7c478bd9Sstevel@tonic-gate vn_link(char *from, char *to, enum uio_seg seg)
907*7c478bd9Sstevel@tonic-gate {
908*7c478bd9Sstevel@tonic-gate 	struct vnode *fvp;		/* from vnode ptr */
909*7c478bd9Sstevel@tonic-gate 	struct vnode *tdvp;		/* to directory vnode ptr */
910*7c478bd9Sstevel@tonic-gate 	struct pathname pn;
911*7c478bd9Sstevel@tonic-gate 	int error;
912*7c478bd9Sstevel@tonic-gate 	struct vattr vattr;
913*7c478bd9Sstevel@tonic-gate 	dev_t fsid;
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate top:
916*7c478bd9Sstevel@tonic-gate 	fvp = tdvp = NULL;
917*7c478bd9Sstevel@tonic-gate 	if (error = pn_get(to, seg, &pn))
918*7c478bd9Sstevel@tonic-gate 		return (error);
919*7c478bd9Sstevel@tonic-gate 	if (error = lookupname(from, seg, NO_FOLLOW, NULLVPP, &fvp))
920*7c478bd9Sstevel@tonic-gate 		goto out;
921*7c478bd9Sstevel@tonic-gate 	if (error = lookuppn(&pn, NULL, NO_FOLLOW, &tdvp, NULLVPP))
922*7c478bd9Sstevel@tonic-gate 		goto out;
923*7c478bd9Sstevel@tonic-gate 	/*
924*7c478bd9Sstevel@tonic-gate 	 * Make sure both source vnode and target directory vnode are
925*7c478bd9Sstevel@tonic-gate 	 * in the same vfs and that it is writeable.
926*7c478bd9Sstevel@tonic-gate 	 */
927*7c478bd9Sstevel@tonic-gate 	vattr.va_mask = AT_FSID;
928*7c478bd9Sstevel@tonic-gate 	if (error = VOP_GETATTR(fvp, &vattr, 0, CRED()))
929*7c478bd9Sstevel@tonic-gate 		goto out;
930*7c478bd9Sstevel@tonic-gate 	fsid = vattr.va_fsid;
931*7c478bd9Sstevel@tonic-gate 	vattr.va_mask = AT_FSID;
932*7c478bd9Sstevel@tonic-gate 	if (error = VOP_GETATTR(tdvp, &vattr, 0, CRED()))
933*7c478bd9Sstevel@tonic-gate 		goto out;
934*7c478bd9Sstevel@tonic-gate 	if (fsid != vattr.va_fsid) {
935*7c478bd9Sstevel@tonic-gate 		error = EXDEV;
936*7c478bd9Sstevel@tonic-gate 		goto out;
937*7c478bd9Sstevel@tonic-gate 	}
938*7c478bd9Sstevel@tonic-gate 	if (tdvp->v_vfsp->vfs_flag & VFS_RDONLY) {
939*7c478bd9Sstevel@tonic-gate 		error = EROFS;
940*7c478bd9Sstevel@tonic-gate 		goto out;
941*7c478bd9Sstevel@tonic-gate 	}
942*7c478bd9Sstevel@tonic-gate 	/*
943*7c478bd9Sstevel@tonic-gate 	 * Do the link.
944*7c478bd9Sstevel@tonic-gate 	 */
945*7c478bd9Sstevel@tonic-gate 	(void) pn_fixslash(&pn);
946*7c478bd9Sstevel@tonic-gate 	error = VOP_LINK(tdvp, fvp, pn.pn_path, CRED());
947*7c478bd9Sstevel@tonic-gate out:
948*7c478bd9Sstevel@tonic-gate 	pn_free(&pn);
949*7c478bd9Sstevel@tonic-gate 	if (fvp)
950*7c478bd9Sstevel@tonic-gate 		VN_RELE(fvp);
951*7c478bd9Sstevel@tonic-gate 	if (tdvp)
952*7c478bd9Sstevel@tonic-gate 		VN_RELE(tdvp);
953*7c478bd9Sstevel@tonic-gate 	if (error == ESTALE)
954*7c478bd9Sstevel@tonic-gate 		goto top;
955*7c478bd9Sstevel@tonic-gate 	return (error);
956*7c478bd9Sstevel@tonic-gate }
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate int
959*7c478bd9Sstevel@tonic-gate vn_rename(char *from, char *to, enum uio_seg seg)
960*7c478bd9Sstevel@tonic-gate {
961*7c478bd9Sstevel@tonic-gate 	return (vn_renameat(NULL, from, NULL, to, seg));
962*7c478bd9Sstevel@tonic-gate }
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate int
965*7c478bd9Sstevel@tonic-gate vn_renameat(vnode_t *fdvp, char *fname, vnode_t *tdvp,
966*7c478bd9Sstevel@tonic-gate 		char *tname, enum uio_seg seg)
967*7c478bd9Sstevel@tonic-gate {
968*7c478bd9Sstevel@tonic-gate 	int error;
969*7c478bd9Sstevel@tonic-gate 	struct vattr vattr;
970*7c478bd9Sstevel@tonic-gate 	struct pathname fpn;		/* from pathname */
971*7c478bd9Sstevel@tonic-gate 	struct pathname tpn;		/* to pathname */
972*7c478bd9Sstevel@tonic-gate 	dev_t fsid;
973*7c478bd9Sstevel@tonic-gate 	int in_crit = 0;
974*7c478bd9Sstevel@tonic-gate 	vnode_t *fromvp, *fvp;
975*7c478bd9Sstevel@tonic-gate 	vnode_t *tovp;
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate top:
978*7c478bd9Sstevel@tonic-gate 	fvp = fromvp = tovp = NULL;
979*7c478bd9Sstevel@tonic-gate 	/*
980*7c478bd9Sstevel@tonic-gate 	 * Get to and from pathnames.
981*7c478bd9Sstevel@tonic-gate 	 */
982*7c478bd9Sstevel@tonic-gate 	if (error = pn_get(fname, seg, &fpn))
983*7c478bd9Sstevel@tonic-gate 		return (error);
984*7c478bd9Sstevel@tonic-gate 	if (error = pn_get(tname, seg, &tpn)) {
985*7c478bd9Sstevel@tonic-gate 		pn_free(&fpn);
986*7c478bd9Sstevel@tonic-gate 		return (error);
987*7c478bd9Sstevel@tonic-gate 	}
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate 	/*
990*7c478bd9Sstevel@tonic-gate 	 * First we need to resolve the correct directories
991*7c478bd9Sstevel@tonic-gate 	 * The passed in directories may only be a starting point,
992*7c478bd9Sstevel@tonic-gate 	 * but we need the real directories the file(s) live in.
993*7c478bd9Sstevel@tonic-gate 	 * For example the fname may be something like usr/lib/sparc
994*7c478bd9Sstevel@tonic-gate 	 * and we were passed in the / directory, but we need to
995*7c478bd9Sstevel@tonic-gate 	 * use the lib directory for the rename.
996*7c478bd9Sstevel@tonic-gate 	 */
997*7c478bd9Sstevel@tonic-gate 
998*7c478bd9Sstevel@tonic-gate #ifdef  C2_AUDIT
999*7c478bd9Sstevel@tonic-gate 	if (audit_active)
1000*7c478bd9Sstevel@tonic-gate 		audit_setfsat_path(1);
1001*7c478bd9Sstevel@tonic-gate #endif /* C2_AUDIT */
1002*7c478bd9Sstevel@tonic-gate 	/*
1003*7c478bd9Sstevel@tonic-gate 	 * Lookup to and from directories.
1004*7c478bd9Sstevel@tonic-gate 	 */
1005*7c478bd9Sstevel@tonic-gate 	if (error = lookuppnat(&fpn, NULL, NO_FOLLOW, &fromvp, &fvp, fdvp)) {
1006*7c478bd9Sstevel@tonic-gate 		goto out;
1007*7c478bd9Sstevel@tonic-gate 	}
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 	/*
1010*7c478bd9Sstevel@tonic-gate 	 * Make sure there is an entry.
1011*7c478bd9Sstevel@tonic-gate 	 */
1012*7c478bd9Sstevel@tonic-gate 	if (fvp == NULL) {
1013*7c478bd9Sstevel@tonic-gate 		error = ENOENT;
1014*7c478bd9Sstevel@tonic-gate 		goto out;
1015*7c478bd9Sstevel@tonic-gate 	}
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate #ifdef  C2_AUDIT
1018*7c478bd9Sstevel@tonic-gate 	if (audit_active)
1019*7c478bd9Sstevel@tonic-gate 		audit_setfsat_path(3);
1020*7c478bd9Sstevel@tonic-gate #endif /* C2_AUDIT */
1021*7c478bd9Sstevel@tonic-gate 	if (error = lookuppnat(&tpn, NULL, NO_FOLLOW, &tovp, NULLVPP, tdvp)) {
1022*7c478bd9Sstevel@tonic-gate 		goto out;
1023*7c478bd9Sstevel@tonic-gate 	}
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 	/*
1026*7c478bd9Sstevel@tonic-gate 	 * Make sure both the from vnode directory and the to directory
1027*7c478bd9Sstevel@tonic-gate 	 * are in the same vfs and the to directory is writable.
1028*7c478bd9Sstevel@tonic-gate 	 * We check fsid's, not vfs pointers, so loopback fs works.
1029*7c478bd9Sstevel@tonic-gate 	 */
1030*7c478bd9Sstevel@tonic-gate 	if (fromvp != tovp) {
1031*7c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_FSID;
1032*7c478bd9Sstevel@tonic-gate 		if (error = VOP_GETATTR(fromvp, &vattr, 0, CRED()))
1033*7c478bd9Sstevel@tonic-gate 			goto out;
1034*7c478bd9Sstevel@tonic-gate 		fsid = vattr.va_fsid;
1035*7c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_FSID;
1036*7c478bd9Sstevel@tonic-gate 		if (error = VOP_GETATTR(tovp, &vattr, 0, CRED()))
1037*7c478bd9Sstevel@tonic-gate 			goto out;
1038*7c478bd9Sstevel@tonic-gate 		if (fsid != vattr.va_fsid) {
1039*7c478bd9Sstevel@tonic-gate 			error = EXDEV;
1040*7c478bd9Sstevel@tonic-gate 			goto out;
1041*7c478bd9Sstevel@tonic-gate 		}
1042*7c478bd9Sstevel@tonic-gate 	}
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate 	if (tovp->v_vfsp->vfs_flag & VFS_RDONLY) {
1045*7c478bd9Sstevel@tonic-gate 		error = EROFS;
1046*7c478bd9Sstevel@tonic-gate 		goto out;
1047*7c478bd9Sstevel@tonic-gate 	}
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 	if (nbl_need_check(fvp)) {
1050*7c478bd9Sstevel@tonic-gate 		nbl_start_crit(fvp, RW_READER);
1051*7c478bd9Sstevel@tonic-gate 		in_crit = 1;
1052*7c478bd9Sstevel@tonic-gate 		if (nbl_conflict(fvp, NBL_RENAME, 0, 0, 0)) {
1053*7c478bd9Sstevel@tonic-gate 			error = EACCES;
1054*7c478bd9Sstevel@tonic-gate 			goto out;
1055*7c478bd9Sstevel@tonic-gate 		}
1056*7c478bd9Sstevel@tonic-gate 	}
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate 	/*
1059*7c478bd9Sstevel@tonic-gate 	 * Do the rename.
1060*7c478bd9Sstevel@tonic-gate 	 */
1061*7c478bd9Sstevel@tonic-gate 	(void) pn_fixslash(&tpn);
1062*7c478bd9Sstevel@tonic-gate 	error = VOP_RENAME(fromvp, fpn.pn_path, tovp, tpn.pn_path, CRED());
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate out:
1065*7c478bd9Sstevel@tonic-gate 	pn_free(&fpn);
1066*7c478bd9Sstevel@tonic-gate 	pn_free(&tpn);
1067*7c478bd9Sstevel@tonic-gate 	if (in_crit) {
1068*7c478bd9Sstevel@tonic-gate 		nbl_end_crit(fvp);
1069*7c478bd9Sstevel@tonic-gate 		in_crit = 0;
1070*7c478bd9Sstevel@tonic-gate 	}
1071*7c478bd9Sstevel@tonic-gate 	if (fromvp)
1072*7c478bd9Sstevel@tonic-gate 		VN_RELE(fromvp);
1073*7c478bd9Sstevel@tonic-gate 	if (tovp)
1074*7c478bd9Sstevel@tonic-gate 		VN_RELE(tovp);
1075*7c478bd9Sstevel@tonic-gate 	if (fvp)
1076*7c478bd9Sstevel@tonic-gate 		VN_RELE(fvp);
1077*7c478bd9Sstevel@tonic-gate 	if (error == ESTALE)
1078*7c478bd9Sstevel@tonic-gate 		goto top;
1079*7c478bd9Sstevel@tonic-gate 	return (error);
1080*7c478bd9Sstevel@tonic-gate }
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate /*
1083*7c478bd9Sstevel@tonic-gate  * Remove a file or directory.
1084*7c478bd9Sstevel@tonic-gate  */
1085*7c478bd9Sstevel@tonic-gate int
1086*7c478bd9Sstevel@tonic-gate vn_remove(char *fnamep, enum uio_seg seg, enum rm dirflag)
1087*7c478bd9Sstevel@tonic-gate {
1088*7c478bd9Sstevel@tonic-gate 	return (vn_removeat(NULL, fnamep, seg, dirflag));
1089*7c478bd9Sstevel@tonic-gate }
1090*7c478bd9Sstevel@tonic-gate 
1091*7c478bd9Sstevel@tonic-gate int
1092*7c478bd9Sstevel@tonic-gate vn_removeat(vnode_t *startvp, char *fnamep, enum uio_seg seg, enum rm dirflag)
1093*7c478bd9Sstevel@tonic-gate {
1094*7c478bd9Sstevel@tonic-gate 	struct vnode *vp;		/* entry vnode */
1095*7c478bd9Sstevel@tonic-gate 	struct vnode *dvp;		/* ptr to parent dir vnode */
1096*7c478bd9Sstevel@tonic-gate 	struct vnode *coveredvp;
1097*7c478bd9Sstevel@tonic-gate 	struct pathname pn;		/* name of entry */
1098*7c478bd9Sstevel@tonic-gate 	enum vtype vtype;
1099*7c478bd9Sstevel@tonic-gate 	int error;
1100*7c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
1101*7c478bd9Sstevel@tonic-gate 	struct vfs *dvfsp;	/* ptr to parent dir vfs */
1102*7c478bd9Sstevel@tonic-gate 	int in_crit = 0;
1103*7c478bd9Sstevel@tonic-gate 
1104*7c478bd9Sstevel@tonic-gate top:
1105*7c478bd9Sstevel@tonic-gate 	if (error = pn_get(fnamep, seg, &pn))
1106*7c478bd9Sstevel@tonic-gate 		return (error);
1107*7c478bd9Sstevel@tonic-gate 	dvp = vp = NULL;
1108*7c478bd9Sstevel@tonic-gate 	if (error = lookuppnat(&pn, NULL, NO_FOLLOW, &dvp, &vp, startvp)) {
1109*7c478bd9Sstevel@tonic-gate 		pn_free(&pn);
1110*7c478bd9Sstevel@tonic-gate 		if (error == ESTALE)
1111*7c478bd9Sstevel@tonic-gate 			goto top;
1112*7c478bd9Sstevel@tonic-gate 		return (error);
1113*7c478bd9Sstevel@tonic-gate 	}
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate 	/*
1116*7c478bd9Sstevel@tonic-gate 	 * Make sure there is an entry.
1117*7c478bd9Sstevel@tonic-gate 	 */
1118*7c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
1119*7c478bd9Sstevel@tonic-gate 		error = ENOENT;
1120*7c478bd9Sstevel@tonic-gate 		goto out;
1121*7c478bd9Sstevel@tonic-gate 	}
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate 	vfsp = vp->v_vfsp;
1124*7c478bd9Sstevel@tonic-gate 	dvfsp = dvp->v_vfsp;
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	/*
1127*7c478bd9Sstevel@tonic-gate 	 * If the named file is the root of a mounted filesystem, fail,
1128*7c478bd9Sstevel@tonic-gate 	 * unless it's marked unlinkable.  In that case, unmount the
1129*7c478bd9Sstevel@tonic-gate 	 * filesystem and proceed to unlink the covered vnode.  (If the
1130*7c478bd9Sstevel@tonic-gate 	 * covered vnode is a directory, use rmdir instead of unlink,
1131*7c478bd9Sstevel@tonic-gate 	 * to avoid file system corruption.)
1132*7c478bd9Sstevel@tonic-gate 	 */
1133*7c478bd9Sstevel@tonic-gate 	if (vp->v_flag & VROOT) {
1134*7c478bd9Sstevel@tonic-gate 		if (vfsp->vfs_flag & VFS_UNLINKABLE) {
1135*7c478bd9Sstevel@tonic-gate 			if (dirflag == RMDIRECTORY) {
1136*7c478bd9Sstevel@tonic-gate 				/*
1137*7c478bd9Sstevel@tonic-gate 				 * User called rmdir(2) on a file that has
1138*7c478bd9Sstevel@tonic-gate 				 * been namefs mounted on top of.  Since
1139*7c478bd9Sstevel@tonic-gate 				 * namefs doesn't allow directories to
1140*7c478bd9Sstevel@tonic-gate 				 * be mounted on other files we know
1141*7c478bd9Sstevel@tonic-gate 				 * vp is not of type VDIR so fail to operation.
1142*7c478bd9Sstevel@tonic-gate 				 */
1143*7c478bd9Sstevel@tonic-gate 				error = ENOTDIR;
1144*7c478bd9Sstevel@tonic-gate 				goto out;
1145*7c478bd9Sstevel@tonic-gate 			}
1146*7c478bd9Sstevel@tonic-gate 			coveredvp = vfsp->vfs_vnodecovered;
1147*7c478bd9Sstevel@tonic-gate 			VN_HOLD(coveredvp);
1148*7c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
1149*7c478bd9Sstevel@tonic-gate 			vp = NULL;
1150*7c478bd9Sstevel@tonic-gate 			if ((error = vn_vfswlock(coveredvp)) == 0)
1151*7c478bd9Sstevel@tonic-gate 				error = dounmount(vfsp, 0, CRED());
1152*7c478bd9Sstevel@tonic-gate 			/*
1153*7c478bd9Sstevel@tonic-gate 			 * Unmounted the namefs file system; now get
1154*7c478bd9Sstevel@tonic-gate 			 * the object it was mounted over.
1155*7c478bd9Sstevel@tonic-gate 			 */
1156*7c478bd9Sstevel@tonic-gate 			vp = coveredvp;
1157*7c478bd9Sstevel@tonic-gate 			/*
1158*7c478bd9Sstevel@tonic-gate 			 * If namefs was mounted over a directory, then
1159*7c478bd9Sstevel@tonic-gate 			 * we want to use rmdir() instead of unlink().
1160*7c478bd9Sstevel@tonic-gate 			 */
1161*7c478bd9Sstevel@tonic-gate 			if (vp->v_type == VDIR)
1162*7c478bd9Sstevel@tonic-gate 				dirflag = RMDIRECTORY;
1163*7c478bd9Sstevel@tonic-gate 		} else
1164*7c478bd9Sstevel@tonic-gate 			error = EBUSY;
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate 		if (error)
1167*7c478bd9Sstevel@tonic-gate 			goto out;
1168*7c478bd9Sstevel@tonic-gate 	}
1169*7c478bd9Sstevel@tonic-gate 
1170*7c478bd9Sstevel@tonic-gate 	/*
1171*7c478bd9Sstevel@tonic-gate 	 * Make sure filesystem is writeable.
1172*7c478bd9Sstevel@tonic-gate 	 * We check the parent directory's vfs in case this is an lofs vnode.
1173*7c478bd9Sstevel@tonic-gate 	 */
1174*7c478bd9Sstevel@tonic-gate 	if (dvfsp && dvfsp->vfs_flag & VFS_RDONLY) {
1175*7c478bd9Sstevel@tonic-gate 		error = EROFS;
1176*7c478bd9Sstevel@tonic-gate 		goto out;
1177*7c478bd9Sstevel@tonic-gate 	}
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate 	vtype = vp->v_type;
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate 	/*
1182*7c478bd9Sstevel@tonic-gate 	 * If there is the possibility of an nbmand share reservation, make
1183*7c478bd9Sstevel@tonic-gate 	 * sure it's okay to remove the file.  Keep a reference to the
1184*7c478bd9Sstevel@tonic-gate 	 * vnode, so that we can exit the nbl critical region after
1185*7c478bd9Sstevel@tonic-gate 	 * calling VOP_REMOVE.
1186*7c478bd9Sstevel@tonic-gate 	 * If there is no possibility of an nbmand share reservation,
1187*7c478bd9Sstevel@tonic-gate 	 * release the vnode reference now.  Filesystems like NFS may
1188*7c478bd9Sstevel@tonic-gate 	 * behave differently if there is an extra reference, so get rid of
1189*7c478bd9Sstevel@tonic-gate 	 * this one.  Fortunately, we can't have nbmand mounts on NFS
1190*7c478bd9Sstevel@tonic-gate 	 * filesystems.
1191*7c478bd9Sstevel@tonic-gate 	 */
1192*7c478bd9Sstevel@tonic-gate 	if (nbl_need_check(vp)) {
1193*7c478bd9Sstevel@tonic-gate 		nbl_start_crit(vp, RW_READER);
1194*7c478bd9Sstevel@tonic-gate 		in_crit = 1;
1195*7c478bd9Sstevel@tonic-gate 		if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0)) {
1196*7c478bd9Sstevel@tonic-gate 			error = EACCES;
1197*7c478bd9Sstevel@tonic-gate 			goto out;
1198*7c478bd9Sstevel@tonic-gate 		}
1199*7c478bd9Sstevel@tonic-gate 	} else {
1200*7c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
1201*7c478bd9Sstevel@tonic-gate 		vp = NULL;
1202*7c478bd9Sstevel@tonic-gate 	}
1203*7c478bd9Sstevel@tonic-gate 
1204*7c478bd9Sstevel@tonic-gate 	if (dirflag == RMDIRECTORY) {
1205*7c478bd9Sstevel@tonic-gate 		/*
1206*7c478bd9Sstevel@tonic-gate 		 * Caller is using rmdir(2), which can only be applied to
1207*7c478bd9Sstevel@tonic-gate 		 * directories.
1208*7c478bd9Sstevel@tonic-gate 		 */
1209*7c478bd9Sstevel@tonic-gate 		if (vtype != VDIR) {
1210*7c478bd9Sstevel@tonic-gate 			error = ENOTDIR;
1211*7c478bd9Sstevel@tonic-gate 		} else {
1212*7c478bd9Sstevel@tonic-gate 			vnode_t *cwd;
1213*7c478bd9Sstevel@tonic-gate 			proc_t *pp = curproc;
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pp->p_lock);
1216*7c478bd9Sstevel@tonic-gate 			cwd = PTOU(pp)->u_cdir;
1217*7c478bd9Sstevel@tonic-gate 			VN_HOLD(cwd);
1218*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pp->p_lock);
1219*7c478bd9Sstevel@tonic-gate 			error = VOP_RMDIR(dvp, pn.pn_path, cwd, CRED());
1220*7c478bd9Sstevel@tonic-gate 			VN_RELE(cwd);
1221*7c478bd9Sstevel@tonic-gate 		}
1222*7c478bd9Sstevel@tonic-gate 	} else {
1223*7c478bd9Sstevel@tonic-gate 		/*
1224*7c478bd9Sstevel@tonic-gate 		 * Unlink(2) can be applied to anything.
1225*7c478bd9Sstevel@tonic-gate 		 */
1226*7c478bd9Sstevel@tonic-gate 		error = VOP_REMOVE(dvp, pn.pn_path, CRED());
1227*7c478bd9Sstevel@tonic-gate 	}
1228*7c478bd9Sstevel@tonic-gate 
1229*7c478bd9Sstevel@tonic-gate out:
1230*7c478bd9Sstevel@tonic-gate 	pn_free(&pn);
1231*7c478bd9Sstevel@tonic-gate 	if (in_crit) {
1232*7c478bd9Sstevel@tonic-gate 		nbl_end_crit(vp);
1233*7c478bd9Sstevel@tonic-gate 		in_crit = 0;
1234*7c478bd9Sstevel@tonic-gate 	}
1235*7c478bd9Sstevel@tonic-gate 	if (vp != NULL)
1236*7c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
1237*7c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
1238*7c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
1239*7c478bd9Sstevel@tonic-gate 	if (error == ESTALE)
1240*7c478bd9Sstevel@tonic-gate 		goto top;
1241*7c478bd9Sstevel@tonic-gate 	return (error);
1242*7c478bd9Sstevel@tonic-gate }
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate /*
1245*7c478bd9Sstevel@tonic-gate  * Utility function to compare equality of vnodes.
1246*7c478bd9Sstevel@tonic-gate  * Compare the underlying real vnodes, if there are underlying vnodes.
1247*7c478bd9Sstevel@tonic-gate  * This is a more thorough comparison than the VN_CMP() macro provides.
1248*7c478bd9Sstevel@tonic-gate  */
1249*7c478bd9Sstevel@tonic-gate int
1250*7c478bd9Sstevel@tonic-gate vn_compare(vnode_t *vp1, vnode_t *vp2)
1251*7c478bd9Sstevel@tonic-gate {
1252*7c478bd9Sstevel@tonic-gate 	vnode_t *realvp;
1253*7c478bd9Sstevel@tonic-gate 
1254*7c478bd9Sstevel@tonic-gate 	if (vp1 != NULL && VOP_REALVP(vp1, &realvp) == 0)
1255*7c478bd9Sstevel@tonic-gate 		vp1 = realvp;
1256*7c478bd9Sstevel@tonic-gate 	if (vp2 != NULL && VOP_REALVP(vp2, &realvp) == 0)
1257*7c478bd9Sstevel@tonic-gate 		vp2 = realvp;
1258*7c478bd9Sstevel@tonic-gate 	return (VN_CMP(vp1, vp2));
1259*7c478bd9Sstevel@tonic-gate }
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate /*
1262*7c478bd9Sstevel@tonic-gate  * The number of locks to hash into.  This value must be a power
1263*7c478bd9Sstevel@tonic-gate  * of 2 minus 1 and should probably also be prime.
1264*7c478bd9Sstevel@tonic-gate  */
1265*7c478bd9Sstevel@tonic-gate #define	NUM_BUCKETS	1023
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate struct  vn_vfslocks_bucket {
1268*7c478bd9Sstevel@tonic-gate 	kmutex_t vb_lock;
1269*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vb_list;
1270*7c478bd9Sstevel@tonic-gate 	char pad[64 - sizeof (kmutex_t) - sizeof (void *)];
1271*7c478bd9Sstevel@tonic-gate };
1272*7c478bd9Sstevel@tonic-gate 
1273*7c478bd9Sstevel@tonic-gate /*
1274*7c478bd9Sstevel@tonic-gate  * Total number of buckets will be NUM_BUCKETS + 1 .
1275*7c478bd9Sstevel@tonic-gate  */
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate #pragma	align	64(vn_vfslocks_buckets)
1278*7c478bd9Sstevel@tonic-gate static	struct vn_vfslocks_bucket	vn_vfslocks_buckets[NUM_BUCKETS + 1];
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate #define	VN_VFSLOCKS_SHIFT	9
1281*7c478bd9Sstevel@tonic-gate 
1282*7c478bd9Sstevel@tonic-gate #define	VN_VFSLOCKS_HASH(vfsvpptr)	\
1283*7c478bd9Sstevel@tonic-gate 	((((intptr_t)(vfsvpptr)) >> VN_VFSLOCKS_SHIFT) & NUM_BUCKETS)
1284*7c478bd9Sstevel@tonic-gate 
1285*7c478bd9Sstevel@tonic-gate /*
1286*7c478bd9Sstevel@tonic-gate  * vn_vfslocks_getlock() uses an HASH scheme to generate
1287*7c478bd9Sstevel@tonic-gate  * rwstlock using vfs/vnode pointer passed to it.
1288*7c478bd9Sstevel@tonic-gate  *
1289*7c478bd9Sstevel@tonic-gate  * vn_vfslocks_rele() releases a reference in the
1290*7c478bd9Sstevel@tonic-gate  * HASH table which allows the entry allocated by
1291*7c478bd9Sstevel@tonic-gate  * vn_vfslocks_getlock() to be freed at a later
1292*7c478bd9Sstevel@tonic-gate  * stage when the refcount drops to zero.
1293*7c478bd9Sstevel@tonic-gate  */
1294*7c478bd9Sstevel@tonic-gate 
1295*7c478bd9Sstevel@tonic-gate vn_vfslocks_entry_t *
1296*7c478bd9Sstevel@tonic-gate vn_vfslocks_getlock(void *vfsvpptr)
1297*7c478bd9Sstevel@tonic-gate {
1298*7c478bd9Sstevel@tonic-gate 	struct vn_vfslocks_bucket *bp;
1299*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vep;
1300*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *tvep;
1301*7c478bd9Sstevel@tonic-gate 
1302*7c478bd9Sstevel@tonic-gate 	ASSERT(vfsvpptr != NULL);
1303*7c478bd9Sstevel@tonic-gate 	bp = &vn_vfslocks_buckets[VN_VFSLOCKS_HASH(vfsvpptr)];
1304*7c478bd9Sstevel@tonic-gate 
1305*7c478bd9Sstevel@tonic-gate 	mutex_enter(&bp->vb_lock);
1306*7c478bd9Sstevel@tonic-gate 	for (vep = bp->vb_list; vep != NULL; vep = vep->ve_next) {
1307*7c478bd9Sstevel@tonic-gate 		if (vep->ve_vpvfs == vfsvpptr) {
1308*7c478bd9Sstevel@tonic-gate 			vep->ve_refcnt++;
1309*7c478bd9Sstevel@tonic-gate 			mutex_exit(&bp->vb_lock);
1310*7c478bd9Sstevel@tonic-gate 			return (vep);
1311*7c478bd9Sstevel@tonic-gate 		}
1312*7c478bd9Sstevel@tonic-gate 	}
1313*7c478bd9Sstevel@tonic-gate 	mutex_exit(&bp->vb_lock);
1314*7c478bd9Sstevel@tonic-gate 	vep = kmem_alloc(sizeof (*vep), KM_SLEEP);
1315*7c478bd9Sstevel@tonic-gate 	rwst_init(&vep->ve_lock, NULL, RW_DEFAULT, NULL);
1316*7c478bd9Sstevel@tonic-gate 	vep->ve_vpvfs = (char *)vfsvpptr;
1317*7c478bd9Sstevel@tonic-gate 	vep->ve_refcnt = 1;
1318*7c478bd9Sstevel@tonic-gate 	mutex_enter(&bp->vb_lock);
1319*7c478bd9Sstevel@tonic-gate 	for (tvep = bp->vb_list; tvep != NULL; tvep = tvep->ve_next) {
1320*7c478bd9Sstevel@tonic-gate 		if (tvep->ve_vpvfs == vfsvpptr) {
1321*7c478bd9Sstevel@tonic-gate 			tvep->ve_refcnt++;
1322*7c478bd9Sstevel@tonic-gate 			mutex_exit(&bp->vb_lock);
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 			/*
1325*7c478bd9Sstevel@tonic-gate 			 * There is already an entry in the hash
1326*7c478bd9Sstevel@tonic-gate 			 * destroy what we just allocated.
1327*7c478bd9Sstevel@tonic-gate 			 */
1328*7c478bd9Sstevel@tonic-gate 			rwst_destroy(&vep->ve_lock);
1329*7c478bd9Sstevel@tonic-gate 			kmem_free(vep, sizeof (*vep));
1330*7c478bd9Sstevel@tonic-gate 			return (tvep);
1331*7c478bd9Sstevel@tonic-gate 		}
1332*7c478bd9Sstevel@tonic-gate 	}
1333*7c478bd9Sstevel@tonic-gate 	vep->ve_next = bp->vb_list;
1334*7c478bd9Sstevel@tonic-gate 	bp->vb_list = vep;
1335*7c478bd9Sstevel@tonic-gate 	mutex_exit(&bp->vb_lock);
1336*7c478bd9Sstevel@tonic-gate 	return (vep);
1337*7c478bd9Sstevel@tonic-gate }
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate void
1340*7c478bd9Sstevel@tonic-gate vn_vfslocks_rele(vn_vfslocks_entry_t *vepent)
1341*7c478bd9Sstevel@tonic-gate {
1342*7c478bd9Sstevel@tonic-gate 	struct vn_vfslocks_bucket *bp;
1343*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vep;
1344*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *pvep;
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate 	ASSERT(vepent != NULL);
1347*7c478bd9Sstevel@tonic-gate 	ASSERT(vepent->ve_vpvfs != NULL);
1348*7c478bd9Sstevel@tonic-gate 
1349*7c478bd9Sstevel@tonic-gate 	bp = &vn_vfslocks_buckets[VN_VFSLOCKS_HASH(vepent->ve_vpvfs)];
1350*7c478bd9Sstevel@tonic-gate 
1351*7c478bd9Sstevel@tonic-gate 	mutex_enter(&bp->vb_lock);
1352*7c478bd9Sstevel@tonic-gate 	vepent->ve_refcnt--;
1353*7c478bd9Sstevel@tonic-gate 
1354*7c478bd9Sstevel@tonic-gate 	if ((int32_t)vepent->ve_refcnt < 0)
1355*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "vn_vfslocks_rele: refcount negative");
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate 	if (vepent->ve_refcnt == 0) {
1358*7c478bd9Sstevel@tonic-gate 		for (vep = bp->vb_list; vep != NULL; vep = vep->ve_next) {
1359*7c478bd9Sstevel@tonic-gate 			if (vep->ve_vpvfs == vepent->ve_vpvfs) {
1360*7c478bd9Sstevel@tonic-gate 				if (bp->vb_list == vep)
1361*7c478bd9Sstevel@tonic-gate 					bp->vb_list = vep->ve_next;
1362*7c478bd9Sstevel@tonic-gate 				else {
1363*7c478bd9Sstevel@tonic-gate 					/* LINTED */
1364*7c478bd9Sstevel@tonic-gate 					pvep->ve_next = vep->ve_next;
1365*7c478bd9Sstevel@tonic-gate 				}
1366*7c478bd9Sstevel@tonic-gate 				mutex_exit(&bp->vb_lock);
1367*7c478bd9Sstevel@tonic-gate 				rwst_destroy(&vep->ve_lock);
1368*7c478bd9Sstevel@tonic-gate 				kmem_free(vep, sizeof (*vep));
1369*7c478bd9Sstevel@tonic-gate 				return;
1370*7c478bd9Sstevel@tonic-gate 			}
1371*7c478bd9Sstevel@tonic-gate 			pvep = vep;
1372*7c478bd9Sstevel@tonic-gate 		}
1373*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "vn_vfslocks_rele: vp/vfs not found");
1374*7c478bd9Sstevel@tonic-gate 	}
1375*7c478bd9Sstevel@tonic-gate 	mutex_exit(&bp->vb_lock);
1376*7c478bd9Sstevel@tonic-gate }
1377*7c478bd9Sstevel@tonic-gate 
1378*7c478bd9Sstevel@tonic-gate /*
1379*7c478bd9Sstevel@tonic-gate  * vn_vfswlock_wait is used to implement a lock which is logically a writers
1380*7c478bd9Sstevel@tonic-gate  * lock protecting the v_vfsmountedhere field.
1381*7c478bd9Sstevel@tonic-gate  * vn_vfswlock_wait has been modified to be similar to vn_vfswlock,
1382*7c478bd9Sstevel@tonic-gate  * except that it blocks to acquire the lock VVFSLOCK.
1383*7c478bd9Sstevel@tonic-gate  *
1384*7c478bd9Sstevel@tonic-gate  * traverse() and routines re-implementing part of traverse (e.g. autofs)
1385*7c478bd9Sstevel@tonic-gate  * need to hold this lock. mount(), vn_rename(), vn_remove() and so on
1386*7c478bd9Sstevel@tonic-gate  * need the non-blocking version of the writers lock i.e. vn_vfswlock
1387*7c478bd9Sstevel@tonic-gate  */
1388*7c478bd9Sstevel@tonic-gate int
1389*7c478bd9Sstevel@tonic-gate vn_vfswlock_wait(vnode_t *vp)
1390*7c478bd9Sstevel@tonic-gate {
1391*7c478bd9Sstevel@tonic-gate 	int retval;
1392*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
1393*7c478bd9Sstevel@tonic-gate 	ASSERT(vp != NULL);
1394*7c478bd9Sstevel@tonic-gate 
1395*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vp);
1396*7c478bd9Sstevel@tonic-gate 	retval = rwst_enter_sig(&vpvfsentry->ve_lock, RW_WRITER);
1397*7c478bd9Sstevel@tonic-gate 
1398*7c478bd9Sstevel@tonic-gate 	if (retval == EINTR) {
1399*7c478bd9Sstevel@tonic-gate 		vn_vfslocks_rele(vpvfsentry);
1400*7c478bd9Sstevel@tonic-gate 		return (EINTR);
1401*7c478bd9Sstevel@tonic-gate 	}
1402*7c478bd9Sstevel@tonic-gate 	return (retval);
1403*7c478bd9Sstevel@tonic-gate }
1404*7c478bd9Sstevel@tonic-gate 
1405*7c478bd9Sstevel@tonic-gate int
1406*7c478bd9Sstevel@tonic-gate vn_vfsrlock_wait(vnode_t *vp)
1407*7c478bd9Sstevel@tonic-gate {
1408*7c478bd9Sstevel@tonic-gate 	int retval;
1409*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
1410*7c478bd9Sstevel@tonic-gate 	ASSERT(vp != NULL);
1411*7c478bd9Sstevel@tonic-gate 
1412*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vp);
1413*7c478bd9Sstevel@tonic-gate 	retval = rwst_enter_sig(&vpvfsentry->ve_lock, RW_READER);
1414*7c478bd9Sstevel@tonic-gate 
1415*7c478bd9Sstevel@tonic-gate 	if (retval == EINTR) {
1416*7c478bd9Sstevel@tonic-gate 		vn_vfslocks_rele(vpvfsentry);
1417*7c478bd9Sstevel@tonic-gate 		return (EINTR);
1418*7c478bd9Sstevel@tonic-gate 	}
1419*7c478bd9Sstevel@tonic-gate 
1420*7c478bd9Sstevel@tonic-gate 	return (retval);
1421*7c478bd9Sstevel@tonic-gate }
1422*7c478bd9Sstevel@tonic-gate 
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate /*
1425*7c478bd9Sstevel@tonic-gate  * vn_vfswlock is used to implement a lock which is logically a writers lock
1426*7c478bd9Sstevel@tonic-gate  * protecting the v_vfsmountedhere field.
1427*7c478bd9Sstevel@tonic-gate  */
1428*7c478bd9Sstevel@tonic-gate int
1429*7c478bd9Sstevel@tonic-gate vn_vfswlock(vnode_t *vp)
1430*7c478bd9Sstevel@tonic-gate {
1431*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
1432*7c478bd9Sstevel@tonic-gate 
1433*7c478bd9Sstevel@tonic-gate 	/*
1434*7c478bd9Sstevel@tonic-gate 	 * If vp is NULL then somebody is trying to lock the covered vnode
1435*7c478bd9Sstevel@tonic-gate 	 * of /.  (vfs_vnodecovered is NULL for /).  This situation will
1436*7c478bd9Sstevel@tonic-gate 	 * only happen when unmounting /.  Since that operation will fail
1437*7c478bd9Sstevel@tonic-gate 	 * anyway, return EBUSY here instead of in VFS_UNMOUNT.
1438*7c478bd9Sstevel@tonic-gate 	 */
1439*7c478bd9Sstevel@tonic-gate 	if (vp == NULL)
1440*7c478bd9Sstevel@tonic-gate 		return (EBUSY);
1441*7c478bd9Sstevel@tonic-gate 
1442*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vp);
1443*7c478bd9Sstevel@tonic-gate 
1444*7c478bd9Sstevel@tonic-gate 	if (rwst_tryenter(&vpvfsentry->ve_lock, RW_WRITER))
1445*7c478bd9Sstevel@tonic-gate 		return (0);
1446*7c478bd9Sstevel@tonic-gate 
1447*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_rele(vpvfsentry);
1448*7c478bd9Sstevel@tonic-gate 	return (EBUSY);
1449*7c478bd9Sstevel@tonic-gate }
1450*7c478bd9Sstevel@tonic-gate 
1451*7c478bd9Sstevel@tonic-gate int
1452*7c478bd9Sstevel@tonic-gate vn_vfsrlock(vnode_t *vp)
1453*7c478bd9Sstevel@tonic-gate {
1454*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
1455*7c478bd9Sstevel@tonic-gate 
1456*7c478bd9Sstevel@tonic-gate 	/*
1457*7c478bd9Sstevel@tonic-gate 	 * If vp is NULL then somebody is trying to lock the covered vnode
1458*7c478bd9Sstevel@tonic-gate 	 * of /.  (vfs_vnodecovered is NULL for /).  This situation will
1459*7c478bd9Sstevel@tonic-gate 	 * only happen when unmounting /.  Since that operation will fail
1460*7c478bd9Sstevel@tonic-gate 	 * anyway, return EBUSY here instead of in VFS_UNMOUNT.
1461*7c478bd9Sstevel@tonic-gate 	 */
1462*7c478bd9Sstevel@tonic-gate 	if (vp == NULL)
1463*7c478bd9Sstevel@tonic-gate 		return (EBUSY);
1464*7c478bd9Sstevel@tonic-gate 
1465*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vp);
1466*7c478bd9Sstevel@tonic-gate 
1467*7c478bd9Sstevel@tonic-gate 	if (rwst_tryenter(&vpvfsentry->ve_lock, RW_READER))
1468*7c478bd9Sstevel@tonic-gate 		return (0);
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_rele(vpvfsentry);
1471*7c478bd9Sstevel@tonic-gate 	return (EBUSY);
1472*7c478bd9Sstevel@tonic-gate }
1473*7c478bd9Sstevel@tonic-gate 
1474*7c478bd9Sstevel@tonic-gate 
1475*7c478bd9Sstevel@tonic-gate /*
1476*7c478bd9Sstevel@tonic-gate  * For compatibility with old (deprecated) interface, continue
1477*7c478bd9Sstevel@tonic-gate  * to support vanilla mutex.
1478*7c478bd9Sstevel@tonic-gate  */
1479*7c478bd9Sstevel@tonic-gate int
1480*7c478bd9Sstevel@tonic-gate vn_vfslock(vnode_t *vp)
1481*7c478bd9Sstevel@tonic-gate {
1482*7c478bd9Sstevel@tonic-gate 	return (vn_vfswlock(vp));
1483*7c478bd9Sstevel@tonic-gate }
1484*7c478bd9Sstevel@tonic-gate 
1485*7c478bd9Sstevel@tonic-gate void
1486*7c478bd9Sstevel@tonic-gate vn_vfsunlock(vnode_t *vp)
1487*7c478bd9Sstevel@tonic-gate {
1488*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
1489*7c478bd9Sstevel@tonic-gate 
1490*7c478bd9Sstevel@tonic-gate 	/*
1491*7c478bd9Sstevel@tonic-gate 	 * ve_refcnt needs to be decremented twice.
1492*7c478bd9Sstevel@tonic-gate 	 * 1. To release refernce after a call to vn_vfslocks_getlock()
1493*7c478bd9Sstevel@tonic-gate 	 * 2. To release the reference from the locking routines like
1494*7c478bd9Sstevel@tonic-gate 	 *    vn_vfsrlock/vn_vfswlock etc,.
1495*7c478bd9Sstevel@tonic-gate 	 */
1496*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vp);
1497*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_rele(vpvfsentry);
1498*7c478bd9Sstevel@tonic-gate 
1499*7c478bd9Sstevel@tonic-gate 	rwst_exit(&vpvfsentry->ve_lock);
1500*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_rele(vpvfsentry);
1501*7c478bd9Sstevel@tonic-gate }
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate int
1504*7c478bd9Sstevel@tonic-gate vn_vfswlock_held(vnode_t *vp)
1505*7c478bd9Sstevel@tonic-gate {
1506*7c478bd9Sstevel@tonic-gate 	int held;
1507*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
1508*7c478bd9Sstevel@tonic-gate 
1509*7c478bd9Sstevel@tonic-gate 	ASSERT(vp != NULL);
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vp);
1512*7c478bd9Sstevel@tonic-gate 	held = rwst_lock_held(&vpvfsentry->ve_lock, RW_WRITER);
1513*7c478bd9Sstevel@tonic-gate 
1514*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_rele(vpvfsentry);
1515*7c478bd9Sstevel@tonic-gate 	return (held);
1516*7c478bd9Sstevel@tonic-gate }
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate 
1519*7c478bd9Sstevel@tonic-gate int
1520*7c478bd9Sstevel@tonic-gate vn_make_ops(
1521*7c478bd9Sstevel@tonic-gate 	const char *name,			/* Name of file system */
1522*7c478bd9Sstevel@tonic-gate 	const fs_operation_def_t *templ,	/* Operation specification */
1523*7c478bd9Sstevel@tonic-gate 	vnodeops_t **actual)			/* Return the vnodeops */
1524*7c478bd9Sstevel@tonic-gate {
1525*7c478bd9Sstevel@tonic-gate 	int unused_ops;
1526*7c478bd9Sstevel@tonic-gate 	int error;
1527*7c478bd9Sstevel@tonic-gate 
1528*7c478bd9Sstevel@tonic-gate 	*actual = (vnodeops_t *)kmem_alloc(sizeof (vnodeops_t), KM_SLEEP);
1529*7c478bd9Sstevel@tonic-gate 
1530*7c478bd9Sstevel@tonic-gate 	(*actual)->vnop_name = name;
1531*7c478bd9Sstevel@tonic-gate 
1532*7c478bd9Sstevel@tonic-gate 	error = fs_build_vector(*actual, &unused_ops, vn_ops_table, templ);
1533*7c478bd9Sstevel@tonic-gate 	if (error) {
1534*7c478bd9Sstevel@tonic-gate 		kmem_free(*actual, sizeof (vnodeops_t));
1535*7c478bd9Sstevel@tonic-gate 	}
1536*7c478bd9Sstevel@tonic-gate 
1537*7c478bd9Sstevel@tonic-gate #if DEBUG
1538*7c478bd9Sstevel@tonic-gate 	if (unused_ops != 0)
1539*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "vn_make_ops: %s: %d operations supplied "
1540*7c478bd9Sstevel@tonic-gate 		    "but not used", name, unused_ops);
1541*7c478bd9Sstevel@tonic-gate #endif
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 	return (error);
1544*7c478bd9Sstevel@tonic-gate }
1545*7c478bd9Sstevel@tonic-gate 
1546*7c478bd9Sstevel@tonic-gate /*
1547*7c478bd9Sstevel@tonic-gate  * Free the vnodeops created as a result of vn_make_ops()
1548*7c478bd9Sstevel@tonic-gate  */
1549*7c478bd9Sstevel@tonic-gate void
1550*7c478bd9Sstevel@tonic-gate vn_freevnodeops(vnodeops_t *vnops)
1551*7c478bd9Sstevel@tonic-gate {
1552*7c478bd9Sstevel@tonic-gate 	kmem_free(vnops, sizeof (vnodeops_t));
1553*7c478bd9Sstevel@tonic-gate }
1554*7c478bd9Sstevel@tonic-gate 
1555*7c478bd9Sstevel@tonic-gate /*
1556*7c478bd9Sstevel@tonic-gate  * Vnode cache.
1557*7c478bd9Sstevel@tonic-gate  */
1558*7c478bd9Sstevel@tonic-gate 
1559*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1560*7c478bd9Sstevel@tonic-gate static int
1561*7c478bd9Sstevel@tonic-gate vn_cache_constructor(void *buf, void *cdrarg, int kmflags)
1562*7c478bd9Sstevel@tonic-gate {
1563*7c478bd9Sstevel@tonic-gate 	struct vnode *vp;
1564*7c478bd9Sstevel@tonic-gate 
1565*7c478bd9Sstevel@tonic-gate 	vp = buf;
1566*7c478bd9Sstevel@tonic-gate 
1567*7c478bd9Sstevel@tonic-gate 	mutex_init(&vp->v_lock, NULL, MUTEX_DEFAULT, NULL);
1568*7c478bd9Sstevel@tonic-gate 	cv_init(&vp->v_cv, NULL, CV_DEFAULT, NULL);
1569*7c478bd9Sstevel@tonic-gate 	rw_init(&vp->v_nbllock, NULL, RW_DEFAULT, NULL);
1570*7c478bd9Sstevel@tonic-gate 	rw_init(&vp->v_mslock, NULL, RW_DEFAULT, NULL);
1571*7c478bd9Sstevel@tonic-gate 
1572*7c478bd9Sstevel@tonic-gate 	vp->v_femhead = NULL;	/* Must be done before vn_reinit() */
1573*7c478bd9Sstevel@tonic-gate 	vp->v_path = NULL;
1574*7c478bd9Sstevel@tonic-gate 	vp->v_mpssdata = NULL;
1575*7c478bd9Sstevel@tonic-gate 
1576*7c478bd9Sstevel@tonic-gate 	return (0);
1577*7c478bd9Sstevel@tonic-gate }
1578*7c478bd9Sstevel@tonic-gate 
1579*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1580*7c478bd9Sstevel@tonic-gate static void
1581*7c478bd9Sstevel@tonic-gate vn_cache_destructor(void *buf, void *cdrarg)
1582*7c478bd9Sstevel@tonic-gate {
1583*7c478bd9Sstevel@tonic-gate 	struct vnode *vp;
1584*7c478bd9Sstevel@tonic-gate 
1585*7c478bd9Sstevel@tonic-gate 	vp = buf;
1586*7c478bd9Sstevel@tonic-gate 
1587*7c478bd9Sstevel@tonic-gate 	rw_destroy(&vp->v_mslock);
1588*7c478bd9Sstevel@tonic-gate 	rw_destroy(&vp->v_nbllock);
1589*7c478bd9Sstevel@tonic-gate 	cv_destroy(&vp->v_cv);
1590*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&vp->v_lock);
1591*7c478bd9Sstevel@tonic-gate }
1592*7c478bd9Sstevel@tonic-gate 
1593*7c478bd9Sstevel@tonic-gate void
1594*7c478bd9Sstevel@tonic-gate vn_create_cache(void)
1595*7c478bd9Sstevel@tonic-gate {
1596*7c478bd9Sstevel@tonic-gate 	vn_cache = kmem_cache_create("vn_cache", sizeof (struct vnode), 64,
1597*7c478bd9Sstevel@tonic-gate 	    vn_cache_constructor, vn_cache_destructor, NULL, NULL,
1598*7c478bd9Sstevel@tonic-gate 	    NULL, 0);
1599*7c478bd9Sstevel@tonic-gate }
1600*7c478bd9Sstevel@tonic-gate 
1601*7c478bd9Sstevel@tonic-gate void
1602*7c478bd9Sstevel@tonic-gate vn_destroy_cache(void)
1603*7c478bd9Sstevel@tonic-gate {
1604*7c478bd9Sstevel@tonic-gate 	kmem_cache_destroy(vn_cache);
1605*7c478bd9Sstevel@tonic-gate }
1606*7c478bd9Sstevel@tonic-gate 
1607*7c478bd9Sstevel@tonic-gate /*
1608*7c478bd9Sstevel@tonic-gate  * Used by file systems when fs-specific nodes (e.g., ufs inodes) are
1609*7c478bd9Sstevel@tonic-gate  * cached by the file system and vnodes remain associated.
1610*7c478bd9Sstevel@tonic-gate  */
1611*7c478bd9Sstevel@tonic-gate void
1612*7c478bd9Sstevel@tonic-gate vn_recycle(vnode_t *vp)
1613*7c478bd9Sstevel@tonic-gate {
1614*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_pages == NULL);
1615*7c478bd9Sstevel@tonic-gate 
1616*7c478bd9Sstevel@tonic-gate 	/*
1617*7c478bd9Sstevel@tonic-gate 	 * XXX - This really belongs in vn_reinit(), but we have some issues
1618*7c478bd9Sstevel@tonic-gate 	 * with the counts.  Best to have it here for clean initialization.
1619*7c478bd9Sstevel@tonic-gate 	 */
1620*7c478bd9Sstevel@tonic-gate 	vp->v_rdcnt = 0;
1621*7c478bd9Sstevel@tonic-gate 	vp->v_wrcnt = 0;
1622*7c478bd9Sstevel@tonic-gate 	vp->v_mmap_read = 0;
1623*7c478bd9Sstevel@tonic-gate 	vp->v_mmap_write = 0;
1624*7c478bd9Sstevel@tonic-gate 
1625*7c478bd9Sstevel@tonic-gate 	/*
1626*7c478bd9Sstevel@tonic-gate 	 * If FEM was in use, make sure everything gets cleaned up
1627*7c478bd9Sstevel@tonic-gate 	 * NOTE: vp->v_femhead is initialized to NULL in the vnode
1628*7c478bd9Sstevel@tonic-gate 	 * constructor.
1629*7c478bd9Sstevel@tonic-gate 	 */
1630*7c478bd9Sstevel@tonic-gate 	if (vp->v_femhead) {
1631*7c478bd9Sstevel@tonic-gate 		/* XXX - There should be a free_femhead() that does all this */
1632*7c478bd9Sstevel@tonic-gate 		ASSERT(vp->v_femhead->femh_list == NULL);
1633*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&vp->v_femhead->femh_lock);
1634*7c478bd9Sstevel@tonic-gate 		kmem_free(vp->v_femhead, sizeof (*(vp->v_femhead)));
1635*7c478bd9Sstevel@tonic-gate 		vp->v_femhead = NULL;
1636*7c478bd9Sstevel@tonic-gate 	}
1637*7c478bd9Sstevel@tonic-gate 	if (vp->v_path) {
1638*7c478bd9Sstevel@tonic-gate 		kmem_free(vp->v_path, strlen(vp->v_path) + 1);
1639*7c478bd9Sstevel@tonic-gate 		vp->v_path = NULL;
1640*7c478bd9Sstevel@tonic-gate 	}
1641*7c478bd9Sstevel@tonic-gate 	vp->v_mpssdata = NULL;
1642*7c478bd9Sstevel@tonic-gate }
1643*7c478bd9Sstevel@tonic-gate 
1644*7c478bd9Sstevel@tonic-gate /*
1645*7c478bd9Sstevel@tonic-gate  * Used to reset the vnode fields including those that are directly accessible
1646*7c478bd9Sstevel@tonic-gate  * as well as those which require an accessor function.
1647*7c478bd9Sstevel@tonic-gate  *
1648*7c478bd9Sstevel@tonic-gate  * Does not initialize:
1649*7c478bd9Sstevel@tonic-gate  *	synchronization objects: v_lock, v_nbllock, v_cv
1650*7c478bd9Sstevel@tonic-gate  *	v_data (since FS-nodes and vnodes point to each other and should
1651*7c478bd9Sstevel@tonic-gate  *		be updated simultaneously)
1652*7c478bd9Sstevel@tonic-gate  *	v_op (in case someone needs to make a VOP call on this object)
1653*7c478bd9Sstevel@tonic-gate  */
1654*7c478bd9Sstevel@tonic-gate void
1655*7c478bd9Sstevel@tonic-gate vn_reinit(vnode_t *vp)
1656*7c478bd9Sstevel@tonic-gate {
1657*7c478bd9Sstevel@tonic-gate 	vp->v_count = 1;
1658*7c478bd9Sstevel@tonic-gate 	vp->v_vfsp = NULL;
1659*7c478bd9Sstevel@tonic-gate 	vp->v_stream = NULL;
1660*7c478bd9Sstevel@tonic-gate 	vp->v_vfsmountedhere = NULL;
1661*7c478bd9Sstevel@tonic-gate 	vp->v_flag = 0;
1662*7c478bd9Sstevel@tonic-gate 	vp->v_type = VNON;
1663*7c478bd9Sstevel@tonic-gate 	vp->v_rdev = NODEV;
1664*7c478bd9Sstevel@tonic-gate 
1665*7c478bd9Sstevel@tonic-gate 	vp->v_filocks = NULL;
1666*7c478bd9Sstevel@tonic-gate 	vp->v_shrlocks = NULL;
1667*7c478bd9Sstevel@tonic-gate 	vp->v_pages = NULL;
1668*7c478bd9Sstevel@tonic-gate 	vp->v_npages = 0;
1669*7c478bd9Sstevel@tonic-gate 	vp->v_msnpages = 0;
1670*7c478bd9Sstevel@tonic-gate 	vp->v_scanfront = NULL;
1671*7c478bd9Sstevel@tonic-gate 	vp->v_scanback = NULL;
1672*7c478bd9Sstevel@tonic-gate 
1673*7c478bd9Sstevel@tonic-gate 	vp->v_locality = NULL;
1674*7c478bd9Sstevel@tonic-gate 	vp->v_scantime = 0;
1675*7c478bd9Sstevel@tonic-gate 	vp->v_mset = 0;
1676*7c478bd9Sstevel@tonic-gate 	vp->v_msflags = 0;
1677*7c478bd9Sstevel@tonic-gate 	vp->v_msnext = NULL;
1678*7c478bd9Sstevel@tonic-gate 	vp->v_msprev = NULL;
1679*7c478bd9Sstevel@tonic-gate 
1680*7c478bd9Sstevel@tonic-gate 	/* Handles v_femhead, v_path, and the r/w/map counts */
1681*7c478bd9Sstevel@tonic-gate 	vn_recycle(vp);
1682*7c478bd9Sstevel@tonic-gate }
1683*7c478bd9Sstevel@tonic-gate 
1684*7c478bd9Sstevel@tonic-gate vnode_t *
1685*7c478bd9Sstevel@tonic-gate vn_alloc(int kmflag)
1686*7c478bd9Sstevel@tonic-gate {
1687*7c478bd9Sstevel@tonic-gate 	vnode_t *vp;
1688*7c478bd9Sstevel@tonic-gate 
1689*7c478bd9Sstevel@tonic-gate 	vp = kmem_cache_alloc(vn_cache, kmflag);
1690*7c478bd9Sstevel@tonic-gate 
1691*7c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
1692*7c478bd9Sstevel@tonic-gate 		vp->v_femhead = NULL;	/* Must be done before vn_reinit() */
1693*7c478bd9Sstevel@tonic-gate 		vn_reinit(vp);
1694*7c478bd9Sstevel@tonic-gate 	}
1695*7c478bd9Sstevel@tonic-gate 
1696*7c478bd9Sstevel@tonic-gate 	return (vp);
1697*7c478bd9Sstevel@tonic-gate }
1698*7c478bd9Sstevel@tonic-gate 
1699*7c478bd9Sstevel@tonic-gate void
1700*7c478bd9Sstevel@tonic-gate vn_free(vnode_t *vp)
1701*7c478bd9Sstevel@tonic-gate {
1702*7c478bd9Sstevel@tonic-gate 	/*
1703*7c478bd9Sstevel@tonic-gate 	 * Some file systems call vn_free() with v_count of zero,
1704*7c478bd9Sstevel@tonic-gate 	 * some with v_count of 1.  In any case, the value should
1705*7c478bd9Sstevel@tonic-gate 	 * never be anything else.
1706*7c478bd9Sstevel@tonic-gate 	 */
1707*7c478bd9Sstevel@tonic-gate 	ASSERT((vp->v_count == 0) || (vp->v_count == 1));
1708*7c478bd9Sstevel@tonic-gate 	if (vp->v_path != NULL) {
1709*7c478bd9Sstevel@tonic-gate 		kmem_free(vp->v_path, strlen(vp->v_path) + 1);
1710*7c478bd9Sstevel@tonic-gate 		vp->v_path = NULL;
1711*7c478bd9Sstevel@tonic-gate 	}
1712*7c478bd9Sstevel@tonic-gate 
1713*7c478bd9Sstevel@tonic-gate 	/* If FEM was in use, make sure everything gets cleaned up */
1714*7c478bd9Sstevel@tonic-gate 	if (vp->v_femhead) {
1715*7c478bd9Sstevel@tonic-gate 		/* XXX - There should be a free_femhead() that does all this */
1716*7c478bd9Sstevel@tonic-gate 		ASSERT(vp->v_femhead->femh_list == NULL);
1717*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&vp->v_femhead->femh_lock);
1718*7c478bd9Sstevel@tonic-gate 		kmem_free(vp->v_femhead, sizeof (*(vp->v_femhead)));
1719*7c478bd9Sstevel@tonic-gate 		vp->v_femhead = NULL;
1720*7c478bd9Sstevel@tonic-gate 	}
1721*7c478bd9Sstevel@tonic-gate 	vp->v_mpssdata = NULL;
1722*7c478bd9Sstevel@tonic-gate 	kmem_cache_free(vn_cache, vp);
1723*7c478bd9Sstevel@tonic-gate }
1724*7c478bd9Sstevel@tonic-gate 
1725*7c478bd9Sstevel@tonic-gate /*
1726*7c478bd9Sstevel@tonic-gate  * vnode status changes, should define better states than 1, 0.
1727*7c478bd9Sstevel@tonic-gate  */
1728*7c478bd9Sstevel@tonic-gate void
1729*7c478bd9Sstevel@tonic-gate vn_reclaim(vnode_t *vp)
1730*7c478bd9Sstevel@tonic-gate {
1731*7c478bd9Sstevel@tonic-gate 	vfs_t   *vfsp = vp->v_vfsp;
1732*7c478bd9Sstevel@tonic-gate 
1733*7c478bd9Sstevel@tonic-gate 	if (vfsp == NULL || vfsp->vfs_femhead == NULL) {
1734*7c478bd9Sstevel@tonic-gate 		return;
1735*7c478bd9Sstevel@tonic-gate 	}
1736*7c478bd9Sstevel@tonic-gate 	(void) VFS_VNSTATE(vfsp, vp, VNTRANS_RECLAIMED);
1737*7c478bd9Sstevel@tonic-gate }
1738*7c478bd9Sstevel@tonic-gate 
1739*7c478bd9Sstevel@tonic-gate void
1740*7c478bd9Sstevel@tonic-gate vn_idle(vnode_t *vp)
1741*7c478bd9Sstevel@tonic-gate {
1742*7c478bd9Sstevel@tonic-gate 	vfs_t   *vfsp = vp->v_vfsp;
1743*7c478bd9Sstevel@tonic-gate 
1744*7c478bd9Sstevel@tonic-gate 	if (vfsp == NULL || vfsp->vfs_femhead == NULL) {
1745*7c478bd9Sstevel@tonic-gate 		return;
1746*7c478bd9Sstevel@tonic-gate 	}
1747*7c478bd9Sstevel@tonic-gate 	(void) VFS_VNSTATE(vfsp, vp, VNTRANS_IDLED);
1748*7c478bd9Sstevel@tonic-gate }
1749*7c478bd9Sstevel@tonic-gate void
1750*7c478bd9Sstevel@tonic-gate vn_exists(vnode_t *vp)
1751*7c478bd9Sstevel@tonic-gate {
1752*7c478bd9Sstevel@tonic-gate 	vfs_t   *vfsp = vp->v_vfsp;
1753*7c478bd9Sstevel@tonic-gate 
1754*7c478bd9Sstevel@tonic-gate 	if (vfsp == NULL || vfsp->vfs_femhead == NULL) {
1755*7c478bd9Sstevel@tonic-gate 		return;
1756*7c478bd9Sstevel@tonic-gate 	}
1757*7c478bd9Sstevel@tonic-gate 	(void) VFS_VNSTATE(vfsp, vp, VNTRANS_EXISTS);
1758*7c478bd9Sstevel@tonic-gate }
1759*7c478bd9Sstevel@tonic-gate 
1760*7c478bd9Sstevel@tonic-gate void
1761*7c478bd9Sstevel@tonic-gate vn_invalid(vnode_t *vp)
1762*7c478bd9Sstevel@tonic-gate {
1763*7c478bd9Sstevel@tonic-gate 	vfs_t   *vfsp = vp->v_vfsp;
1764*7c478bd9Sstevel@tonic-gate 
1765*7c478bd9Sstevel@tonic-gate 	if (vfsp == NULL || vfsp->vfs_femhead == NULL) {
1766*7c478bd9Sstevel@tonic-gate 		return;
1767*7c478bd9Sstevel@tonic-gate 	}
1768*7c478bd9Sstevel@tonic-gate 	(void) VFS_VNSTATE(vfsp, vp, VNTRANS_DESTROYED);
1769*7c478bd9Sstevel@tonic-gate }
1770*7c478bd9Sstevel@tonic-gate 
1771*7c478bd9Sstevel@tonic-gate /* Vnode event notification */
1772*7c478bd9Sstevel@tonic-gate 
1773*7c478bd9Sstevel@tonic-gate int
1774*7c478bd9Sstevel@tonic-gate vnevent_support(vnode_t *vp)
1775*7c478bd9Sstevel@tonic-gate {
1776*7c478bd9Sstevel@tonic-gate 	if (vp == NULL)
1777*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1778*7c478bd9Sstevel@tonic-gate 
1779*7c478bd9Sstevel@tonic-gate 	return (VOP_VNEVENT(vp, VE_SUPPORT));
1780*7c478bd9Sstevel@tonic-gate }
1781*7c478bd9Sstevel@tonic-gate 
1782*7c478bd9Sstevel@tonic-gate void
1783*7c478bd9Sstevel@tonic-gate vnevent_rename_src(vnode_t *vp)
1784*7c478bd9Sstevel@tonic-gate {
1785*7c478bd9Sstevel@tonic-gate 	if (vp == NULL || vp->v_femhead == NULL) {
1786*7c478bd9Sstevel@tonic-gate 		return;
1787*7c478bd9Sstevel@tonic-gate 	}
1788*7c478bd9Sstevel@tonic-gate 	(void) VOP_VNEVENT(vp, VE_RENAME_SRC);
1789*7c478bd9Sstevel@tonic-gate }
1790*7c478bd9Sstevel@tonic-gate 
1791*7c478bd9Sstevel@tonic-gate void
1792*7c478bd9Sstevel@tonic-gate vnevent_rename_dest(vnode_t *vp)
1793*7c478bd9Sstevel@tonic-gate {
1794*7c478bd9Sstevel@tonic-gate 	if (vp == NULL || vp->v_femhead == NULL) {
1795*7c478bd9Sstevel@tonic-gate 		return;
1796*7c478bd9Sstevel@tonic-gate 	}
1797*7c478bd9Sstevel@tonic-gate 	(void) VOP_VNEVENT(vp, VE_RENAME_DEST);
1798*7c478bd9Sstevel@tonic-gate }
1799*7c478bd9Sstevel@tonic-gate 
1800*7c478bd9Sstevel@tonic-gate void
1801*7c478bd9Sstevel@tonic-gate vnevent_remove(vnode_t *vp)
1802*7c478bd9Sstevel@tonic-gate {
1803*7c478bd9Sstevel@tonic-gate 	if (vp == NULL || vp->v_femhead == NULL) {
1804*7c478bd9Sstevel@tonic-gate 		return;
1805*7c478bd9Sstevel@tonic-gate 	}
1806*7c478bd9Sstevel@tonic-gate 	(void) VOP_VNEVENT(vp, VE_REMOVE);
1807*7c478bd9Sstevel@tonic-gate }
1808*7c478bd9Sstevel@tonic-gate 
1809*7c478bd9Sstevel@tonic-gate void
1810*7c478bd9Sstevel@tonic-gate vnevent_rmdir(vnode_t *vp)
1811*7c478bd9Sstevel@tonic-gate {
1812*7c478bd9Sstevel@tonic-gate 	if (vp == NULL || vp->v_femhead == NULL) {
1813*7c478bd9Sstevel@tonic-gate 		return;
1814*7c478bd9Sstevel@tonic-gate 	}
1815*7c478bd9Sstevel@tonic-gate 	(void) VOP_VNEVENT(vp, VE_RMDIR);
1816*7c478bd9Sstevel@tonic-gate }
1817*7c478bd9Sstevel@tonic-gate 
1818*7c478bd9Sstevel@tonic-gate /*
1819*7c478bd9Sstevel@tonic-gate  * Vnode accessors.
1820*7c478bd9Sstevel@tonic-gate  */
1821*7c478bd9Sstevel@tonic-gate 
1822*7c478bd9Sstevel@tonic-gate int
1823*7c478bd9Sstevel@tonic-gate vn_is_readonly(vnode_t *vp)
1824*7c478bd9Sstevel@tonic-gate {
1825*7c478bd9Sstevel@tonic-gate 	return (vp->v_vfsp->vfs_flag & VFS_RDONLY);
1826*7c478bd9Sstevel@tonic-gate }
1827*7c478bd9Sstevel@tonic-gate 
1828*7c478bd9Sstevel@tonic-gate int
1829*7c478bd9Sstevel@tonic-gate vn_has_flocks(vnode_t *vp)
1830*7c478bd9Sstevel@tonic-gate {
1831*7c478bd9Sstevel@tonic-gate 	return (vp->v_filocks != NULL);
1832*7c478bd9Sstevel@tonic-gate }
1833*7c478bd9Sstevel@tonic-gate 
1834*7c478bd9Sstevel@tonic-gate int
1835*7c478bd9Sstevel@tonic-gate vn_has_mandatory_locks(vnode_t *vp, int mode)
1836*7c478bd9Sstevel@tonic-gate {
1837*7c478bd9Sstevel@tonic-gate 	return ((vp->v_filocks != NULL) && (MANDLOCK(vp, mode)));
1838*7c478bd9Sstevel@tonic-gate }
1839*7c478bd9Sstevel@tonic-gate 
1840*7c478bd9Sstevel@tonic-gate int
1841*7c478bd9Sstevel@tonic-gate vn_has_cached_data(vnode_t *vp)
1842*7c478bd9Sstevel@tonic-gate {
1843*7c478bd9Sstevel@tonic-gate 	return (vp->v_pages != NULL);
1844*7c478bd9Sstevel@tonic-gate }
1845*7c478bd9Sstevel@tonic-gate 
1846*7c478bd9Sstevel@tonic-gate /*
1847*7c478bd9Sstevel@tonic-gate  * Return 0 if the vnode in question shouldn't be permitted into a zone via
1848*7c478bd9Sstevel@tonic-gate  * zone_enter(2).
1849*7c478bd9Sstevel@tonic-gate  */
1850*7c478bd9Sstevel@tonic-gate int
1851*7c478bd9Sstevel@tonic-gate vn_can_change_zones(vnode_t *vp)
1852*7c478bd9Sstevel@tonic-gate {
1853*7c478bd9Sstevel@tonic-gate 	struct vfssw *vswp;
1854*7c478bd9Sstevel@tonic-gate 	int allow = 1;
1855*7c478bd9Sstevel@tonic-gate 	vnode_t *rvp;
1856*7c478bd9Sstevel@tonic-gate 
1857*7c478bd9Sstevel@tonic-gate 	/*
1858*7c478bd9Sstevel@tonic-gate 	 * We always want to look at the underlying vnode if there is one.
1859*7c478bd9Sstevel@tonic-gate 	 */
1860*7c478bd9Sstevel@tonic-gate 	if (VOP_REALVP(vp, &rvp) != 0)
1861*7c478bd9Sstevel@tonic-gate 		rvp = vp;
1862*7c478bd9Sstevel@tonic-gate 	/*
1863*7c478bd9Sstevel@tonic-gate 	 * Some pseudo filesystems (including doorfs) don't actually register
1864*7c478bd9Sstevel@tonic-gate 	 * their vfsops_t, so the following may return NULL; we happily let
1865*7c478bd9Sstevel@tonic-gate 	 * such vnodes switch zones.
1866*7c478bd9Sstevel@tonic-gate 	 */
1867*7c478bd9Sstevel@tonic-gate 	vswp = vfs_getvfsswbyvfsops(vfs_getops(rvp->v_vfsp));
1868*7c478bd9Sstevel@tonic-gate 	if (vswp != NULL) {
1869*7c478bd9Sstevel@tonic-gate 		if (vswp->vsw_flag & VSW_NOTZONESAFE)
1870*7c478bd9Sstevel@tonic-gate 			allow = 0;
1871*7c478bd9Sstevel@tonic-gate 		vfs_unrefvfssw(vswp);
1872*7c478bd9Sstevel@tonic-gate 	}
1873*7c478bd9Sstevel@tonic-gate 	return (allow);
1874*7c478bd9Sstevel@tonic-gate }
1875*7c478bd9Sstevel@tonic-gate 
1876*7c478bd9Sstevel@tonic-gate /*
1877*7c478bd9Sstevel@tonic-gate  * Return nonzero if the vnode is a mount point, zero if not.
1878*7c478bd9Sstevel@tonic-gate  */
1879*7c478bd9Sstevel@tonic-gate int
1880*7c478bd9Sstevel@tonic-gate vn_ismntpt(vnode_t *vp)
1881*7c478bd9Sstevel@tonic-gate {
1882*7c478bd9Sstevel@tonic-gate 	return (vp->v_vfsmountedhere != NULL);
1883*7c478bd9Sstevel@tonic-gate }
1884*7c478bd9Sstevel@tonic-gate 
1885*7c478bd9Sstevel@tonic-gate /* Retrieve the vfs (if any) mounted on this vnode */
1886*7c478bd9Sstevel@tonic-gate vfs_t *
1887*7c478bd9Sstevel@tonic-gate vn_mountedvfs(vnode_t *vp)
1888*7c478bd9Sstevel@tonic-gate {
1889*7c478bd9Sstevel@tonic-gate 	return (vp->v_vfsmountedhere);
1890*7c478bd9Sstevel@tonic-gate }
1891*7c478bd9Sstevel@tonic-gate 
1892*7c478bd9Sstevel@tonic-gate /*
1893*7c478bd9Sstevel@tonic-gate  * vn_is_opened() checks whether a particular file is opened and
1894*7c478bd9Sstevel@tonic-gate  * whether the open is for read and/or write.
1895*7c478bd9Sstevel@tonic-gate  *
1896*7c478bd9Sstevel@tonic-gate  * Vnode counts are only kept on regular files (v_type=VREG).
1897*7c478bd9Sstevel@tonic-gate  */
1898*7c478bd9Sstevel@tonic-gate int
1899*7c478bd9Sstevel@tonic-gate vn_is_opened(
1900*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
1901*7c478bd9Sstevel@tonic-gate 	v_mode_t mode)
1902*7c478bd9Sstevel@tonic-gate {
1903*7c478bd9Sstevel@tonic-gate 
1904*7c478bd9Sstevel@tonic-gate 	ASSERT(vp != NULL);
1905*7c478bd9Sstevel@tonic-gate 
1906*7c478bd9Sstevel@tonic-gate 	switch (mode) {
1907*7c478bd9Sstevel@tonic-gate 	case V_WRITE:
1908*7c478bd9Sstevel@tonic-gate 		if (vp->v_wrcnt)
1909*7c478bd9Sstevel@tonic-gate 			return (V_TRUE);
1910*7c478bd9Sstevel@tonic-gate 		break;
1911*7c478bd9Sstevel@tonic-gate 	case V_RDANDWR:
1912*7c478bd9Sstevel@tonic-gate 		if (vp->v_rdcnt && vp->v_wrcnt)
1913*7c478bd9Sstevel@tonic-gate 			return (V_TRUE);
1914*7c478bd9Sstevel@tonic-gate 		break;
1915*7c478bd9Sstevel@tonic-gate 	case V_RDORWR:
1916*7c478bd9Sstevel@tonic-gate 		if (vp->v_rdcnt || vp->v_wrcnt)
1917*7c478bd9Sstevel@tonic-gate 			return (V_TRUE);
1918*7c478bd9Sstevel@tonic-gate 		break;
1919*7c478bd9Sstevel@tonic-gate 	case V_READ:
1920*7c478bd9Sstevel@tonic-gate 		if (vp->v_rdcnt)
1921*7c478bd9Sstevel@tonic-gate 			return (V_TRUE);
1922*7c478bd9Sstevel@tonic-gate 		break;
1923*7c478bd9Sstevel@tonic-gate 	}
1924*7c478bd9Sstevel@tonic-gate 
1925*7c478bd9Sstevel@tonic-gate 	return (V_FALSE);
1926*7c478bd9Sstevel@tonic-gate }
1927*7c478bd9Sstevel@tonic-gate 
1928*7c478bd9Sstevel@tonic-gate /*
1929*7c478bd9Sstevel@tonic-gate  * vn_is_mapped() checks whether a particular file is mapped and whether
1930*7c478bd9Sstevel@tonic-gate  * the file is mapped read and/or write.
1931*7c478bd9Sstevel@tonic-gate  */
1932*7c478bd9Sstevel@tonic-gate int
1933*7c478bd9Sstevel@tonic-gate vn_is_mapped(
1934*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
1935*7c478bd9Sstevel@tonic-gate 	v_mode_t mode)
1936*7c478bd9Sstevel@tonic-gate {
1937*7c478bd9Sstevel@tonic-gate 
1938*7c478bd9Sstevel@tonic-gate 	ASSERT(vp != NULL);
1939*7c478bd9Sstevel@tonic-gate 
1940*7c478bd9Sstevel@tonic-gate #if !defined(_LP64)
1941*7c478bd9Sstevel@tonic-gate 	switch (mode) {
1942*7c478bd9Sstevel@tonic-gate 	/*
1943*7c478bd9Sstevel@tonic-gate 	 * The atomic_add_64_nv functions force atomicity in the
1944*7c478bd9Sstevel@tonic-gate 	 * case of 32 bit architectures. Otherwise the 64 bit values
1945*7c478bd9Sstevel@tonic-gate 	 * require two fetches. The value of the fields may be
1946*7c478bd9Sstevel@tonic-gate 	 * (potentially) changed between the first fetch and the
1947*7c478bd9Sstevel@tonic-gate 	 * second
1948*7c478bd9Sstevel@tonic-gate 	 */
1949*7c478bd9Sstevel@tonic-gate 	case V_WRITE:
1950*7c478bd9Sstevel@tonic-gate 		if (atomic_add_64_nv((&(vp->v_mmap_write)), 0))
1951*7c478bd9Sstevel@tonic-gate 			return (V_TRUE);
1952*7c478bd9Sstevel@tonic-gate 		break;
1953*7c478bd9Sstevel@tonic-gate 	case V_RDANDWR:
1954*7c478bd9Sstevel@tonic-gate 		if ((atomic_add_64_nv((&(vp->v_mmap_read)), 0)) &&
1955*7c478bd9Sstevel@tonic-gate 		    (atomic_add_64_nv((&(vp->v_mmap_write)), 0)))
1956*7c478bd9Sstevel@tonic-gate 			return (V_TRUE);
1957*7c478bd9Sstevel@tonic-gate 		break;
1958*7c478bd9Sstevel@tonic-gate 	case V_RDORWR:
1959*7c478bd9Sstevel@tonic-gate 		if ((atomic_add_64_nv((&(vp->v_mmap_read)), 0)) ||
1960*7c478bd9Sstevel@tonic-gate 		    (atomic_add_64_nv((&(vp->v_mmap_write)), 0)))
1961*7c478bd9Sstevel@tonic-gate 			return (V_TRUE);
1962*7c478bd9Sstevel@tonic-gate 		break;
1963*7c478bd9Sstevel@tonic-gate 	case V_READ:
1964*7c478bd9Sstevel@tonic-gate 		if (atomic_add_64_nv((&(vp->v_mmap_read)), 0))
1965*7c478bd9Sstevel@tonic-gate 			return (V_TRUE);
1966*7c478bd9Sstevel@tonic-gate 		break;
1967*7c478bd9Sstevel@tonic-gate 	}
1968*7c478bd9Sstevel@tonic-gate #else
1969*7c478bd9Sstevel@tonic-gate 	switch (mode) {
1970*7c478bd9Sstevel@tonic-gate 	case V_WRITE:
1971*7c478bd9Sstevel@tonic-gate 		if (vp->v_mmap_write)
1972*7c478bd9Sstevel@tonic-gate 			return (V_TRUE);
1973*7c478bd9Sstevel@tonic-gate 		break;
1974*7c478bd9Sstevel@tonic-gate 	case V_RDANDWR:
1975*7c478bd9Sstevel@tonic-gate 		if (vp->v_mmap_read && vp->v_mmap_write)
1976*7c478bd9Sstevel@tonic-gate 			return (V_TRUE);
1977*7c478bd9Sstevel@tonic-gate 		break;
1978*7c478bd9Sstevel@tonic-gate 	case V_RDORWR:
1979*7c478bd9Sstevel@tonic-gate 		if (vp->v_mmap_read || vp->v_mmap_write)
1980*7c478bd9Sstevel@tonic-gate 			return (V_TRUE);
1981*7c478bd9Sstevel@tonic-gate 		break;
1982*7c478bd9Sstevel@tonic-gate 	case V_READ:
1983*7c478bd9Sstevel@tonic-gate 		if (vp->v_mmap_read)
1984*7c478bd9Sstevel@tonic-gate 			return (V_TRUE);
1985*7c478bd9Sstevel@tonic-gate 		break;
1986*7c478bd9Sstevel@tonic-gate 	}
1987*7c478bd9Sstevel@tonic-gate #endif
1988*7c478bd9Sstevel@tonic-gate 
1989*7c478bd9Sstevel@tonic-gate 	return (V_FALSE);
1990*7c478bd9Sstevel@tonic-gate }
1991*7c478bd9Sstevel@tonic-gate 
1992*7c478bd9Sstevel@tonic-gate /*
1993*7c478bd9Sstevel@tonic-gate  * Set the operations vector for a vnode.
1994*7c478bd9Sstevel@tonic-gate  *
1995*7c478bd9Sstevel@tonic-gate  * FEM ensures that the v_femhead pointer is filled in before the
1996*7c478bd9Sstevel@tonic-gate  * v_op pointer is changed.  This means that if the v_femhead pointer
1997*7c478bd9Sstevel@tonic-gate  * is NULL, and the v_op field hasn't changed since before which checked
1998*7c478bd9Sstevel@tonic-gate  * the v_femhead pointer; then our update is ok - we are not racing with
1999*7c478bd9Sstevel@tonic-gate  * FEM.
2000*7c478bd9Sstevel@tonic-gate  */
2001*7c478bd9Sstevel@tonic-gate void
2002*7c478bd9Sstevel@tonic-gate vn_setops(vnode_t *vp, vnodeops_t *vnodeops)
2003*7c478bd9Sstevel@tonic-gate {
2004*7c478bd9Sstevel@tonic-gate 	vnodeops_t	*op;
2005*7c478bd9Sstevel@tonic-gate 
2006*7c478bd9Sstevel@tonic-gate 	ASSERT(vp != NULL);
2007*7c478bd9Sstevel@tonic-gate 	ASSERT(vnodeops != NULL);
2008*7c478bd9Sstevel@tonic-gate 
2009*7c478bd9Sstevel@tonic-gate 	op = vp->v_op;
2010*7c478bd9Sstevel@tonic-gate 	membar_consumer();
2011*7c478bd9Sstevel@tonic-gate 	/*
2012*7c478bd9Sstevel@tonic-gate 	 * If vp->v_femhead == NULL, then we'll call casptr() to do the
2013*7c478bd9Sstevel@tonic-gate 	 * compare-and-swap on vp->v_op.  If either fails, then FEM is
2014*7c478bd9Sstevel@tonic-gate 	 * in effect on the vnode and we need to have FEM deal with it.
2015*7c478bd9Sstevel@tonic-gate 	 */
2016*7c478bd9Sstevel@tonic-gate 	if (vp->v_femhead != NULL || casptr(&vp->v_op, op, vnodeops) != op) {
2017*7c478bd9Sstevel@tonic-gate 		fem_setvnops(vp, vnodeops);
2018*7c478bd9Sstevel@tonic-gate 	}
2019*7c478bd9Sstevel@tonic-gate }
2020*7c478bd9Sstevel@tonic-gate 
2021*7c478bd9Sstevel@tonic-gate /*
2022*7c478bd9Sstevel@tonic-gate  * Retrieve the operations vector for a vnode
2023*7c478bd9Sstevel@tonic-gate  * As with vn_setops(above); make sure we aren't racing with FEM.
2024*7c478bd9Sstevel@tonic-gate  * FEM sets the v_op to a special, internal, vnodeops that wouldn't
2025*7c478bd9Sstevel@tonic-gate  * make sense to the callers of this routine.
2026*7c478bd9Sstevel@tonic-gate  */
2027*7c478bd9Sstevel@tonic-gate vnodeops_t *
2028*7c478bd9Sstevel@tonic-gate vn_getops(vnode_t *vp)
2029*7c478bd9Sstevel@tonic-gate {
2030*7c478bd9Sstevel@tonic-gate 	vnodeops_t	*op;
2031*7c478bd9Sstevel@tonic-gate 
2032*7c478bd9Sstevel@tonic-gate 	ASSERT(vp != NULL);
2033*7c478bd9Sstevel@tonic-gate 
2034*7c478bd9Sstevel@tonic-gate 	op = vp->v_op;
2035*7c478bd9Sstevel@tonic-gate 	membar_consumer();
2036*7c478bd9Sstevel@tonic-gate 	if (vp->v_femhead == NULL && op == vp->v_op) {
2037*7c478bd9Sstevel@tonic-gate 		return (op);
2038*7c478bd9Sstevel@tonic-gate 	} else {
2039*7c478bd9Sstevel@tonic-gate 		return (fem_getvnops(vp));
2040*7c478bd9Sstevel@tonic-gate 	}
2041*7c478bd9Sstevel@tonic-gate }
2042*7c478bd9Sstevel@tonic-gate 
2043*7c478bd9Sstevel@tonic-gate /*
2044*7c478bd9Sstevel@tonic-gate  * Returns non-zero (1) if the vnodeops matches that of the vnode.
2045*7c478bd9Sstevel@tonic-gate  * Returns zero (0) if not.
2046*7c478bd9Sstevel@tonic-gate  */
2047*7c478bd9Sstevel@tonic-gate int
2048*7c478bd9Sstevel@tonic-gate vn_matchops(vnode_t *vp, vnodeops_t *vnodeops)
2049*7c478bd9Sstevel@tonic-gate {
2050*7c478bd9Sstevel@tonic-gate 	return (vn_getops(vp) == vnodeops);
2051*7c478bd9Sstevel@tonic-gate }
2052*7c478bd9Sstevel@tonic-gate 
2053*7c478bd9Sstevel@tonic-gate /*
2054*7c478bd9Sstevel@tonic-gate  * Returns non-zero (1) if the specified operation matches the
2055*7c478bd9Sstevel@tonic-gate  * corresponding operation for that the vnode.
2056*7c478bd9Sstevel@tonic-gate  * Returns zero (0) if not.
2057*7c478bd9Sstevel@tonic-gate  */
2058*7c478bd9Sstevel@tonic-gate 
2059*7c478bd9Sstevel@tonic-gate #define	MATCHNAME(n1, n2) (((n1)[0] == (n2)[0]) && (strcmp((n1), (n2)) == 0))
2060*7c478bd9Sstevel@tonic-gate 
2061*7c478bd9Sstevel@tonic-gate int
2062*7c478bd9Sstevel@tonic-gate vn_matchopval(vnode_t *vp, char *vopname, fs_generic_func_p funcp)
2063*7c478bd9Sstevel@tonic-gate {
2064*7c478bd9Sstevel@tonic-gate 	const fs_operation_trans_def_t *otdp;
2065*7c478bd9Sstevel@tonic-gate 	fs_generic_func_p *loc = NULL;
2066*7c478bd9Sstevel@tonic-gate 	vnodeops_t	*vop = vn_getops(vp);
2067*7c478bd9Sstevel@tonic-gate 
2068*7c478bd9Sstevel@tonic-gate 	ASSERT(vopname != NULL);
2069*7c478bd9Sstevel@tonic-gate 
2070*7c478bd9Sstevel@tonic-gate 	for (otdp = vn_ops_table; otdp->name != NULL; otdp++) {
2071*7c478bd9Sstevel@tonic-gate 		if (MATCHNAME(otdp->name, vopname)) {
2072*7c478bd9Sstevel@tonic-gate 			loc = (fs_generic_func_p *)((char *)(vop)
2073*7c478bd9Sstevel@tonic-gate 							+ otdp->offset);
2074*7c478bd9Sstevel@tonic-gate 			break;
2075*7c478bd9Sstevel@tonic-gate 		}
2076*7c478bd9Sstevel@tonic-gate 	}
2077*7c478bd9Sstevel@tonic-gate 
2078*7c478bd9Sstevel@tonic-gate 	return ((loc != NULL) && (*loc == funcp));
2079*7c478bd9Sstevel@tonic-gate }
2080*7c478bd9Sstevel@tonic-gate 
2081*7c478bd9Sstevel@tonic-gate /*
2082*7c478bd9Sstevel@tonic-gate  * fs_new_caller_id() needs to return a unique ID on a given local system.
2083*7c478bd9Sstevel@tonic-gate  * The IDs do not need to survive across reboots.  These are primarily
2084*7c478bd9Sstevel@tonic-gate  * used so that (FEM) monitors can detect particular callers (such as
2085*7c478bd9Sstevel@tonic-gate  * the NFS server) to a given vnode/vfs operation.
2086*7c478bd9Sstevel@tonic-gate  */
2087*7c478bd9Sstevel@tonic-gate u_longlong_t
2088*7c478bd9Sstevel@tonic-gate fs_new_caller_id()
2089*7c478bd9Sstevel@tonic-gate {
2090*7c478bd9Sstevel@tonic-gate 	static uint64_t next_caller_id = 0LL; /* First call returns 1 */
2091*7c478bd9Sstevel@tonic-gate 
2092*7c478bd9Sstevel@tonic-gate 	return ((u_longlong_t)atomic_add_64_nv(&next_caller_id, 1));
2093*7c478bd9Sstevel@tonic-gate }
2094*7c478bd9Sstevel@tonic-gate 
2095*7c478bd9Sstevel@tonic-gate /*
2096*7c478bd9Sstevel@tonic-gate  * Returns the raw path associated with this vnode.  Normal consumers should
2097*7c478bd9Sstevel@tonic-gate  * use the vnodetopath() function to get a validated, secure path.
2098*7c478bd9Sstevel@tonic-gate  */
2099*7c478bd9Sstevel@tonic-gate char *
2100*7c478bd9Sstevel@tonic-gate vn_path(vnode_t *vp)
2101*7c478bd9Sstevel@tonic-gate {
2102*7c478bd9Sstevel@tonic-gate 	return (vp->v_path);
2103*7c478bd9Sstevel@tonic-gate }
2104*7c478bd9Sstevel@tonic-gate 
2105*7c478bd9Sstevel@tonic-gate /*
2106*7c478bd9Sstevel@tonic-gate  * Given a starting vnode and a path, updates the path in the target vnode in
2107*7c478bd9Sstevel@tonic-gate  * a safe manner.  If the vnode already has path information embedded, then the
2108*7c478bd9Sstevel@tonic-gate  * cached path is left untouched.  Consumers should use the VN_SETPATH() macro,
2109*7c478bd9Sstevel@tonic-gate  * which only calls this function if the path is already NULL.
2110*7c478bd9Sstevel@tonic-gate  */
2111*7c478bd9Sstevel@tonic-gate void
2112*7c478bd9Sstevel@tonic-gate vn_setpath(vnode_t *rootvp, struct vnode *startvp, struct vnode *vp,
2113*7c478bd9Sstevel@tonic-gate     const char *path, size_t plen)
2114*7c478bd9Sstevel@tonic-gate {
2115*7c478bd9Sstevel@tonic-gate 	char	*rpath;
2116*7c478bd9Sstevel@tonic-gate 	vnode_t	*base;
2117*7c478bd9Sstevel@tonic-gate 	size_t	rpathlen, rpathalloc;
2118*7c478bd9Sstevel@tonic-gate 	int	doslash = 1;
2119*7c478bd9Sstevel@tonic-gate 
2120*7c478bd9Sstevel@tonic-gate 	if (*path == '/') {
2121*7c478bd9Sstevel@tonic-gate 		base = rootvp;
2122*7c478bd9Sstevel@tonic-gate 		path++;
2123*7c478bd9Sstevel@tonic-gate 		plen--;
2124*7c478bd9Sstevel@tonic-gate 	} else {
2125*7c478bd9Sstevel@tonic-gate 		base = startvp;
2126*7c478bd9Sstevel@tonic-gate 	}
2127*7c478bd9Sstevel@tonic-gate 
2128*7c478bd9Sstevel@tonic-gate 	/*
2129*7c478bd9Sstevel@tonic-gate 	 * We cannot grab base->v_lock while we hold vp->v_lock because of
2130*7c478bd9Sstevel@tonic-gate 	 * the potential for deadlock.
2131*7c478bd9Sstevel@tonic-gate 	 */
2132*7c478bd9Sstevel@tonic-gate 	mutex_enter(&base->v_lock);
2133*7c478bd9Sstevel@tonic-gate 	if (base->v_path == NULL) {
2134*7c478bd9Sstevel@tonic-gate 		mutex_exit(&base->v_lock);
2135*7c478bd9Sstevel@tonic-gate 		return;
2136*7c478bd9Sstevel@tonic-gate 	}
2137*7c478bd9Sstevel@tonic-gate 
2138*7c478bd9Sstevel@tonic-gate 	rpathlen = strlen(base->v_path);
2139*7c478bd9Sstevel@tonic-gate 	rpathalloc = rpathlen + plen + 1;
2140*7c478bd9Sstevel@tonic-gate 	/* Avoid adding a slash if there's already one there */
2141*7c478bd9Sstevel@tonic-gate 	if (base->v_path[rpathlen-1] == '/')
2142*7c478bd9Sstevel@tonic-gate 		doslash = 0;
2143*7c478bd9Sstevel@tonic-gate 	else
2144*7c478bd9Sstevel@tonic-gate 		rpathalloc++;
2145*7c478bd9Sstevel@tonic-gate 
2146*7c478bd9Sstevel@tonic-gate 	/*
2147*7c478bd9Sstevel@tonic-gate 	 * We don't want to call kmem_alloc(KM_SLEEP) with kernel locks held,
2148*7c478bd9Sstevel@tonic-gate 	 * so we must do this dance.  If, by chance, something changes the path,
2149*7c478bd9Sstevel@tonic-gate 	 * just give up since there is no real harm.
2150*7c478bd9Sstevel@tonic-gate 	 */
2151*7c478bd9Sstevel@tonic-gate 	mutex_exit(&base->v_lock);
2152*7c478bd9Sstevel@tonic-gate 
2153*7c478bd9Sstevel@tonic-gate 	rpath = kmem_alloc(rpathalloc, KM_SLEEP);
2154*7c478bd9Sstevel@tonic-gate 
2155*7c478bd9Sstevel@tonic-gate 	mutex_enter(&base->v_lock);
2156*7c478bd9Sstevel@tonic-gate 	if (base->v_path == NULL || strlen(base->v_path) != rpathlen) {
2157*7c478bd9Sstevel@tonic-gate 		mutex_exit(&base->v_lock);
2158*7c478bd9Sstevel@tonic-gate 		kmem_free(rpath, rpathalloc);
2159*7c478bd9Sstevel@tonic-gate 		return;
2160*7c478bd9Sstevel@tonic-gate 	}
2161*7c478bd9Sstevel@tonic-gate 	bcopy(base->v_path, rpath, rpathlen);
2162*7c478bd9Sstevel@tonic-gate 	mutex_exit(&base->v_lock);
2163*7c478bd9Sstevel@tonic-gate 
2164*7c478bd9Sstevel@tonic-gate 	if (doslash)
2165*7c478bd9Sstevel@tonic-gate 		rpath[rpathlen++] = '/';
2166*7c478bd9Sstevel@tonic-gate 	bcopy(path, rpath + rpathlen, plen);
2167*7c478bd9Sstevel@tonic-gate 	rpath[rpathlen + plen] = '\0';
2168*7c478bd9Sstevel@tonic-gate 
2169*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
2170*7c478bd9Sstevel@tonic-gate 	if (vp->v_path != NULL) {
2171*7c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
2172*7c478bd9Sstevel@tonic-gate 		kmem_free(rpath, rpathalloc);
2173*7c478bd9Sstevel@tonic-gate 	} else {
2174*7c478bd9Sstevel@tonic-gate 		vp->v_path = rpath;
2175*7c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
2176*7c478bd9Sstevel@tonic-gate 	}
2177*7c478bd9Sstevel@tonic-gate }
2178*7c478bd9Sstevel@tonic-gate 
2179*7c478bd9Sstevel@tonic-gate /*
2180*7c478bd9Sstevel@tonic-gate  * Sets the path to the vnode to be the given string, regardless of current
2181*7c478bd9Sstevel@tonic-gate  * context.  The string must be a complete path from rootdir.  This is only used
2182*7c478bd9Sstevel@tonic-gate  * by fsop_root() for setting the path based on the mountpoint.
2183*7c478bd9Sstevel@tonic-gate  */
2184*7c478bd9Sstevel@tonic-gate void
2185*7c478bd9Sstevel@tonic-gate vn_setpath_str(struct vnode *vp, const char *str, size_t len)
2186*7c478bd9Sstevel@tonic-gate {
2187*7c478bd9Sstevel@tonic-gate 	char *buf = kmem_alloc(len + 1, KM_SLEEP);
2188*7c478bd9Sstevel@tonic-gate 
2189*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
2190*7c478bd9Sstevel@tonic-gate 	if (vp->v_path != NULL) {
2191*7c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
2192*7c478bd9Sstevel@tonic-gate 		kmem_free(buf, len + 1);
2193*7c478bd9Sstevel@tonic-gate 		return;
2194*7c478bd9Sstevel@tonic-gate 	}
2195*7c478bd9Sstevel@tonic-gate 
2196*7c478bd9Sstevel@tonic-gate 	vp->v_path = buf;
2197*7c478bd9Sstevel@tonic-gate 	bcopy(str, vp->v_path, len);
2198*7c478bd9Sstevel@tonic-gate 	vp->v_path[len] = '\0';
2199*7c478bd9Sstevel@tonic-gate 
2200*7c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
2201*7c478bd9Sstevel@tonic-gate }
2202*7c478bd9Sstevel@tonic-gate 
2203*7c478bd9Sstevel@tonic-gate /*
2204*7c478bd9Sstevel@tonic-gate  * Similar to vn_setpath_str(), this function sets the path of the destination
2205*7c478bd9Sstevel@tonic-gate  * vnode to the be the same as the source vnode.
2206*7c478bd9Sstevel@tonic-gate  */
2207*7c478bd9Sstevel@tonic-gate void
2208*7c478bd9Sstevel@tonic-gate vn_copypath(struct vnode *src, struct vnode *dst)
2209*7c478bd9Sstevel@tonic-gate {
2210*7c478bd9Sstevel@tonic-gate 	char *buf;
2211*7c478bd9Sstevel@tonic-gate 	int alloc;
2212*7c478bd9Sstevel@tonic-gate 
2213*7c478bd9Sstevel@tonic-gate 	mutex_enter(&src->v_lock);
2214*7c478bd9Sstevel@tonic-gate 	if (src->v_path == NULL) {
2215*7c478bd9Sstevel@tonic-gate 		mutex_exit(&src->v_lock);
2216*7c478bd9Sstevel@tonic-gate 		return;
2217*7c478bd9Sstevel@tonic-gate 	}
2218*7c478bd9Sstevel@tonic-gate 	alloc = strlen(src->v_path) + 1;
2219*7c478bd9Sstevel@tonic-gate 
2220*7c478bd9Sstevel@tonic-gate 	/* avoid kmem_alloc() with lock held */
2221*7c478bd9Sstevel@tonic-gate 	mutex_exit(&src->v_lock);
2222*7c478bd9Sstevel@tonic-gate 	buf = kmem_alloc(alloc, KM_SLEEP);
2223*7c478bd9Sstevel@tonic-gate 	mutex_enter(&src->v_lock);
2224*7c478bd9Sstevel@tonic-gate 	if (src->v_path == NULL || strlen(src->v_path) + 1 != alloc) {
2225*7c478bd9Sstevel@tonic-gate 		mutex_exit(&src->v_lock);
2226*7c478bd9Sstevel@tonic-gate 		kmem_free(buf, alloc);
2227*7c478bd9Sstevel@tonic-gate 		return;
2228*7c478bd9Sstevel@tonic-gate 	}
2229*7c478bd9Sstevel@tonic-gate 	bcopy(src->v_path, buf, alloc);
2230*7c478bd9Sstevel@tonic-gate 	mutex_exit(&src->v_lock);
2231*7c478bd9Sstevel@tonic-gate 
2232*7c478bd9Sstevel@tonic-gate 	mutex_enter(&dst->v_lock);
2233*7c478bd9Sstevel@tonic-gate 	if (dst->v_path != NULL) {
2234*7c478bd9Sstevel@tonic-gate 		mutex_exit(&dst->v_lock);
2235*7c478bd9Sstevel@tonic-gate 		kmem_free(buf, alloc);
2236*7c478bd9Sstevel@tonic-gate 		return;
2237*7c478bd9Sstevel@tonic-gate 	}
2238*7c478bd9Sstevel@tonic-gate 	dst->v_path = buf;
2239*7c478bd9Sstevel@tonic-gate 	mutex_exit(&dst->v_lock);
2240*7c478bd9Sstevel@tonic-gate }
2241*7c478bd9Sstevel@tonic-gate 
2242*7c478bd9Sstevel@tonic-gate /*
2243*7c478bd9Sstevel@tonic-gate  * XXX Private interface for segvn routines that handle vnode
2244*7c478bd9Sstevel@tonic-gate  * large page segments.
2245*7c478bd9Sstevel@tonic-gate  *
2246*7c478bd9Sstevel@tonic-gate  * return 1 if vp's file system VOP_PAGEIO() implementation
2247*7c478bd9Sstevel@tonic-gate  * can be safely used instead of VOP_GETPAGE() for handling
2248*7c478bd9Sstevel@tonic-gate  * pagefaults against regular non swap files. VOP_PAGEIO()
2249*7c478bd9Sstevel@tonic-gate  * interface is considered safe here if its implementation
2250*7c478bd9Sstevel@tonic-gate  * is very close to VOP_GETPAGE() implementation.
2251*7c478bd9Sstevel@tonic-gate  * e.g. It zero's out the part of the page beyond EOF. Doesn't
2252*7c478bd9Sstevel@tonic-gate  * panic if there're file holes but instead returns an error.
2253*7c478bd9Sstevel@tonic-gate  * Doesn't assume file won't be changed by user writes, etc.
2254*7c478bd9Sstevel@tonic-gate  *
2255*7c478bd9Sstevel@tonic-gate  * return 0 otherwise.
2256*7c478bd9Sstevel@tonic-gate  *
2257*7c478bd9Sstevel@tonic-gate  * For now allow segvn to only use VOP_PAGEIO() with ufs and nfs.
2258*7c478bd9Sstevel@tonic-gate  */
2259*7c478bd9Sstevel@tonic-gate int
2260*7c478bd9Sstevel@tonic-gate vn_vmpss_usepageio(vnode_t *vp)
2261*7c478bd9Sstevel@tonic-gate {
2262*7c478bd9Sstevel@tonic-gate 	vfs_t   *vfsp = vp->v_vfsp;
2263*7c478bd9Sstevel@tonic-gate 	char *fsname = vfssw[vfsp->vfs_fstype].vsw_name;
2264*7c478bd9Sstevel@tonic-gate 	char *pageio_ok_fss[] = {"ufs", "nfs", NULL};
2265*7c478bd9Sstevel@tonic-gate 	char **fsok = pageio_ok_fss;
2266*7c478bd9Sstevel@tonic-gate 
2267*7c478bd9Sstevel@tonic-gate 	if (fsname == NULL) {
2268*7c478bd9Sstevel@tonic-gate 		return (0);
2269*7c478bd9Sstevel@tonic-gate 	}
2270*7c478bd9Sstevel@tonic-gate 
2271*7c478bd9Sstevel@tonic-gate 	for (; *fsok; fsok++) {
2272*7c478bd9Sstevel@tonic-gate 		if (strcmp(*fsok, fsname) == 0) {
2273*7c478bd9Sstevel@tonic-gate 			return (1);
2274*7c478bd9Sstevel@tonic-gate 		}
2275*7c478bd9Sstevel@tonic-gate 	}
2276*7c478bd9Sstevel@tonic-gate 	return (0);
2277*7c478bd9Sstevel@tonic-gate }
2278*7c478bd9Sstevel@tonic-gate 
2279*7c478bd9Sstevel@tonic-gate /* VOP_XXX() macros call the corresponding fop_xxx() function */
2280*7c478bd9Sstevel@tonic-gate 
2281*7c478bd9Sstevel@tonic-gate int
2282*7c478bd9Sstevel@tonic-gate fop_open(
2283*7c478bd9Sstevel@tonic-gate 	vnode_t **vpp,
2284*7c478bd9Sstevel@tonic-gate 	int mode,
2285*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2286*7c478bd9Sstevel@tonic-gate {
2287*7c478bd9Sstevel@tonic-gate 	int ret;
2288*7c478bd9Sstevel@tonic-gate 	vnode_t *vp = *vpp;
2289*7c478bd9Sstevel@tonic-gate 
2290*7c478bd9Sstevel@tonic-gate 	VN_HOLD(vp);
2291*7c478bd9Sstevel@tonic-gate 	/*
2292*7c478bd9Sstevel@tonic-gate 	 * Adding to the vnode counts before calling open
2293*7c478bd9Sstevel@tonic-gate 	 * avoids the need for a mutex. It circumvents a race
2294*7c478bd9Sstevel@tonic-gate 	 * condition where a query made on the vnode counts results in a
2295*7c478bd9Sstevel@tonic-gate 	 * false negative. The inquirer goes away believing the file is
2296*7c478bd9Sstevel@tonic-gate 	 * not open when there is an open on the file already under way.
2297*7c478bd9Sstevel@tonic-gate 	 *
2298*7c478bd9Sstevel@tonic-gate 	 * The counts are meant to prevent NFS from granting a delegation
2299*7c478bd9Sstevel@tonic-gate 	 * when it would be dangerous to do so.
2300*7c478bd9Sstevel@tonic-gate 	 *
2301*7c478bd9Sstevel@tonic-gate 	 * The vnode counts are only kept on regular files
2302*7c478bd9Sstevel@tonic-gate 	 */
2303*7c478bd9Sstevel@tonic-gate 	if ((*vpp)->v_type == VREG) {
2304*7c478bd9Sstevel@tonic-gate 		if (mode & FREAD)
2305*7c478bd9Sstevel@tonic-gate 			atomic_add_32(&((*vpp)->v_rdcnt), 1);
2306*7c478bd9Sstevel@tonic-gate 		if (mode & FWRITE)
2307*7c478bd9Sstevel@tonic-gate 			atomic_add_32(&((*vpp)->v_wrcnt), 1);
2308*7c478bd9Sstevel@tonic-gate 	}
2309*7c478bd9Sstevel@tonic-gate 
2310*7c478bd9Sstevel@tonic-gate 	ret = (*(*(vpp))->v_op->vop_open)(vpp, mode, cr);
2311*7c478bd9Sstevel@tonic-gate 
2312*7c478bd9Sstevel@tonic-gate 	if (ret) {
2313*7c478bd9Sstevel@tonic-gate 		/*
2314*7c478bd9Sstevel@tonic-gate 		 * Use the saved vp just in case the vnode ptr got trashed
2315*7c478bd9Sstevel@tonic-gate 		 * by the error.
2316*7c478bd9Sstevel@tonic-gate 		 */
2317*7c478bd9Sstevel@tonic-gate 		if ((vp->v_type == VREG) && (mode & FREAD))
2318*7c478bd9Sstevel@tonic-gate 			atomic_add_32(&(vp->v_rdcnt), -1);
2319*7c478bd9Sstevel@tonic-gate 		if ((vp->v_type == VREG) && (mode & FWRITE))
2320*7c478bd9Sstevel@tonic-gate 			atomic_add_32(&(vp->v_wrcnt), -1);
2321*7c478bd9Sstevel@tonic-gate 	} else {
2322*7c478bd9Sstevel@tonic-gate 		/*
2323*7c478bd9Sstevel@tonic-gate 		 * Some filesystems will return a different vnode,
2324*7c478bd9Sstevel@tonic-gate 		 * but the same path was still used to open it.
2325*7c478bd9Sstevel@tonic-gate 		 * So if we do change the vnode and need to
2326*7c478bd9Sstevel@tonic-gate 		 * copy over the path, do so here, rather than special
2327*7c478bd9Sstevel@tonic-gate 		 * casing each filesystem. Adjust the vnode counts to
2328*7c478bd9Sstevel@tonic-gate 		 * reflect the vnode switch.
2329*7c478bd9Sstevel@tonic-gate 		 */
2330*7c478bd9Sstevel@tonic-gate 
2331*7c478bd9Sstevel@tonic-gate 		if (*vpp != vp && *vpp != NULL) {
2332*7c478bd9Sstevel@tonic-gate 			if (vfs_vnode_path)
2333*7c478bd9Sstevel@tonic-gate 				vn_copypath(vp, *vpp);
2334*7c478bd9Sstevel@tonic-gate 		    if (((*vpp)->v_type == VREG) && (mode & FREAD))
2335*7c478bd9Sstevel@tonic-gate 			atomic_add_32(&((*vpp)->v_rdcnt), 1);
2336*7c478bd9Sstevel@tonic-gate 		    if ((vp->v_type == VREG) && (mode & FREAD))
2337*7c478bd9Sstevel@tonic-gate 			atomic_add_32(&(vp->v_rdcnt), -1);
2338*7c478bd9Sstevel@tonic-gate 		    if (((*vpp)->v_type == VREG) && (mode & FWRITE))
2339*7c478bd9Sstevel@tonic-gate 			atomic_add_32(&((*vpp)->v_wrcnt), 1);
2340*7c478bd9Sstevel@tonic-gate 		    if ((vp->v_type == VREG) && (mode & FWRITE))
2341*7c478bd9Sstevel@tonic-gate 			atomic_add_32(&(vp->v_wrcnt), -1);
2342*7c478bd9Sstevel@tonic-gate 		}
2343*7c478bd9Sstevel@tonic-gate 	}
2344*7c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
2345*7c478bd9Sstevel@tonic-gate 	return (ret);
2346*7c478bd9Sstevel@tonic-gate }
2347*7c478bd9Sstevel@tonic-gate 
2348*7c478bd9Sstevel@tonic-gate int
2349*7c478bd9Sstevel@tonic-gate fop_close(
2350*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2351*7c478bd9Sstevel@tonic-gate 	int flag,
2352*7c478bd9Sstevel@tonic-gate 	int count,
2353*7c478bd9Sstevel@tonic-gate 	offset_t offset,
2354*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2355*7c478bd9Sstevel@tonic-gate {
2356*7c478bd9Sstevel@tonic-gate 	int error;
2357*7c478bd9Sstevel@tonic-gate 	error = (*(vp)->v_op->vop_close)(vp, flag, count, offset, cr);
2358*7c478bd9Sstevel@tonic-gate 	/*
2359*7c478bd9Sstevel@tonic-gate 	 * Check passed in count to handle possible dups. Vnode counts are only
2360*7c478bd9Sstevel@tonic-gate 	 * kept on regular files
2361*7c478bd9Sstevel@tonic-gate 	 */
2362*7c478bd9Sstevel@tonic-gate 	if ((vp->v_type == VREG) && (count == 1))  {
2363*7c478bd9Sstevel@tonic-gate 		if (flag & FREAD) {
2364*7c478bd9Sstevel@tonic-gate 			ASSERT(vp->v_rdcnt > 0);
2365*7c478bd9Sstevel@tonic-gate 			atomic_add_32(&(vp->v_rdcnt), -1);
2366*7c478bd9Sstevel@tonic-gate 		}
2367*7c478bd9Sstevel@tonic-gate 		if (flag & FWRITE) {
2368*7c478bd9Sstevel@tonic-gate 			ASSERT(vp->v_wrcnt > 0);
2369*7c478bd9Sstevel@tonic-gate 			atomic_add_32(&(vp->v_wrcnt), -1);
2370*7c478bd9Sstevel@tonic-gate 		}
2371*7c478bd9Sstevel@tonic-gate 	}
2372*7c478bd9Sstevel@tonic-gate 	return (error);
2373*7c478bd9Sstevel@tonic-gate }
2374*7c478bd9Sstevel@tonic-gate 
2375*7c478bd9Sstevel@tonic-gate int
2376*7c478bd9Sstevel@tonic-gate fop_read(
2377*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2378*7c478bd9Sstevel@tonic-gate 	uio_t *uiop,
2379*7c478bd9Sstevel@tonic-gate 	int ioflag,
2380*7c478bd9Sstevel@tonic-gate 	cred_t *cr,
2381*7c478bd9Sstevel@tonic-gate 	struct caller_context *ct)
2382*7c478bd9Sstevel@tonic-gate {
2383*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_read)(vp, uiop, ioflag, cr, ct);
2384*7c478bd9Sstevel@tonic-gate }
2385*7c478bd9Sstevel@tonic-gate 
2386*7c478bd9Sstevel@tonic-gate int
2387*7c478bd9Sstevel@tonic-gate fop_write(
2388*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2389*7c478bd9Sstevel@tonic-gate 	uio_t *uiop,
2390*7c478bd9Sstevel@tonic-gate 	int ioflag,
2391*7c478bd9Sstevel@tonic-gate 	cred_t *cr,
2392*7c478bd9Sstevel@tonic-gate 	struct caller_context *ct)
2393*7c478bd9Sstevel@tonic-gate {
2394*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_write)(vp, uiop, ioflag, cr, ct);
2395*7c478bd9Sstevel@tonic-gate }
2396*7c478bd9Sstevel@tonic-gate 
2397*7c478bd9Sstevel@tonic-gate int
2398*7c478bd9Sstevel@tonic-gate fop_ioctl(
2399*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2400*7c478bd9Sstevel@tonic-gate 	int cmd,
2401*7c478bd9Sstevel@tonic-gate 	intptr_t arg,
2402*7c478bd9Sstevel@tonic-gate 	int flag,
2403*7c478bd9Sstevel@tonic-gate 	cred_t *cr,
2404*7c478bd9Sstevel@tonic-gate 	int *rvalp)
2405*7c478bd9Sstevel@tonic-gate {
2406*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_ioctl)(vp, cmd, arg, flag, cr, rvalp);
2407*7c478bd9Sstevel@tonic-gate }
2408*7c478bd9Sstevel@tonic-gate 
2409*7c478bd9Sstevel@tonic-gate int
2410*7c478bd9Sstevel@tonic-gate fop_setfl(
2411*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2412*7c478bd9Sstevel@tonic-gate 	int oflags,
2413*7c478bd9Sstevel@tonic-gate 	int nflags,
2414*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2415*7c478bd9Sstevel@tonic-gate {
2416*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_setfl)(vp, oflags, nflags, cr);
2417*7c478bd9Sstevel@tonic-gate }
2418*7c478bd9Sstevel@tonic-gate 
2419*7c478bd9Sstevel@tonic-gate int
2420*7c478bd9Sstevel@tonic-gate fop_getattr(
2421*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2422*7c478bd9Sstevel@tonic-gate 	vattr_t *vap,
2423*7c478bd9Sstevel@tonic-gate 	int flags,
2424*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2425*7c478bd9Sstevel@tonic-gate {
2426*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_getattr)(vp, vap, flags, cr);
2427*7c478bd9Sstevel@tonic-gate }
2428*7c478bd9Sstevel@tonic-gate 
2429*7c478bd9Sstevel@tonic-gate int
2430*7c478bd9Sstevel@tonic-gate fop_setattr(
2431*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2432*7c478bd9Sstevel@tonic-gate 	vattr_t *vap,
2433*7c478bd9Sstevel@tonic-gate 	int flags,
2434*7c478bd9Sstevel@tonic-gate 	cred_t *cr,
2435*7c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
2436*7c478bd9Sstevel@tonic-gate {
2437*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_setattr)(vp, vap, flags, cr, ct);
2438*7c478bd9Sstevel@tonic-gate }
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate int
2441*7c478bd9Sstevel@tonic-gate fop_access(
2442*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2443*7c478bd9Sstevel@tonic-gate 	int mode,
2444*7c478bd9Sstevel@tonic-gate 	int flags,
2445*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2446*7c478bd9Sstevel@tonic-gate {
2447*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_access)(vp, mode, flags, cr);
2448*7c478bd9Sstevel@tonic-gate }
2449*7c478bd9Sstevel@tonic-gate 
2450*7c478bd9Sstevel@tonic-gate int
2451*7c478bd9Sstevel@tonic-gate fop_lookup(
2452*7c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
2453*7c478bd9Sstevel@tonic-gate 	char *nm,
2454*7c478bd9Sstevel@tonic-gate 	vnode_t **vpp,
2455*7c478bd9Sstevel@tonic-gate 	pathname_t *pnp,
2456*7c478bd9Sstevel@tonic-gate 	int flags,
2457*7c478bd9Sstevel@tonic-gate 	vnode_t *rdir,
2458*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2459*7c478bd9Sstevel@tonic-gate {
2460*7c478bd9Sstevel@tonic-gate 	return (*(dvp)->v_op->vop_lookup)(dvp, nm, vpp, pnp, flags, rdir, cr);
2461*7c478bd9Sstevel@tonic-gate }
2462*7c478bd9Sstevel@tonic-gate 
2463*7c478bd9Sstevel@tonic-gate int
2464*7c478bd9Sstevel@tonic-gate fop_create(
2465*7c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
2466*7c478bd9Sstevel@tonic-gate 	char *name,
2467*7c478bd9Sstevel@tonic-gate 	vattr_t *vap,
2468*7c478bd9Sstevel@tonic-gate 	vcexcl_t excl,
2469*7c478bd9Sstevel@tonic-gate 	int mode,
2470*7c478bd9Sstevel@tonic-gate 	vnode_t **vpp,
2471*7c478bd9Sstevel@tonic-gate 	cred_t *cr,
2472*7c478bd9Sstevel@tonic-gate 	int flag)
2473*7c478bd9Sstevel@tonic-gate {
2474*7c478bd9Sstevel@tonic-gate 	int ret;
2475*7c478bd9Sstevel@tonic-gate 
2476*7c478bd9Sstevel@tonic-gate 	ret = (*(dvp)->v_op->vop_create)
2477*7c478bd9Sstevel@tonic-gate 				(dvp, name, vap, excl, mode, vpp, cr, flag);
2478*7c478bd9Sstevel@tonic-gate 	if (vfs_vnode_path && ret == 0 && *vpp)
2479*7c478bd9Sstevel@tonic-gate 		VN_SETPATH(rootdir, dvp, *vpp, name, strlen(name));
2480*7c478bd9Sstevel@tonic-gate 
2481*7c478bd9Sstevel@tonic-gate 	return (ret);
2482*7c478bd9Sstevel@tonic-gate }
2483*7c478bd9Sstevel@tonic-gate 
2484*7c478bd9Sstevel@tonic-gate int
2485*7c478bd9Sstevel@tonic-gate fop_remove(
2486*7c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
2487*7c478bd9Sstevel@tonic-gate 	char *nm,
2488*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2489*7c478bd9Sstevel@tonic-gate {
2490*7c478bd9Sstevel@tonic-gate 	return (*(dvp)->v_op->vop_remove)(dvp, nm, cr);
2491*7c478bd9Sstevel@tonic-gate }
2492*7c478bd9Sstevel@tonic-gate 
2493*7c478bd9Sstevel@tonic-gate int
2494*7c478bd9Sstevel@tonic-gate fop_link(
2495*7c478bd9Sstevel@tonic-gate 	vnode_t *tdvp,
2496*7c478bd9Sstevel@tonic-gate 	vnode_t *svp,
2497*7c478bd9Sstevel@tonic-gate 	char *tnm,
2498*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2499*7c478bd9Sstevel@tonic-gate {
2500*7c478bd9Sstevel@tonic-gate 	return (*(tdvp)->v_op->vop_link)(tdvp, svp, tnm, cr);
2501*7c478bd9Sstevel@tonic-gate }
2502*7c478bd9Sstevel@tonic-gate 
2503*7c478bd9Sstevel@tonic-gate int
2504*7c478bd9Sstevel@tonic-gate fop_rename(
2505*7c478bd9Sstevel@tonic-gate 	vnode_t *sdvp,
2506*7c478bd9Sstevel@tonic-gate 	char *snm,
2507*7c478bd9Sstevel@tonic-gate 	vnode_t *tdvp,
2508*7c478bd9Sstevel@tonic-gate 	char *tnm,
2509*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2510*7c478bd9Sstevel@tonic-gate {
2511*7c478bd9Sstevel@tonic-gate 	return (*(sdvp)->v_op->vop_rename)(sdvp, snm, tdvp, tnm, cr);
2512*7c478bd9Sstevel@tonic-gate }
2513*7c478bd9Sstevel@tonic-gate 
2514*7c478bd9Sstevel@tonic-gate int
2515*7c478bd9Sstevel@tonic-gate fop_mkdir(
2516*7c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
2517*7c478bd9Sstevel@tonic-gate 	char *dirname,
2518*7c478bd9Sstevel@tonic-gate 	vattr_t *vap,
2519*7c478bd9Sstevel@tonic-gate 	vnode_t **vpp,
2520*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2521*7c478bd9Sstevel@tonic-gate {
2522*7c478bd9Sstevel@tonic-gate 	int ret;
2523*7c478bd9Sstevel@tonic-gate 
2524*7c478bd9Sstevel@tonic-gate 	ret = (*(dvp)->v_op->vop_mkdir)(dvp, dirname, vap, vpp, cr);
2525*7c478bd9Sstevel@tonic-gate 	if (vfs_vnode_path && ret == 0 && *vpp)
2526*7c478bd9Sstevel@tonic-gate 		VN_SETPATH(rootdir, dvp, *vpp, dirname, strlen(dirname));
2527*7c478bd9Sstevel@tonic-gate 
2528*7c478bd9Sstevel@tonic-gate 	return (ret);
2529*7c478bd9Sstevel@tonic-gate }
2530*7c478bd9Sstevel@tonic-gate 
2531*7c478bd9Sstevel@tonic-gate int
2532*7c478bd9Sstevel@tonic-gate fop_rmdir(
2533*7c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
2534*7c478bd9Sstevel@tonic-gate 	char *nm,
2535*7c478bd9Sstevel@tonic-gate 	vnode_t *cdir,
2536*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2537*7c478bd9Sstevel@tonic-gate {
2538*7c478bd9Sstevel@tonic-gate 	return (*(dvp)->v_op->vop_rmdir)(dvp, nm, cdir, cr);
2539*7c478bd9Sstevel@tonic-gate }
2540*7c478bd9Sstevel@tonic-gate 
2541*7c478bd9Sstevel@tonic-gate int
2542*7c478bd9Sstevel@tonic-gate fop_readdir(
2543*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2544*7c478bd9Sstevel@tonic-gate 	uio_t *uiop,
2545*7c478bd9Sstevel@tonic-gate 	cred_t *cr,
2546*7c478bd9Sstevel@tonic-gate 	int *eofp)
2547*7c478bd9Sstevel@tonic-gate {
2548*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_readdir)(vp, uiop, cr, eofp);
2549*7c478bd9Sstevel@tonic-gate }
2550*7c478bd9Sstevel@tonic-gate 
2551*7c478bd9Sstevel@tonic-gate int
2552*7c478bd9Sstevel@tonic-gate fop_symlink(
2553*7c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
2554*7c478bd9Sstevel@tonic-gate 	char *linkname,
2555*7c478bd9Sstevel@tonic-gate 	vattr_t *vap,
2556*7c478bd9Sstevel@tonic-gate 	char *target,
2557*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2558*7c478bd9Sstevel@tonic-gate {
2559*7c478bd9Sstevel@tonic-gate 	return (*(dvp)->v_op->vop_symlink) (dvp, linkname, vap, target, cr);
2560*7c478bd9Sstevel@tonic-gate }
2561*7c478bd9Sstevel@tonic-gate 
2562*7c478bd9Sstevel@tonic-gate int
2563*7c478bd9Sstevel@tonic-gate fop_readlink(
2564*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2565*7c478bd9Sstevel@tonic-gate 	uio_t *uiop,
2566*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2567*7c478bd9Sstevel@tonic-gate {
2568*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_readlink)(vp, uiop, cr);
2569*7c478bd9Sstevel@tonic-gate }
2570*7c478bd9Sstevel@tonic-gate 
2571*7c478bd9Sstevel@tonic-gate int
2572*7c478bd9Sstevel@tonic-gate fop_fsync(
2573*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2574*7c478bd9Sstevel@tonic-gate 	int syncflag,
2575*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2576*7c478bd9Sstevel@tonic-gate {
2577*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_fsync)(vp, syncflag, cr);
2578*7c478bd9Sstevel@tonic-gate }
2579*7c478bd9Sstevel@tonic-gate 
2580*7c478bd9Sstevel@tonic-gate void
2581*7c478bd9Sstevel@tonic-gate fop_inactive(
2582*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2583*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2584*7c478bd9Sstevel@tonic-gate {
2585*7c478bd9Sstevel@tonic-gate 	(*(vp)->v_op->vop_inactive)(vp, cr);
2586*7c478bd9Sstevel@tonic-gate }
2587*7c478bd9Sstevel@tonic-gate 
2588*7c478bd9Sstevel@tonic-gate int
2589*7c478bd9Sstevel@tonic-gate fop_fid(
2590*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2591*7c478bd9Sstevel@tonic-gate 	fid_t *fidp)
2592*7c478bd9Sstevel@tonic-gate {
2593*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_fid)(vp, fidp);
2594*7c478bd9Sstevel@tonic-gate }
2595*7c478bd9Sstevel@tonic-gate 
2596*7c478bd9Sstevel@tonic-gate int
2597*7c478bd9Sstevel@tonic-gate fop_rwlock(
2598*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2599*7c478bd9Sstevel@tonic-gate 	int write_lock,
2600*7c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
2601*7c478bd9Sstevel@tonic-gate {
2602*7c478bd9Sstevel@tonic-gate 	return ((*(vp)->v_op->vop_rwlock)(vp, write_lock, ct));
2603*7c478bd9Sstevel@tonic-gate }
2604*7c478bd9Sstevel@tonic-gate 
2605*7c478bd9Sstevel@tonic-gate void
2606*7c478bd9Sstevel@tonic-gate fop_rwunlock(
2607*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2608*7c478bd9Sstevel@tonic-gate 	int write_lock,
2609*7c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
2610*7c478bd9Sstevel@tonic-gate {
2611*7c478bd9Sstevel@tonic-gate 	(*(vp)->v_op->vop_rwunlock)(vp, write_lock, ct);
2612*7c478bd9Sstevel@tonic-gate }
2613*7c478bd9Sstevel@tonic-gate 
2614*7c478bd9Sstevel@tonic-gate int
2615*7c478bd9Sstevel@tonic-gate fop_seek(
2616*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2617*7c478bd9Sstevel@tonic-gate 	offset_t ooff,
2618*7c478bd9Sstevel@tonic-gate 	offset_t *noffp)
2619*7c478bd9Sstevel@tonic-gate {
2620*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_seek)(vp, ooff, noffp);
2621*7c478bd9Sstevel@tonic-gate }
2622*7c478bd9Sstevel@tonic-gate 
2623*7c478bd9Sstevel@tonic-gate int
2624*7c478bd9Sstevel@tonic-gate fop_cmp(
2625*7c478bd9Sstevel@tonic-gate 	vnode_t *vp1,
2626*7c478bd9Sstevel@tonic-gate 	vnode_t *vp2)
2627*7c478bd9Sstevel@tonic-gate {
2628*7c478bd9Sstevel@tonic-gate 	return (*(vp1)->v_op->vop_cmp)(vp1, vp2);
2629*7c478bd9Sstevel@tonic-gate }
2630*7c478bd9Sstevel@tonic-gate 
2631*7c478bd9Sstevel@tonic-gate int
2632*7c478bd9Sstevel@tonic-gate fop_frlock(
2633*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2634*7c478bd9Sstevel@tonic-gate 	int cmd,
2635*7c478bd9Sstevel@tonic-gate 	flock64_t *bfp,
2636*7c478bd9Sstevel@tonic-gate 	int flag,
2637*7c478bd9Sstevel@tonic-gate 	offset_t offset,
2638*7c478bd9Sstevel@tonic-gate 	struct flk_callback *flk_cbp,
2639*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2640*7c478bd9Sstevel@tonic-gate {
2641*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_frlock)
2642*7c478bd9Sstevel@tonic-gate 				(vp, cmd, bfp, flag, offset, flk_cbp, cr);
2643*7c478bd9Sstevel@tonic-gate }
2644*7c478bd9Sstevel@tonic-gate 
2645*7c478bd9Sstevel@tonic-gate int
2646*7c478bd9Sstevel@tonic-gate fop_space(
2647*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2648*7c478bd9Sstevel@tonic-gate 	int cmd,
2649*7c478bd9Sstevel@tonic-gate 	flock64_t *bfp,
2650*7c478bd9Sstevel@tonic-gate 	int flag,
2651*7c478bd9Sstevel@tonic-gate 	offset_t offset,
2652*7c478bd9Sstevel@tonic-gate 	cred_t *cr,
2653*7c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
2654*7c478bd9Sstevel@tonic-gate {
2655*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_space)(vp, cmd, bfp, flag, offset, cr, ct);
2656*7c478bd9Sstevel@tonic-gate }
2657*7c478bd9Sstevel@tonic-gate 
2658*7c478bd9Sstevel@tonic-gate int
2659*7c478bd9Sstevel@tonic-gate fop_realvp(
2660*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2661*7c478bd9Sstevel@tonic-gate 	vnode_t **vpp)
2662*7c478bd9Sstevel@tonic-gate {
2663*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_realvp)(vp, vpp);
2664*7c478bd9Sstevel@tonic-gate }
2665*7c478bd9Sstevel@tonic-gate 
2666*7c478bd9Sstevel@tonic-gate int
2667*7c478bd9Sstevel@tonic-gate fop_getpage(
2668*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2669*7c478bd9Sstevel@tonic-gate 	offset_t off,
2670*7c478bd9Sstevel@tonic-gate 	size_t len,
2671*7c478bd9Sstevel@tonic-gate 	uint_t *protp,
2672*7c478bd9Sstevel@tonic-gate 	page_t **plarr,
2673*7c478bd9Sstevel@tonic-gate 	size_t plsz,
2674*7c478bd9Sstevel@tonic-gate 	struct seg *seg,
2675*7c478bd9Sstevel@tonic-gate 	caddr_t addr,
2676*7c478bd9Sstevel@tonic-gate 	enum seg_rw rw,
2677*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2678*7c478bd9Sstevel@tonic-gate {
2679*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_getpage)
2680*7c478bd9Sstevel@tonic-gate 			(vp, off, len, protp, plarr, plsz, seg, addr, rw, cr);
2681*7c478bd9Sstevel@tonic-gate }
2682*7c478bd9Sstevel@tonic-gate 
2683*7c478bd9Sstevel@tonic-gate int
2684*7c478bd9Sstevel@tonic-gate fop_putpage(
2685*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2686*7c478bd9Sstevel@tonic-gate 	offset_t off,
2687*7c478bd9Sstevel@tonic-gate 	size_t len,
2688*7c478bd9Sstevel@tonic-gate 	int flags,
2689*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2690*7c478bd9Sstevel@tonic-gate {
2691*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_putpage)(vp, off, len, flags, cr);
2692*7c478bd9Sstevel@tonic-gate }
2693*7c478bd9Sstevel@tonic-gate 
2694*7c478bd9Sstevel@tonic-gate int
2695*7c478bd9Sstevel@tonic-gate fop_map(
2696*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2697*7c478bd9Sstevel@tonic-gate 	offset_t off,
2698*7c478bd9Sstevel@tonic-gate 	struct as *as,
2699*7c478bd9Sstevel@tonic-gate 	caddr_t *addrp,
2700*7c478bd9Sstevel@tonic-gate 	size_t len,
2701*7c478bd9Sstevel@tonic-gate 	uchar_t prot,
2702*7c478bd9Sstevel@tonic-gate 	uchar_t maxprot,
2703*7c478bd9Sstevel@tonic-gate 	uint_t flags,
2704*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2705*7c478bd9Sstevel@tonic-gate {
2706*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_map)
2707*7c478bd9Sstevel@tonic-gate 			(vp, off, as, addrp, len, prot, maxprot, flags, cr);
2708*7c478bd9Sstevel@tonic-gate }
2709*7c478bd9Sstevel@tonic-gate 
2710*7c478bd9Sstevel@tonic-gate int
2711*7c478bd9Sstevel@tonic-gate fop_addmap(
2712*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2713*7c478bd9Sstevel@tonic-gate 	offset_t off,
2714*7c478bd9Sstevel@tonic-gate 	struct as *as,
2715*7c478bd9Sstevel@tonic-gate 	caddr_t addr,
2716*7c478bd9Sstevel@tonic-gate 	size_t len,
2717*7c478bd9Sstevel@tonic-gate 	uchar_t prot,
2718*7c478bd9Sstevel@tonic-gate 	uchar_t maxprot,
2719*7c478bd9Sstevel@tonic-gate 	uint_t flags,
2720*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2721*7c478bd9Sstevel@tonic-gate {
2722*7c478bd9Sstevel@tonic-gate 	int error;
2723*7c478bd9Sstevel@tonic-gate 	u_longlong_t delta;
2724*7c478bd9Sstevel@tonic-gate 
2725*7c478bd9Sstevel@tonic-gate 	error = (*(vp)->v_op->vop_addmap)
2726*7c478bd9Sstevel@tonic-gate 			(vp, off, as, addr, len, prot, maxprot, flags, cr);
2727*7c478bd9Sstevel@tonic-gate 
2728*7c478bd9Sstevel@tonic-gate 	if ((!error) && (vp->v_type == VREG)) {
2729*7c478bd9Sstevel@tonic-gate 		delta = (u_longlong_t)btopr(len);
2730*7c478bd9Sstevel@tonic-gate 		/*
2731*7c478bd9Sstevel@tonic-gate 		 * If file is declared MAP_PRIVATE, it can't be written back
2732*7c478bd9Sstevel@tonic-gate 		 * even if open for write. Handle as read.
2733*7c478bd9Sstevel@tonic-gate 		 */
2734*7c478bd9Sstevel@tonic-gate 		if (flags & MAP_PRIVATE) {
2735*7c478bd9Sstevel@tonic-gate 			atomic_add_64((uint64_t *)(&(vp->v_mmap_read)),
2736*7c478bd9Sstevel@tonic-gate 				(int64_t)delta);
2737*7c478bd9Sstevel@tonic-gate 		} else {
2738*7c478bd9Sstevel@tonic-gate 			/*
2739*7c478bd9Sstevel@tonic-gate 			 * atomic_add_64 forces the fetch of a 64 bit value to
2740*7c478bd9Sstevel@tonic-gate 			 * be atomic on 32 bit machines
2741*7c478bd9Sstevel@tonic-gate 			 */
2742*7c478bd9Sstevel@tonic-gate 			if (maxprot & PROT_WRITE)
2743*7c478bd9Sstevel@tonic-gate 				atomic_add_64((uint64_t *)(&(vp->v_mmap_write)),
2744*7c478bd9Sstevel@tonic-gate 					(int64_t)delta);
2745*7c478bd9Sstevel@tonic-gate 			if (maxprot & PROT_READ)
2746*7c478bd9Sstevel@tonic-gate 				atomic_add_64((uint64_t *)(&(vp->v_mmap_read)),
2747*7c478bd9Sstevel@tonic-gate 					(int64_t)delta);
2748*7c478bd9Sstevel@tonic-gate 			if (maxprot & PROT_EXEC)
2749*7c478bd9Sstevel@tonic-gate 				atomic_add_64((uint64_t *)(&(vp->v_mmap_read)),
2750*7c478bd9Sstevel@tonic-gate 					(int64_t)delta);
2751*7c478bd9Sstevel@tonic-gate 		}
2752*7c478bd9Sstevel@tonic-gate 	}
2753*7c478bd9Sstevel@tonic-gate 	return (error);
2754*7c478bd9Sstevel@tonic-gate }
2755*7c478bd9Sstevel@tonic-gate 
2756*7c478bd9Sstevel@tonic-gate int
2757*7c478bd9Sstevel@tonic-gate fop_delmap(
2758*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2759*7c478bd9Sstevel@tonic-gate 	offset_t off,
2760*7c478bd9Sstevel@tonic-gate 	struct as *as,
2761*7c478bd9Sstevel@tonic-gate 	caddr_t addr,
2762*7c478bd9Sstevel@tonic-gate 	size_t len,
2763*7c478bd9Sstevel@tonic-gate 	uint_t prot,
2764*7c478bd9Sstevel@tonic-gate 	uint_t maxprot,
2765*7c478bd9Sstevel@tonic-gate 	uint_t flags,
2766*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2767*7c478bd9Sstevel@tonic-gate {
2768*7c478bd9Sstevel@tonic-gate 	int error;
2769*7c478bd9Sstevel@tonic-gate 	u_longlong_t delta;
2770*7c478bd9Sstevel@tonic-gate 	error = (*(vp)->v_op->vop_delmap)
2771*7c478bd9Sstevel@tonic-gate 		(vp, off, as, addr, len, prot, maxprot, flags, cr);
2772*7c478bd9Sstevel@tonic-gate 
2773*7c478bd9Sstevel@tonic-gate 	/*
2774*7c478bd9Sstevel@tonic-gate 	 * NFS calls into delmap twice, the first time
2775*7c478bd9Sstevel@tonic-gate 	 * it simply establishes a callback mechanism and returns EAGAIN
2776*7c478bd9Sstevel@tonic-gate 	 * while the real work is being done upon the second invocation.
2777*7c478bd9Sstevel@tonic-gate 	 * We have to detect this here and only decrement the counts upon
2778*7c478bd9Sstevel@tonic-gate 	 * the second delmap request.
2779*7c478bd9Sstevel@tonic-gate 	 */
2780*7c478bd9Sstevel@tonic-gate 	if ((error != EAGAIN) && (vp->v_type == VREG)) {
2781*7c478bd9Sstevel@tonic-gate 
2782*7c478bd9Sstevel@tonic-gate 		delta = (u_longlong_t)btopr(len);
2783*7c478bd9Sstevel@tonic-gate 
2784*7c478bd9Sstevel@tonic-gate 		if (flags & MAP_PRIVATE) {
2785*7c478bd9Sstevel@tonic-gate 			atomic_add_64((uint64_t *)(&(vp->v_mmap_read)),
2786*7c478bd9Sstevel@tonic-gate 				(int64_t)(-delta));
2787*7c478bd9Sstevel@tonic-gate 		} else {
2788*7c478bd9Sstevel@tonic-gate 			/*
2789*7c478bd9Sstevel@tonic-gate 			 * atomic_add_64 forces the fetch of a 64 bit value
2790*7c478bd9Sstevel@tonic-gate 			 * to be atomic on 32 bit machines
2791*7c478bd9Sstevel@tonic-gate 			 */
2792*7c478bd9Sstevel@tonic-gate 			if (maxprot & PROT_WRITE)
2793*7c478bd9Sstevel@tonic-gate 				atomic_add_64((uint64_t *)(&(vp->v_mmap_write)),
2794*7c478bd9Sstevel@tonic-gate 					(int64_t)(-delta));
2795*7c478bd9Sstevel@tonic-gate 			if (maxprot & PROT_READ)
2796*7c478bd9Sstevel@tonic-gate 				atomic_add_64((uint64_t *)(&(vp->v_mmap_read)),
2797*7c478bd9Sstevel@tonic-gate 					(int64_t)(-delta));
2798*7c478bd9Sstevel@tonic-gate 			if (maxprot & PROT_EXEC)
2799*7c478bd9Sstevel@tonic-gate 				atomic_add_64((uint64_t *)(&(vp->v_mmap_read)),
2800*7c478bd9Sstevel@tonic-gate 					(int64_t)(-delta));
2801*7c478bd9Sstevel@tonic-gate 		}
2802*7c478bd9Sstevel@tonic-gate 	}
2803*7c478bd9Sstevel@tonic-gate 	return (error);
2804*7c478bd9Sstevel@tonic-gate }
2805*7c478bd9Sstevel@tonic-gate 
2806*7c478bd9Sstevel@tonic-gate 
2807*7c478bd9Sstevel@tonic-gate int
2808*7c478bd9Sstevel@tonic-gate fop_poll(
2809*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2810*7c478bd9Sstevel@tonic-gate 	short events,
2811*7c478bd9Sstevel@tonic-gate 	int anyyet,
2812*7c478bd9Sstevel@tonic-gate 	short *reventsp,
2813*7c478bd9Sstevel@tonic-gate 	struct pollhead **phpp)
2814*7c478bd9Sstevel@tonic-gate {
2815*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_poll)(vp, events, anyyet, reventsp, phpp);
2816*7c478bd9Sstevel@tonic-gate }
2817*7c478bd9Sstevel@tonic-gate 
2818*7c478bd9Sstevel@tonic-gate int
2819*7c478bd9Sstevel@tonic-gate fop_dump(
2820*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2821*7c478bd9Sstevel@tonic-gate 	caddr_t addr,
2822*7c478bd9Sstevel@tonic-gate 	int lbdn,
2823*7c478bd9Sstevel@tonic-gate 	int dblks)
2824*7c478bd9Sstevel@tonic-gate {
2825*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_dump)(vp, addr, lbdn, dblks);
2826*7c478bd9Sstevel@tonic-gate }
2827*7c478bd9Sstevel@tonic-gate 
2828*7c478bd9Sstevel@tonic-gate int
2829*7c478bd9Sstevel@tonic-gate fop_pathconf(
2830*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2831*7c478bd9Sstevel@tonic-gate 	int cmd,
2832*7c478bd9Sstevel@tonic-gate 	ulong_t *valp,
2833*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2834*7c478bd9Sstevel@tonic-gate {
2835*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_pathconf)(vp, cmd, valp, cr);
2836*7c478bd9Sstevel@tonic-gate }
2837*7c478bd9Sstevel@tonic-gate 
2838*7c478bd9Sstevel@tonic-gate int
2839*7c478bd9Sstevel@tonic-gate fop_pageio(
2840*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2841*7c478bd9Sstevel@tonic-gate 	struct page *pp,
2842*7c478bd9Sstevel@tonic-gate 	u_offset_t io_off,
2843*7c478bd9Sstevel@tonic-gate 	size_t io_len,
2844*7c478bd9Sstevel@tonic-gate 	int flags,
2845*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2846*7c478bd9Sstevel@tonic-gate {
2847*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_pageio)(vp, pp, io_off, io_len, flags, cr);
2848*7c478bd9Sstevel@tonic-gate }
2849*7c478bd9Sstevel@tonic-gate 
2850*7c478bd9Sstevel@tonic-gate int
2851*7c478bd9Sstevel@tonic-gate fop_dumpctl(
2852*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2853*7c478bd9Sstevel@tonic-gate 	int action,
2854*7c478bd9Sstevel@tonic-gate 	int *blkp)
2855*7c478bd9Sstevel@tonic-gate {
2856*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_dumpctl)(vp, action, blkp);
2857*7c478bd9Sstevel@tonic-gate }
2858*7c478bd9Sstevel@tonic-gate 
2859*7c478bd9Sstevel@tonic-gate void
2860*7c478bd9Sstevel@tonic-gate fop_dispose(
2861*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2862*7c478bd9Sstevel@tonic-gate 	page_t *pp,
2863*7c478bd9Sstevel@tonic-gate 	int flag,
2864*7c478bd9Sstevel@tonic-gate 	int dn,
2865*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2866*7c478bd9Sstevel@tonic-gate {
2867*7c478bd9Sstevel@tonic-gate 	(*(vp)->v_op->vop_dispose)(vp, pp, flag, dn, cr);
2868*7c478bd9Sstevel@tonic-gate }
2869*7c478bd9Sstevel@tonic-gate 
2870*7c478bd9Sstevel@tonic-gate int
2871*7c478bd9Sstevel@tonic-gate fop_setsecattr(
2872*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2873*7c478bd9Sstevel@tonic-gate 	vsecattr_t *vsap,
2874*7c478bd9Sstevel@tonic-gate 	int flag,
2875*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2876*7c478bd9Sstevel@tonic-gate {
2877*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_setsecattr) (vp, vsap, flag, cr);
2878*7c478bd9Sstevel@tonic-gate }
2879*7c478bd9Sstevel@tonic-gate 
2880*7c478bd9Sstevel@tonic-gate int
2881*7c478bd9Sstevel@tonic-gate fop_getsecattr(
2882*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2883*7c478bd9Sstevel@tonic-gate 	vsecattr_t *vsap,
2884*7c478bd9Sstevel@tonic-gate 	int flag,
2885*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2886*7c478bd9Sstevel@tonic-gate {
2887*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_getsecattr) (vp, vsap, flag, cr);
2888*7c478bd9Sstevel@tonic-gate }
2889*7c478bd9Sstevel@tonic-gate 
2890*7c478bd9Sstevel@tonic-gate int
2891*7c478bd9Sstevel@tonic-gate fop_shrlock(
2892*7c478bd9Sstevel@tonic-gate 	vnode_t *vp,
2893*7c478bd9Sstevel@tonic-gate 	int cmd,
2894*7c478bd9Sstevel@tonic-gate 	struct shrlock *shr,
2895*7c478bd9Sstevel@tonic-gate 	int flag,
2896*7c478bd9Sstevel@tonic-gate 	cred_t *cr)
2897*7c478bd9Sstevel@tonic-gate {
2898*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_shrlock)(vp, cmd, shr, flag, cr);
2899*7c478bd9Sstevel@tonic-gate }
2900*7c478bd9Sstevel@tonic-gate 
2901*7c478bd9Sstevel@tonic-gate int
2902*7c478bd9Sstevel@tonic-gate fop_vnevent(vnode_t *vp, vnevent_t vnevent)
2903*7c478bd9Sstevel@tonic-gate {
2904*7c478bd9Sstevel@tonic-gate 	return (*(vp)->v_op->vop_vnevent)(vp, vnevent);
2905*7c478bd9Sstevel@tonic-gate }
2906