xref: /onnv-gate/usr/src/uts/common/fs/lofs/lofs_vnops.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/param.h>
30*0Sstevel@tonic-gate #include <sys/systm.h>
31*0Sstevel@tonic-gate #include <sys/errno.h>
32*0Sstevel@tonic-gate #include <sys/vnode.h>
33*0Sstevel@tonic-gate #include <sys/vfs.h>
34*0Sstevel@tonic-gate #include <sys/uio.h>
35*0Sstevel@tonic-gate #include <sys/cred.h>
36*0Sstevel@tonic-gate #include <sys/pathname.h>
37*0Sstevel@tonic-gate #include <sys/debug.h>
38*0Sstevel@tonic-gate #include <sys/fs/lofs_node.h>
39*0Sstevel@tonic-gate #include <sys/fs/lofs_info.h>
40*0Sstevel@tonic-gate #include <fs/fs_subr.h>
41*0Sstevel@tonic-gate #include <vm/as.h>
42*0Sstevel@tonic-gate #include <vm/seg.h>
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate #define	IS_ZONEDEVFS(vp) \
45*0Sstevel@tonic-gate 	(vtoli((vp)->v_vfsp)->li_flag & LO_ZONEDEVFS)
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate /*
48*0Sstevel@tonic-gate  * These are the vnode ops routines which implement the vnode interface to
49*0Sstevel@tonic-gate  * the looped-back file system.  These routines just take their parameters,
50*0Sstevel@tonic-gate  * and then calling the appropriate real vnode routine(s) to do the work.
51*0Sstevel@tonic-gate  */
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate static int
54*0Sstevel@tonic-gate lo_open(vnode_t **vpp, int flag, struct cred *cr)
55*0Sstevel@tonic-gate {
56*0Sstevel@tonic-gate 	vnode_t *vp = *vpp;
57*0Sstevel@tonic-gate 	vnode_t *rvp;
58*0Sstevel@tonic-gate 	vnode_t *oldvp;
59*0Sstevel@tonic-gate 	int error;
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate #ifdef LODEBUG
62*0Sstevel@tonic-gate 	lo_dprint(4, "lo_open vp %p cnt=%d realvp %p cnt=%d\n",
63*0Sstevel@tonic-gate 		vp, vp->v_count, realvp(vp), realvp(vp)->v_count);
64*0Sstevel@tonic-gate #endif
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate 	oldvp = vp;
67*0Sstevel@tonic-gate 	vp = rvp = realvp(vp);
68*0Sstevel@tonic-gate 	/*
69*0Sstevel@tonic-gate 	 * Need to hold new reference to vp since VOP_OPEN() may
70*0Sstevel@tonic-gate 	 * decide to release it.
71*0Sstevel@tonic-gate 	 */
72*0Sstevel@tonic-gate 	VN_HOLD(vp);
73*0Sstevel@tonic-gate 	error = VOP_OPEN(&rvp, flag, cr);
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate 	if (!error && rvp != vp) {
76*0Sstevel@tonic-gate 		/*
77*0Sstevel@tonic-gate 		 * the FS which we called should have released the
78*0Sstevel@tonic-gate 		 * new reference on vp
79*0Sstevel@tonic-gate 		 */
80*0Sstevel@tonic-gate 		*vpp = makelonode(rvp, vtoli(oldvp->v_vfsp));
81*0Sstevel@tonic-gate 		if (IS_DEVVP(*vpp)) {
82*0Sstevel@tonic-gate 			vnode_t *svp;
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate 			svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
85*0Sstevel@tonic-gate 			VN_RELE(*vpp);
86*0Sstevel@tonic-gate 			if (svp == NULL)
87*0Sstevel@tonic-gate 				error = ENOSYS;
88*0Sstevel@tonic-gate 			else
89*0Sstevel@tonic-gate 				*vpp = svp;
90*0Sstevel@tonic-gate 		}
91*0Sstevel@tonic-gate 		VN_RELE(oldvp);
92*0Sstevel@tonic-gate 	} else {
93*0Sstevel@tonic-gate 		ASSERT(rvp->v_count > 1);
94*0Sstevel@tonic-gate 		VN_RELE(rvp);
95*0Sstevel@tonic-gate 	}
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 	return (error);
98*0Sstevel@tonic-gate }
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate static int
101*0Sstevel@tonic-gate lo_close(
102*0Sstevel@tonic-gate 	vnode_t *vp,
103*0Sstevel@tonic-gate 	int flag,
104*0Sstevel@tonic-gate 	int count,
105*0Sstevel@tonic-gate 	offset_t offset,
106*0Sstevel@tonic-gate 	struct cred *cr)
107*0Sstevel@tonic-gate {
108*0Sstevel@tonic-gate #ifdef LODEBUG
109*0Sstevel@tonic-gate 	lo_dprint(4, "lo_close vp %p realvp %p\n", vp, realvp(vp));
110*0Sstevel@tonic-gate #endif
111*0Sstevel@tonic-gate 	vp = realvp(vp);
112*0Sstevel@tonic-gate 	return (VOP_CLOSE(vp, flag, count, offset, cr));
113*0Sstevel@tonic-gate }
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate static int
116*0Sstevel@tonic-gate lo_read(vnode_t *vp, struct uio *uiop, int ioflag, struct cred *cr,
117*0Sstevel@tonic-gate 	caller_context_t *ct)
118*0Sstevel@tonic-gate {
119*0Sstevel@tonic-gate #ifdef LODEBUG
120*0Sstevel@tonic-gate 	lo_dprint(4, "lo_read vp %p realvp %p\n", vp, realvp(vp));
121*0Sstevel@tonic-gate #endif
122*0Sstevel@tonic-gate 	vp = realvp(vp);
123*0Sstevel@tonic-gate 	return (VOP_READ(vp, uiop, ioflag, cr, ct));
124*0Sstevel@tonic-gate }
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate static int
127*0Sstevel@tonic-gate lo_write(vnode_t *vp, struct uio *uiop, int ioflag, struct cred *cr,
128*0Sstevel@tonic-gate 	caller_context_t *ct)
129*0Sstevel@tonic-gate {
130*0Sstevel@tonic-gate #ifdef LODEBUG
131*0Sstevel@tonic-gate 	lo_dprint(4, "lo_write vp %p realvp %p\n", vp, realvp(vp));
132*0Sstevel@tonic-gate #endif
133*0Sstevel@tonic-gate 	vp = realvp(vp);
134*0Sstevel@tonic-gate 	return (VOP_WRITE(vp, uiop, ioflag, cr, ct));
135*0Sstevel@tonic-gate }
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate static int
138*0Sstevel@tonic-gate lo_ioctl(
139*0Sstevel@tonic-gate 	vnode_t *vp,
140*0Sstevel@tonic-gate 	int cmd,
141*0Sstevel@tonic-gate 	intptr_t arg,
142*0Sstevel@tonic-gate 	int flag,
143*0Sstevel@tonic-gate 	struct cred *cr,
144*0Sstevel@tonic-gate 	int *rvalp)
145*0Sstevel@tonic-gate {
146*0Sstevel@tonic-gate #ifdef LODEBUG
147*0Sstevel@tonic-gate 	lo_dprint(4, "lo_ioctl vp %p realvp %p\n", vp, realvp(vp));
148*0Sstevel@tonic-gate #endif
149*0Sstevel@tonic-gate 	vp = realvp(vp);
150*0Sstevel@tonic-gate 	return (VOP_IOCTL(vp, cmd, arg, flag, cr, rvalp));
151*0Sstevel@tonic-gate }
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate static int
154*0Sstevel@tonic-gate lo_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
155*0Sstevel@tonic-gate {
156*0Sstevel@tonic-gate 	vp = realvp(vp);
157*0Sstevel@tonic-gate 	return (VOP_SETFL(vp, oflags, nflags, cr));
158*0Sstevel@tonic-gate }
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate static int
161*0Sstevel@tonic-gate lo_getattr(
162*0Sstevel@tonic-gate 	vnode_t *vp,
163*0Sstevel@tonic-gate 	struct vattr *vap,
164*0Sstevel@tonic-gate 	int flags,
165*0Sstevel@tonic-gate 	struct cred *cr)
166*0Sstevel@tonic-gate {
167*0Sstevel@tonic-gate 	int error;
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate #ifdef LODEBUG
170*0Sstevel@tonic-gate 	lo_dprint(4, "lo_getattr vp %p realvp %p\n", vp, realvp(vp));
171*0Sstevel@tonic-gate #endif
172*0Sstevel@tonic-gate 	if (error = VOP_GETATTR(realvp(vp), vap, flags, cr))
173*0Sstevel@tonic-gate 		return (error);
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	/*
176*0Sstevel@tonic-gate 	 * In zonedevfs mode, we pull a nasty trick; we make sure that
177*0Sstevel@tonic-gate 	 * the dev_t does *not* reflect the underlying device, so that
178*0Sstevel@tonic-gate 	 * no renames can occur to or from the /dev hierarchy.
179*0Sstevel@tonic-gate 	 */
180*0Sstevel@tonic-gate 	if (IS_ZONEDEVFS(vp)) {
181*0Sstevel@tonic-gate 		vap->va_fsid = expldev(vp->v_vfsp->vfs_fsid.val[0]);
182*0Sstevel@tonic-gate 	}
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	return (0);
185*0Sstevel@tonic-gate }
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate static int
188*0Sstevel@tonic-gate lo_setattr(
189*0Sstevel@tonic-gate 	vnode_t *vp,
190*0Sstevel@tonic-gate 	struct vattr *vap,
191*0Sstevel@tonic-gate 	int flags,
192*0Sstevel@tonic-gate 	struct cred *cr,
193*0Sstevel@tonic-gate 	caller_context_t *ct)
194*0Sstevel@tonic-gate {
195*0Sstevel@tonic-gate #ifdef LODEBUG
196*0Sstevel@tonic-gate 	lo_dprint(4, "lo_setattr vp %p realvp %p\n", vp, realvp(vp));
197*0Sstevel@tonic-gate #endif
198*0Sstevel@tonic-gate 	if (IS_ZONEDEVFS(vp) && !IS_DEVVP(vp)) {
199*0Sstevel@tonic-gate 		return (EACCES);
200*0Sstevel@tonic-gate 	}
201*0Sstevel@tonic-gate 	vp = realvp(vp);
202*0Sstevel@tonic-gate 	return (VOP_SETATTR(vp, vap, flags, cr, ct));
203*0Sstevel@tonic-gate }
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate static int
206*0Sstevel@tonic-gate lo_access(vnode_t *vp, int mode, int flags, struct cred *cr)
207*0Sstevel@tonic-gate {
208*0Sstevel@tonic-gate #ifdef LODEBUG
209*0Sstevel@tonic-gate 	lo_dprint(4, "lo_access vp %p realvp %p\n", vp, realvp(vp));
210*0Sstevel@tonic-gate #endif
211*0Sstevel@tonic-gate 	if (mode & VWRITE) {
212*0Sstevel@tonic-gate 		if (vp->v_type == VREG && vn_is_readonly(vp))
213*0Sstevel@tonic-gate 			return (EROFS);
214*0Sstevel@tonic-gate 		if (IS_ZONEDEVFS(vp) && !IS_DEVVP(vp))
215*0Sstevel@tonic-gate 			return (EACCES);
216*0Sstevel@tonic-gate 	}
217*0Sstevel@tonic-gate 	vp = realvp(vp);
218*0Sstevel@tonic-gate 	return (VOP_ACCESS(vp, mode, flags, cr));
219*0Sstevel@tonic-gate }
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate static int
222*0Sstevel@tonic-gate lo_fsync(vnode_t *vp, int syncflag, struct cred *cr)
223*0Sstevel@tonic-gate {
224*0Sstevel@tonic-gate #ifdef LODEBUG
225*0Sstevel@tonic-gate 	lo_dprint(4, "lo_fsync vp %p realvp %p\n", vp, realvp(vp));
226*0Sstevel@tonic-gate #endif
227*0Sstevel@tonic-gate 	vp = realvp(vp);
228*0Sstevel@tonic-gate 	return (VOP_FSYNC(vp, syncflag, cr));
229*0Sstevel@tonic-gate }
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate /*ARGSUSED*/
232*0Sstevel@tonic-gate static void
233*0Sstevel@tonic-gate lo_inactive(vnode_t *vp, struct cred *cr)
234*0Sstevel@tonic-gate {
235*0Sstevel@tonic-gate #ifdef LODEBUG
236*0Sstevel@tonic-gate 	lo_dprint(4, "lo_inactive %p, realvp %p\n", vp, realvp(vp));
237*0Sstevel@tonic-gate #endif
238*0Sstevel@tonic-gate 	freelonode(vtol(vp));
239*0Sstevel@tonic-gate }
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate /* ARGSUSED */
242*0Sstevel@tonic-gate static int
243*0Sstevel@tonic-gate lo_fid(vnode_t *vp, struct fid *fidp)
244*0Sstevel@tonic-gate {
245*0Sstevel@tonic-gate #ifdef LODEBUG
246*0Sstevel@tonic-gate 	lo_dprint(4, "lo_fid %p, realvp %p\n", vp, realvp(vp));
247*0Sstevel@tonic-gate #endif
248*0Sstevel@tonic-gate 	vp = realvp(vp);
249*0Sstevel@tonic-gate 	return (VOP_FID(vp, fidp));
250*0Sstevel@tonic-gate }
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate /*
253*0Sstevel@tonic-gate  * Given a vnode of lofs type, lookup nm name and
254*0Sstevel@tonic-gate  * return a shadow vnode (of lofs type) of the
255*0Sstevel@tonic-gate  * real vnode found.
256*0Sstevel@tonic-gate  *
257*0Sstevel@tonic-gate  * Due to the nature of lofs, there is a potential
258*0Sstevel@tonic-gate  * looping in path traversal.
259*0Sstevel@tonic-gate  *
260*0Sstevel@tonic-gate  * starting from the mount point of an lofs;
261*0Sstevel@tonic-gate  * a loop is defined to be a traversal path
262*0Sstevel@tonic-gate  * where the mount point or the real vnode of
263*0Sstevel@tonic-gate  * the root of this lofs is encountered twice.
264*0Sstevel@tonic-gate  * Once at the start of traversal and second
265*0Sstevel@tonic-gate  * when the looping is found.
266*0Sstevel@tonic-gate  *
267*0Sstevel@tonic-gate  * When a loop is encountered, a shadow of the
268*0Sstevel@tonic-gate  * covered vnode is returned to stop the looping.
269*0Sstevel@tonic-gate  *
270*0Sstevel@tonic-gate  * This normally works, but with the advent of
271*0Sstevel@tonic-gate  * the new automounter, returning the shadow of the
272*0Sstevel@tonic-gate  * covered vnode (autonode, in this case) does not
273*0Sstevel@tonic-gate  * stop the loop.  Because further lookup on this
274*0Sstevel@tonic-gate  * lonode will cause the autonode to call lo_lookup()
275*0Sstevel@tonic-gate  * on the lonode covering it.
276*0Sstevel@tonic-gate  *
277*0Sstevel@tonic-gate  * example "/net/jurassic/net/jurassic" is a loop.
278*0Sstevel@tonic-gate  * returning the shadow of the autonode corresponding to
279*0Sstevel@tonic-gate  * "/net/jurassic/net/jurassic" will not terminate the
280*0Sstevel@tonic-gate  * loop.   To solve this problem we allow the loop to go
281*0Sstevel@tonic-gate  * through one more level component lookup.  If it hit
282*0Sstevel@tonic-gate  * "net" after the loop as in "/net/jurassic/net/jurassic/net",
283*0Sstevel@tonic-gate  * then returning the vnode covered by the autonode "net"
284*0Sstevel@tonic-gate  * will terminate the loop.
285*0Sstevel@tonic-gate  *
286*0Sstevel@tonic-gate  * Lookup for dot dot has to be dealt with separately.
287*0Sstevel@tonic-gate  * It will be nice to have a "one size fits all" kind
288*0Sstevel@tonic-gate  * of solution, so that we don't have so many ifs statement
289*0Sstevel@tonic-gate  * in the lo_lookup() to handle dotdot.  But, since
290*0Sstevel@tonic-gate  * there are so many special cases to handle different
291*0Sstevel@tonic-gate  * kinds looping above, we need special codes to handle
292*0Sstevel@tonic-gate  * dotdot lookup as well.
293*0Sstevel@tonic-gate  */
294*0Sstevel@tonic-gate static int
295*0Sstevel@tonic-gate lo_lookup(
296*0Sstevel@tonic-gate 	vnode_t *dvp,
297*0Sstevel@tonic-gate 	char *nm,
298*0Sstevel@tonic-gate 	vnode_t **vpp,
299*0Sstevel@tonic-gate 	struct pathname *pnp,
300*0Sstevel@tonic-gate 	int flags,
301*0Sstevel@tonic-gate 	vnode_t *rdir,
302*0Sstevel@tonic-gate 	struct cred *cr)
303*0Sstevel@tonic-gate {
304*0Sstevel@tonic-gate 	vnode_t *vp = NULL, *tvp = NULL, *nonlovp;
305*0Sstevel@tonic-gate 	int error, is_indirectloop;
306*0Sstevel@tonic-gate 	vnode_t *realdvp = realvp(dvp);
307*0Sstevel@tonic-gate 	struct loinfo *li = vtoli(dvp->v_vfsp);
308*0Sstevel@tonic-gate 	int looping = 0;
309*0Sstevel@tonic-gate 	int doingdotdot = 0;
310*0Sstevel@tonic-gate 	int nosub = 0;
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	/*
313*0Sstevel@tonic-gate 	 * If name is empty and no XATTR flags are set, then return
314*0Sstevel@tonic-gate 	 * dvp (empty name == lookup ".").  If an XATTR flag is set
315*0Sstevel@tonic-gate 	 * then we need to call VOP_LOOKUP to get the xattr dir.
316*0Sstevel@tonic-gate 	 */
317*0Sstevel@tonic-gate 	if (nm[0] == '\0' && ! (flags & (CREATE_XATTR_DIR|LOOKUP_XATTR))) {
318*0Sstevel@tonic-gate 		VN_HOLD(dvp);
319*0Sstevel@tonic-gate 		*vpp = dvp;
320*0Sstevel@tonic-gate 		return (0);
321*0Sstevel@tonic-gate 	}
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 	if (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0') {
324*0Sstevel@tonic-gate 		doingdotdot++;
325*0Sstevel@tonic-gate 		/*
326*0Sstevel@tonic-gate 		 * Handle ".." out of mounted filesystem
327*0Sstevel@tonic-gate 		 */
328*0Sstevel@tonic-gate 		while ((realdvp->v_flag & VROOT) && realdvp != rootdir) {
329*0Sstevel@tonic-gate 			realdvp = realdvp->v_vfsp->vfs_vnodecovered;
330*0Sstevel@tonic-gate 			ASSERT(realdvp != NULL);
331*0Sstevel@tonic-gate 		}
332*0Sstevel@tonic-gate 	}
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 	*vpp = NULL;	/* default(error) case */
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	/*
337*0Sstevel@tonic-gate 	 * Do the normal lookup
338*0Sstevel@tonic-gate 	 */
339*0Sstevel@tonic-gate 	if (error = VOP_LOOKUP(realdvp, nm, &vp, pnp, flags, rdir, cr))
340*0Sstevel@tonic-gate 		goto out;
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	/*
343*0Sstevel@tonic-gate 	 * We do this check here to avoid returning a stale file handle to the
344*0Sstevel@tonic-gate 	 * caller.
345*0Sstevel@tonic-gate 	 */
346*0Sstevel@tonic-gate 	if (nm[0] == '.' && nm[1] == '\0') {
347*0Sstevel@tonic-gate 		ASSERT(vp == realdvp);
348*0Sstevel@tonic-gate 		VN_HOLD(dvp);
349*0Sstevel@tonic-gate 		VN_RELE(vp);
350*0Sstevel@tonic-gate 		*vpp = dvp;
351*0Sstevel@tonic-gate 		return (0);
352*0Sstevel@tonic-gate 	}
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 	if (doingdotdot) {
355*0Sstevel@tonic-gate 		if ((vtol(dvp))->lo_looping) {
356*0Sstevel@tonic-gate 			vfs_t *vfsp;
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 			error = vn_vfswlock_wait(realdvp);
359*0Sstevel@tonic-gate 			if (error)
360*0Sstevel@tonic-gate 				goto out;
361*0Sstevel@tonic-gate 			vfsp = vn_mountedvfs(realdvp);
362*0Sstevel@tonic-gate 			if (vfsp != NULL) {
363*0Sstevel@tonic-gate 				/*
364*0Sstevel@tonic-gate 				 * if looping get the actual found vnode
365*0Sstevel@tonic-gate 				 * instead of the vnode covered
366*0Sstevel@tonic-gate 				 * Here we have to hold the lock for realdvp
367*0Sstevel@tonic-gate 				 * since an unmount during the traversal to the
368*0Sstevel@tonic-gate 				 * root vnode would turn *vfsp into garbage
369*0Sstevel@tonic-gate 				 * which would be fatal.
370*0Sstevel@tonic-gate 				 */
371*0Sstevel@tonic-gate 				vfs_lock_wait(vfsp);
372*0Sstevel@tonic-gate 				vn_vfsunlock(realdvp);
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 				error = VFS_ROOT(vfsp, &tvp);
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 				vfs_unlock(vfsp);
377*0Sstevel@tonic-gate 				if (error)
378*0Sstevel@tonic-gate 					goto out;
379*0Sstevel@tonic-gate 				if ((tvp == li->li_rootvp)&&
380*0Sstevel@tonic-gate 				    (vp == realvp(tvp))) {
381*0Sstevel@tonic-gate 					/*
382*0Sstevel@tonic-gate 					 * we're back at the real vnode
383*0Sstevel@tonic-gate 					 * of the rootvp
384*0Sstevel@tonic-gate 					 *
385*0Sstevel@tonic-gate 					 * return the rootvp
386*0Sstevel@tonic-gate 					 * Ex: /mnt/mnt/..
387*0Sstevel@tonic-gate 					 * where / has been lofs-mounted
388*0Sstevel@tonic-gate 					 * onto /mnt.  Return the lofs
389*0Sstevel@tonic-gate 					 * node mounted at /mnt.
390*0Sstevel@tonic-gate 					 */
391*0Sstevel@tonic-gate 					*vpp = tvp;
392*0Sstevel@tonic-gate 					VN_RELE(vp);
393*0Sstevel@tonic-gate 					return (0);
394*0Sstevel@tonic-gate 				} else {
395*0Sstevel@tonic-gate 					/*
396*0Sstevel@tonic-gate 					 * We are returning from a covered
397*0Sstevel@tonic-gate 					 * node whose vfs_mountedhere is
398*0Sstevel@tonic-gate 					 * not pointing to vfs of the current
399*0Sstevel@tonic-gate 					 * root vnode.
400*0Sstevel@tonic-gate 					 * This is a condn where in we
401*0Sstevel@tonic-gate 					 * returned a covered node say Zc
402*0Sstevel@tonic-gate 					 * but Zc is not the cover of current
403*0Sstevel@tonic-gate 					 * root.
404*0Sstevel@tonic-gate 					 * i.e.., if X is the root vnode
405*0Sstevel@tonic-gate 					 * lookup(Zc,"..") is taking us to
406*0Sstevel@tonic-gate 					 * X.
407*0Sstevel@tonic-gate 					 * Ex: /net/X/net/X/net
408*0Sstevel@tonic-gate 					 * We are encountering cover of net.
409*0Sstevel@tonic-gate 					 * doing a dotdot from here means we
410*0Sstevel@tonic-gate 					 * to take the lookup to the same state
411*0Sstevel@tonic-gate 					 * that would have happened when we do
412*0Sstevel@tonic-gate 					 * lookup of any Y under /net/X/net/X
413*0Sstevel@tonic-gate 					 */
414*0Sstevel@tonic-gate 					VN_RELE(tvp);
415*0Sstevel@tonic-gate 					if (vp == realvp(li->li_rootvp)) {
416*0Sstevel@tonic-gate 						VN_RELE(vp);
417*0Sstevel@tonic-gate 						vp = li->li_rootvp;
418*0Sstevel@tonic-gate 						vp = vp->v_vfsp->
419*0Sstevel@tonic-gate 							vfs_vnodecovered;
420*0Sstevel@tonic-gate 						VN_HOLD(vp);
421*0Sstevel@tonic-gate 						*vpp = makelonode(vp, li);
422*0Sstevel@tonic-gate 						(vtol(*vpp))->lo_looping = 1;
423*0Sstevel@tonic-gate 						return (0);
424*0Sstevel@tonic-gate 					}
425*0Sstevel@tonic-gate 				}
426*0Sstevel@tonic-gate 			} else {
427*0Sstevel@tonic-gate 				/*
428*0Sstevel@tonic-gate 				 * We are returning from a looping dvp.
429*0Sstevel@tonic-gate 				 * If we are returning to rootvp return
430*0Sstevel@tonic-gate 				 * the covered node with looping bit set.
431*0Sstevel@tonic-gate 				 *
432*0Sstevel@tonic-gate 				 * This means we are not returning from cover
433*0Sstevel@tonic-gate 				 * but we should return to the root node by
434*0Sstevel@tonic-gate 				 * giving the covered node with looping flag
435*0Sstevel@tonic-gate 				 * set. We are returning from a non-covernode
436*0Sstevel@tonic-gate 				 * with looping bit set means we couldn't stop
437*0Sstevel@tonic-gate 				 * by giving the cover of root vnode.
438*0Sstevel@tonic-gate 				 *
439*0Sstevel@tonic-gate 				 *	Say X is the root vnode and lookup of
440*0Sstevel@tonic-gate 				 * X again under X returns Xc(due to looping
441*0Sstevel@tonic-gate 				 * condn). let Z=lookup(Xc,"path") and
442*0Sstevel@tonic-gate 				 * if lookup(Z,"..") returns  the root vp X
443*0Sstevel@tonic-gate 				 * return Xc with looping bit set or if a new
444*0Sstevel@tonic-gate 				 * node Z.. is returned make a shadow with a
445*0Sstevel@tonic-gate 				 * looping flag.
446*0Sstevel@tonic-gate 				 *
447*0Sstevel@tonic-gate 				 * Ex:- lookup of /net/X/net/X/Y/.. or
448*0Sstevel@tonic-gate 				 * lookup of /net/X/net/X/Y/Z/.. .
449*0Sstevel@tonic-gate 				 * In the first case we are returning to root
450*0Sstevel@tonic-gate 				 * we will return the cover of root with
451*0Sstevel@tonic-gate 				 * looping bit set.
452*0Sstevel@tonic-gate 				 */
453*0Sstevel@tonic-gate 				vn_vfsunlock(realdvp);
454*0Sstevel@tonic-gate 				if (vp == li->li_rootvp) {
455*0Sstevel@tonic-gate 					tvp = vp;
456*0Sstevel@tonic-gate 					vp = (vp)->v_vfsp->vfs_vnodecovered;
457*0Sstevel@tonic-gate 					VN_RELE(tvp);
458*0Sstevel@tonic-gate 					VN_HOLD(vp);
459*0Sstevel@tonic-gate 				}
460*0Sstevel@tonic-gate 				*vpp = makelonode(vp, li);
461*0Sstevel@tonic-gate 				(vtol(*vpp))->lo_looping = 1;
462*0Sstevel@tonic-gate 				return (0);
463*0Sstevel@tonic-gate 			}
464*0Sstevel@tonic-gate 		} else {
465*0Sstevel@tonic-gate 			/*
466*0Sstevel@tonic-gate 			 * No frills just make the shadow node.
467*0Sstevel@tonic-gate 			 */
468*0Sstevel@tonic-gate 			*vpp = makelonode(vp, li);
469*0Sstevel@tonic-gate 			return (0);
470*0Sstevel@tonic-gate 		}
471*0Sstevel@tonic-gate 	}
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate 	nosub = (vtoli(dvp->v_vfsp)->li_flag & LO_NOSUB);
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 	/*
476*0Sstevel@tonic-gate 	 * If this vnode is mounted on, then we
477*0Sstevel@tonic-gate 	 * traverse to the vnode which is the root of
478*0Sstevel@tonic-gate 	 * the mounted file system.
479*0Sstevel@tonic-gate 	 */
480*0Sstevel@tonic-gate 	if (!nosub && (error = traverse(&vp)))
481*0Sstevel@tonic-gate 		goto out;
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	/*
484*0Sstevel@tonic-gate 	 * Make a lnode for the real vnode.
485*0Sstevel@tonic-gate 	 */
486*0Sstevel@tonic-gate 	if (vp->v_type != VDIR || nosub) {
487*0Sstevel@tonic-gate 		*vpp = makelonode(vp, li);
488*0Sstevel@tonic-gate 		if (IS_DEVVP(*vpp)) {
489*0Sstevel@tonic-gate 			vnode_t *svp;
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 			svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
492*0Sstevel@tonic-gate 			VN_RELE(*vpp);
493*0Sstevel@tonic-gate 			if (svp == NULL)
494*0Sstevel@tonic-gate 				error = ENOSYS;
495*0Sstevel@tonic-gate 			else
496*0Sstevel@tonic-gate 				*vpp = svp;
497*0Sstevel@tonic-gate 		}
498*0Sstevel@tonic-gate 		return (error);
499*0Sstevel@tonic-gate 	}
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate 	/*
502*0Sstevel@tonic-gate 	 * if the found vnode (vp) is not of type lofs
503*0Sstevel@tonic-gate 	 * then we're just going to make a shadow of that
504*0Sstevel@tonic-gate 	 * vp and get out.
505*0Sstevel@tonic-gate 	 *
506*0Sstevel@tonic-gate 	 * If the found vnode (vp) is of lofs type, and
507*0Sstevel@tonic-gate 	 * we're not doing dotdot, check if we are
508*0Sstevel@tonic-gate 	 * looping.
509*0Sstevel@tonic-gate 	 */
510*0Sstevel@tonic-gate 	if (!doingdotdot && vfs_matchops(vp->v_vfsp, lo_vfsops)) {
511*0Sstevel@tonic-gate 		/*
512*0Sstevel@tonic-gate 		 * Check if we're looping, i.e.
513*0Sstevel@tonic-gate 		 * vp equals the root vp of the lofs, directly
514*0Sstevel@tonic-gate 		 * or indirectly, return the covered node.
515*0Sstevel@tonic-gate 		 */
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 		if (!(vtol(dvp))->lo_looping) {
518*0Sstevel@tonic-gate 			if (vp == li->li_rootvp) {
519*0Sstevel@tonic-gate 				/*
520*0Sstevel@tonic-gate 				 * Direct looping condn.
521*0Sstevel@tonic-gate 				 * Ex:- X is / mounted directory so lookup of
522*0Sstevel@tonic-gate 				 * /X/X is a direct looping condn.
523*0Sstevel@tonic-gate 				 */
524*0Sstevel@tonic-gate 				tvp = vp;
525*0Sstevel@tonic-gate 				vp = vp->v_vfsp->vfs_vnodecovered;
526*0Sstevel@tonic-gate 				VN_HOLD(vp);
527*0Sstevel@tonic-gate 				VN_RELE(tvp);
528*0Sstevel@tonic-gate 				looping++;
529*0Sstevel@tonic-gate 			} else {
530*0Sstevel@tonic-gate 				/*
531*0Sstevel@tonic-gate 				 * Indirect looping can be defined as
532*0Sstevel@tonic-gate 				 * real lookup returning rootvp of the current
533*0Sstevel@tonic-gate 				 * tree in any level of recursion.
534*0Sstevel@tonic-gate 				 *
535*0Sstevel@tonic-gate 				 * This check is useful if there are multiple
536*0Sstevel@tonic-gate 				 * levels of lofs indirections. Suppose vnode X
537*0Sstevel@tonic-gate 				 * in the current lookup has as its real vnode
538*0Sstevel@tonic-gate 				 * another lofs node. Y = realvp(X) Y should be
539*0Sstevel@tonic-gate 				 * a lofs node for the check to continue or Y
540*0Sstevel@tonic-gate 				 * is not the rootvp of X.
541*0Sstevel@tonic-gate 				 * Ex:- say X and Y are two vnodes
542*0Sstevel@tonic-gate 				 * say real(Y) is X and real(X) is Z
543*0Sstevel@tonic-gate 				 * parent vnode for X and Y is Z
544*0Sstevel@tonic-gate 				 * lookup(Y,"path") say we are looking for Y
545*0Sstevel@tonic-gate 				 * again under Y and we have to return Yc.
546*0Sstevel@tonic-gate 				 * but the lookup of Y under Y doesnot return
547*0Sstevel@tonic-gate 				 * Y the root vnode again here is why.
548*0Sstevel@tonic-gate 				 * 1. lookup(Y,"path of Y") will go to
549*0Sstevel@tonic-gate 				 * 2. lookup(real(Y),"path of Y") and then to
550*0Sstevel@tonic-gate 				 * 3. lookup(real(X),"path of Y").
551*0Sstevel@tonic-gate 				 * and now what lookup level 1 sees is the
552*0Sstevel@tonic-gate 				 * outcome of 2 but the vnode Y is due to
553*0Sstevel@tonic-gate 				 * lookup(Z,"path of Y") so we have to skip
554*0Sstevel@tonic-gate 				 * intermediate levels to find if in any level
555*0Sstevel@tonic-gate 				 * there is a looping.
556*0Sstevel@tonic-gate 				 */
557*0Sstevel@tonic-gate 				is_indirectloop = 0;
558*0Sstevel@tonic-gate 				nonlovp = vp;
559*0Sstevel@tonic-gate 				while (
560*0Sstevel@tonic-gate 				    vfs_matchops(nonlovp->v_vfsp, lo_vfsops) &&
561*0Sstevel@tonic-gate 				    !(is_indirectloop)) {
562*0Sstevel@tonic-gate 					if (li->li_rootvp  == nonlovp) {
563*0Sstevel@tonic-gate 						is_indirectloop++;
564*0Sstevel@tonic-gate 						break;
565*0Sstevel@tonic-gate 					}
566*0Sstevel@tonic-gate 					nonlovp = realvp(nonlovp);
567*0Sstevel@tonic-gate 				}
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate 				if (is_indirectloop) {
570*0Sstevel@tonic-gate 					VN_RELE(vp);
571*0Sstevel@tonic-gate 					vp = nonlovp;
572*0Sstevel@tonic-gate 					vp = vp->v_vfsp->vfs_vnodecovered;
573*0Sstevel@tonic-gate 					VN_HOLD(vp);
574*0Sstevel@tonic-gate 					looping++;
575*0Sstevel@tonic-gate 				}
576*0Sstevel@tonic-gate 			}
577*0Sstevel@tonic-gate 		} else {
578*0Sstevel@tonic-gate 			/*
579*0Sstevel@tonic-gate 			 * come here only because of the interaction between
580*0Sstevel@tonic-gate 			 * the autofs and lofs.
581*0Sstevel@tonic-gate 			 *
582*0Sstevel@tonic-gate 			 * Lookup of "/net/X/net/X" will return a shadow of
583*0Sstevel@tonic-gate 			 * an autonode X_a which we call X_l.
584*0Sstevel@tonic-gate 			 *
585*0Sstevel@tonic-gate 			 * Lookup of anything under X_l, will trigger a call to
586*0Sstevel@tonic-gate 			 * auto_lookup(X_a,nm) which will eventually call
587*0Sstevel@tonic-gate 			 * lo_lookup(X_lr,nm) where X_lr is the root vnode of
588*0Sstevel@tonic-gate 			 * the current lofs.
589*0Sstevel@tonic-gate 			 *
590*0Sstevel@tonic-gate 			 * We come here only when we are called with X_l as dvp
591*0Sstevel@tonic-gate 			 * and look for something underneath.
592*0Sstevel@tonic-gate 			 *
593*0Sstevel@tonic-gate 			 * We need to find out if the vnode, which vp is
594*0Sstevel@tonic-gate 			 * shadowing, is the rootvp of the autofs.
595*0Sstevel@tonic-gate 			 *
596*0Sstevel@tonic-gate 			 */
597*0Sstevel@tonic-gate 			realdvp = realvp(dvp);
598*0Sstevel@tonic-gate 			while (vfs_matchops(realdvp->v_vfsp, lo_vfsops)) {
599*0Sstevel@tonic-gate 				realdvp = realvp(realdvp);
600*0Sstevel@tonic-gate 			}
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 			error = VFS_ROOT(realdvp->v_vfsp, &tvp);
603*0Sstevel@tonic-gate 			if (error)
604*0Sstevel@tonic-gate 				goto out;
605*0Sstevel@tonic-gate 			/*
606*0Sstevel@tonic-gate 			 * tvp now contains the rootvp of the vfs of the
607*0Sstevel@tonic-gate 			 * real vnode of dvp
608*0Sstevel@tonic-gate 			 */
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 			if (realvp(dvp)->v_vfsp == realvp(vp)->v_vfsp &&
611*0Sstevel@tonic-gate 			    tvp == realvp(vp)) {
612*0Sstevel@tonic-gate 				/*
613*0Sstevel@tonic-gate 				 * vp is the shadow of "net",
614*0Sstevel@tonic-gate 				 * the rootvp of autofs
615*0Sstevel@tonic-gate 				 */
616*0Sstevel@tonic-gate 				VN_RELE(vp);
617*0Sstevel@tonic-gate 				vp = tvp;	/* this is an autonode */
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 				/*
620*0Sstevel@tonic-gate 				 * Need to find the covered vnode
621*0Sstevel@tonic-gate 				 */
622*0Sstevel@tonic-gate 				vp = vp->v_vfsp->vfs_vnodecovered;
623*0Sstevel@tonic-gate 				ASSERT(vp);
624*0Sstevel@tonic-gate 				VN_HOLD(vp);
625*0Sstevel@tonic-gate 				VN_RELE(tvp);
626*0Sstevel@tonic-gate 			} else {
627*0Sstevel@tonic-gate 				VN_RELE(tvp);
628*0Sstevel@tonic-gate 			}
629*0Sstevel@tonic-gate 		}
630*0Sstevel@tonic-gate 	}
631*0Sstevel@tonic-gate 	*vpp = makelonode(vp, li);
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	if ((looping) || ((vtol(dvp))->lo_looping && !doingdotdot)) {
634*0Sstevel@tonic-gate 		(vtol(*vpp))->lo_looping = 1;
635*0Sstevel@tonic-gate 	}
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate out:
638*0Sstevel@tonic-gate 	if (error != 0 && vp != NULL)
639*0Sstevel@tonic-gate 		VN_RELE(vp);
640*0Sstevel@tonic-gate #ifdef LODEBUG
641*0Sstevel@tonic-gate 	lo_dprint(4,
642*0Sstevel@tonic-gate 	"lo_lookup dvp %x realdvp %x nm '%s' newvp %x real vp %x error %d\n",
643*0Sstevel@tonic-gate 		dvp, realvp(dvp), nm, *vpp, vp, error);
644*0Sstevel@tonic-gate #endif
645*0Sstevel@tonic-gate 	return (error);
646*0Sstevel@tonic-gate }
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate /*ARGSUSED*/
649*0Sstevel@tonic-gate static int
650*0Sstevel@tonic-gate lo_create(
651*0Sstevel@tonic-gate 	vnode_t *dvp,
652*0Sstevel@tonic-gate 	char *nm,
653*0Sstevel@tonic-gate 	struct vattr *va,
654*0Sstevel@tonic-gate 	enum vcexcl exclusive,
655*0Sstevel@tonic-gate 	int mode,
656*0Sstevel@tonic-gate 	vnode_t **vpp,
657*0Sstevel@tonic-gate 	struct cred *cr,
658*0Sstevel@tonic-gate 	int flag)
659*0Sstevel@tonic-gate {
660*0Sstevel@tonic-gate 	int error;
661*0Sstevel@tonic-gate 	vnode_t *vp = NULL;
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate #ifdef LODEBUG
664*0Sstevel@tonic-gate 	lo_dprint(4, "lo_create vp %p realvp %p\n", dvp, realvp(dvp));
665*0Sstevel@tonic-gate #endif
666*0Sstevel@tonic-gate 	if (*nm == '\0') {
667*0Sstevel@tonic-gate 		ASSERT(vpp && dvp == *vpp);
668*0Sstevel@tonic-gate 		vp = realvp(*vpp);
669*0Sstevel@tonic-gate 	}
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 	if (IS_ZONEDEVFS(dvp)) {
672*0Sstevel@tonic-gate 		/* Is this truly a create?  If so, fail */
673*0Sstevel@tonic-gate 		if (*vpp == NULL)
674*0Sstevel@tonic-gate 			return (EACCES);
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate 		/* Is this an open of a non-special for writing?  If so, fail */
677*0Sstevel@tonic-gate 		if (*vpp != NULL && (mode & VWRITE) && !IS_DEVVP(*vpp))
678*0Sstevel@tonic-gate 			return (EACCES);
679*0Sstevel@tonic-gate 	}
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 	error = VOP_CREATE(realvp(dvp), nm, va, exclusive, mode, &vp, cr, flag);
682*0Sstevel@tonic-gate 	if (!error) {
683*0Sstevel@tonic-gate 		*vpp = makelonode(vp, vtoli(dvp->v_vfsp));
684*0Sstevel@tonic-gate 		if (IS_DEVVP(*vpp)) {
685*0Sstevel@tonic-gate 			vnode_t *svp;
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 			svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
688*0Sstevel@tonic-gate 			VN_RELE(*vpp);
689*0Sstevel@tonic-gate 			if (svp == NULL)
690*0Sstevel@tonic-gate 				error = ENOSYS;
691*0Sstevel@tonic-gate 			else
692*0Sstevel@tonic-gate 				*vpp = svp;
693*0Sstevel@tonic-gate 		}
694*0Sstevel@tonic-gate 	}
695*0Sstevel@tonic-gate 	return (error);
696*0Sstevel@tonic-gate }
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate static int
699*0Sstevel@tonic-gate lo_remove(vnode_t *dvp, char *nm, struct cred *cr)
700*0Sstevel@tonic-gate {
701*0Sstevel@tonic-gate #ifdef LODEBUG
702*0Sstevel@tonic-gate 	lo_dprint(4, "lo_remove vp %p realvp %p\n", dvp, realvp(dvp));
703*0Sstevel@tonic-gate #endif
704*0Sstevel@tonic-gate 	if (IS_ZONEDEVFS(dvp))
705*0Sstevel@tonic-gate 		return (EACCES);
706*0Sstevel@tonic-gate 	dvp = realvp(dvp);
707*0Sstevel@tonic-gate 	return (VOP_REMOVE(dvp, nm, cr));
708*0Sstevel@tonic-gate }
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate static int
711*0Sstevel@tonic-gate lo_link(vnode_t *tdvp, vnode_t *vp, char *tnm, struct cred *cr)
712*0Sstevel@tonic-gate {
713*0Sstevel@tonic-gate #ifdef LODEBUG
714*0Sstevel@tonic-gate 	lo_dprint(4, "lo_link vp %p realvp %p\n", vp, realvp(vp));
715*0Sstevel@tonic-gate #endif
716*0Sstevel@tonic-gate 	while (vn_matchops(vp, lo_vnodeops)) {
717*0Sstevel@tonic-gate 		if (IS_ZONEDEVFS(vp))
718*0Sstevel@tonic-gate 			return (EACCES);
719*0Sstevel@tonic-gate 		vp = realvp(vp);
720*0Sstevel@tonic-gate 	}
721*0Sstevel@tonic-gate 	while (vn_matchops(tdvp, lo_vnodeops)) {
722*0Sstevel@tonic-gate 		if (IS_ZONEDEVFS(tdvp))
723*0Sstevel@tonic-gate 			return (EACCES);
724*0Sstevel@tonic-gate 		tdvp = realvp(tdvp);
725*0Sstevel@tonic-gate 	}
726*0Sstevel@tonic-gate 	if (vp->v_vfsp != tdvp->v_vfsp)
727*0Sstevel@tonic-gate 		return (EXDEV);
728*0Sstevel@tonic-gate 	return (VOP_LINK(tdvp, vp, tnm, cr));
729*0Sstevel@tonic-gate }
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate static int
732*0Sstevel@tonic-gate lo_rename(
733*0Sstevel@tonic-gate 	vnode_t *odvp,
734*0Sstevel@tonic-gate 	char *onm,
735*0Sstevel@tonic-gate 	vnode_t *ndvp,
736*0Sstevel@tonic-gate 	char *nnm,
737*0Sstevel@tonic-gate 	struct cred *cr)
738*0Sstevel@tonic-gate {
739*0Sstevel@tonic-gate 	vnode_t *tnvp;
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate #ifdef LODEBUG
742*0Sstevel@tonic-gate 	lo_dprint(4, "lo_rename vp %p realvp %p\n", odvp, realvp(odvp));
743*0Sstevel@tonic-gate #endif
744*0Sstevel@tonic-gate 	if (IS_ZONEDEVFS(odvp))
745*0Sstevel@tonic-gate 		return (EACCES);
746*0Sstevel@tonic-gate 	/*
747*0Sstevel@tonic-gate 	 * We need to make sure we're not trying to remove a mount point for a
748*0Sstevel@tonic-gate 	 * filesystem mounted on top of lofs, which only we know about.
749*0Sstevel@tonic-gate 	 */
750*0Sstevel@tonic-gate 	if (vn_matchops(ndvp, lo_vnodeops))	/* Not our problem. */
751*0Sstevel@tonic-gate 		goto rename;
752*0Sstevel@tonic-gate 	if (VOP_LOOKUP(ndvp, nnm, &tnvp, NULL, 0, NULL, cr) != 0)
753*0Sstevel@tonic-gate 		goto rename;
754*0Sstevel@tonic-gate 	if (tnvp->v_type != VDIR) {
755*0Sstevel@tonic-gate 		VN_RELE(tnvp);
756*0Sstevel@tonic-gate 		goto rename;
757*0Sstevel@tonic-gate 	}
758*0Sstevel@tonic-gate 	if (vn_mountedvfs(tnvp)) {
759*0Sstevel@tonic-gate 		VN_RELE(tnvp);
760*0Sstevel@tonic-gate 		return (EBUSY);
761*0Sstevel@tonic-gate 	}
762*0Sstevel@tonic-gate 	VN_RELE(tnvp);
763*0Sstevel@tonic-gate rename:
764*0Sstevel@tonic-gate 	/*
765*0Sstevel@tonic-gate 	 * Since the case we're dealing with above can happen at any layer in
766*0Sstevel@tonic-gate 	 * the stack of lofs filesystems, we need to recurse down the stack,
767*0Sstevel@tonic-gate 	 * checking to see if there are any instances of a filesystem mounted on
768*0Sstevel@tonic-gate 	 * top of lofs. In order to keep on using the lofs version of
769*0Sstevel@tonic-gate 	 * VOP_RENAME(), we make sure that while the target directory is of type
770*0Sstevel@tonic-gate 	 * lofs, the source directory (the one used for getting the fs-specific
771*0Sstevel@tonic-gate 	 * version of VOP_RENAME()) is also of type lofs.
772*0Sstevel@tonic-gate 	 */
773*0Sstevel@tonic-gate 	if (vn_matchops(ndvp, lo_vnodeops)) {
774*0Sstevel@tonic-gate 		if (IS_ZONEDEVFS(ndvp))
775*0Sstevel@tonic-gate 			return (EACCES);
776*0Sstevel@tonic-gate 		ndvp = realvp(ndvp);	/* Check the next layer */
777*0Sstevel@tonic-gate 	} else {
778*0Sstevel@tonic-gate 		/*
779*0Sstevel@tonic-gate 		 * We can go fast here
780*0Sstevel@tonic-gate 		 */
781*0Sstevel@tonic-gate 		while (vn_matchops(odvp, lo_vnodeops)) {
782*0Sstevel@tonic-gate 			if (IS_ZONEDEVFS(odvp))
783*0Sstevel@tonic-gate 				return (EACCES);
784*0Sstevel@tonic-gate 			odvp = realvp(odvp);
785*0Sstevel@tonic-gate 		}
786*0Sstevel@tonic-gate 		if (odvp->v_vfsp != ndvp->v_vfsp)
787*0Sstevel@tonic-gate 			return (EXDEV);
788*0Sstevel@tonic-gate 	}
789*0Sstevel@tonic-gate 	return (VOP_RENAME(odvp, onm, ndvp, nnm, cr));
790*0Sstevel@tonic-gate }
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate static int
793*0Sstevel@tonic-gate lo_mkdir(
794*0Sstevel@tonic-gate 	vnode_t *dvp,
795*0Sstevel@tonic-gate 	char *nm,
796*0Sstevel@tonic-gate 	struct vattr *va,
797*0Sstevel@tonic-gate 	vnode_t **vpp,
798*0Sstevel@tonic-gate 	struct cred *cr)
799*0Sstevel@tonic-gate {
800*0Sstevel@tonic-gate 	int error;
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate #ifdef LODEBUG
803*0Sstevel@tonic-gate 	lo_dprint(4, "lo_mkdir vp %p realvp %p\n", dvp, realvp(dvp));
804*0Sstevel@tonic-gate #endif
805*0Sstevel@tonic-gate 	if (IS_ZONEDEVFS(dvp))
806*0Sstevel@tonic-gate 		return (EACCES);
807*0Sstevel@tonic-gate 	error = VOP_MKDIR(realvp(dvp), nm, va, vpp, cr);
808*0Sstevel@tonic-gate 	if (!error)
809*0Sstevel@tonic-gate 		*vpp = makelonode(*vpp, vtoli(dvp->v_vfsp));
810*0Sstevel@tonic-gate 	return (error);
811*0Sstevel@tonic-gate }
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate static int
814*0Sstevel@tonic-gate lo_realvp(vnode_t *vp, vnode_t **vpp)
815*0Sstevel@tonic-gate {
816*0Sstevel@tonic-gate #ifdef LODEBUG
817*0Sstevel@tonic-gate 	lo_dprint(4, "lo_realvp %p\n", vp);
818*0Sstevel@tonic-gate #endif
819*0Sstevel@tonic-gate 	while (vn_matchops(vp, lo_vnodeops))
820*0Sstevel@tonic-gate 		vp = realvp(vp);
821*0Sstevel@tonic-gate 
822*0Sstevel@tonic-gate 	if (VOP_REALVP(vp, vpp) != 0)
823*0Sstevel@tonic-gate 		*vpp = vp;
824*0Sstevel@tonic-gate 	return (0);
825*0Sstevel@tonic-gate }
826*0Sstevel@tonic-gate 
827*0Sstevel@tonic-gate static int
828*0Sstevel@tonic-gate lo_rmdir(
829*0Sstevel@tonic-gate 	vnode_t *dvp,
830*0Sstevel@tonic-gate 	char *nm,
831*0Sstevel@tonic-gate 	vnode_t *cdir,
832*0Sstevel@tonic-gate 	struct cred *cr)
833*0Sstevel@tonic-gate {
834*0Sstevel@tonic-gate 	vnode_t *rvp = cdir;
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate #ifdef LODEBUG
837*0Sstevel@tonic-gate 	lo_dprint(4, "lo_rmdir vp %p realvp %p\n", dvp, realvp(dvp));
838*0Sstevel@tonic-gate #endif
839*0Sstevel@tonic-gate 	if (IS_ZONEDEVFS(dvp))
840*0Sstevel@tonic-gate 		return (EACCES);
841*0Sstevel@tonic-gate 	/* if cdir is lofs vnode ptr get its real vnode ptr */
842*0Sstevel@tonic-gate 	if (vn_matchops(dvp, vn_getops(rvp)))
843*0Sstevel@tonic-gate 		(void) lo_realvp(cdir, &rvp);
844*0Sstevel@tonic-gate 	dvp = realvp(dvp);
845*0Sstevel@tonic-gate 	return (VOP_RMDIR(dvp, nm, rvp, cr));
846*0Sstevel@tonic-gate }
847*0Sstevel@tonic-gate 
848*0Sstevel@tonic-gate static int
849*0Sstevel@tonic-gate lo_symlink(
850*0Sstevel@tonic-gate 	vnode_t *dvp,
851*0Sstevel@tonic-gate 	char *lnm,
852*0Sstevel@tonic-gate 	struct vattr *tva,
853*0Sstevel@tonic-gate 	char *tnm,
854*0Sstevel@tonic-gate 	struct cred *cr)
855*0Sstevel@tonic-gate {
856*0Sstevel@tonic-gate #ifdef LODEBUG
857*0Sstevel@tonic-gate 	lo_dprint(4, "lo_symlink vp %p realvp %p\n", dvp, realvp(dvp));
858*0Sstevel@tonic-gate #endif
859*0Sstevel@tonic-gate 	if (IS_ZONEDEVFS(dvp))
860*0Sstevel@tonic-gate 		return (EACCES);
861*0Sstevel@tonic-gate 	dvp = realvp(dvp);
862*0Sstevel@tonic-gate 	return (VOP_SYMLINK(dvp, lnm, tva, tnm, cr));
863*0Sstevel@tonic-gate }
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate static int
866*0Sstevel@tonic-gate lo_readlink(vnode_t *vp, struct uio *uiop, struct cred *cr)
867*0Sstevel@tonic-gate {
868*0Sstevel@tonic-gate 	vp = realvp(vp);
869*0Sstevel@tonic-gate 	return (VOP_READLINK(vp, uiop, cr));
870*0Sstevel@tonic-gate }
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate static int
873*0Sstevel@tonic-gate lo_readdir(vnode_t *vp, struct uio *uiop, struct cred *cr, int *eofp)
874*0Sstevel@tonic-gate {
875*0Sstevel@tonic-gate #ifdef LODEBUG
876*0Sstevel@tonic-gate 	lo_dprint(4, "lo_readdir vp %p realvp %p\n", vp, realvp(vp));
877*0Sstevel@tonic-gate #endif
878*0Sstevel@tonic-gate 	vp = realvp(vp);
879*0Sstevel@tonic-gate 	return (VOP_READDIR(vp, uiop, cr, eofp));
880*0Sstevel@tonic-gate }
881*0Sstevel@tonic-gate 
882*0Sstevel@tonic-gate static int
883*0Sstevel@tonic-gate lo_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct)
884*0Sstevel@tonic-gate {
885*0Sstevel@tonic-gate 	vp = realvp(vp);
886*0Sstevel@tonic-gate 	return (VOP_RWLOCK(vp, write_lock, ct));
887*0Sstevel@tonic-gate }
888*0Sstevel@tonic-gate 
889*0Sstevel@tonic-gate static void
890*0Sstevel@tonic-gate lo_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
891*0Sstevel@tonic-gate {
892*0Sstevel@tonic-gate 	vp = realvp(vp);
893*0Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, write_lock, ct);
894*0Sstevel@tonic-gate }
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate static int
897*0Sstevel@tonic-gate lo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
898*0Sstevel@tonic-gate {
899*0Sstevel@tonic-gate 	vp = realvp(vp);
900*0Sstevel@tonic-gate 	return (VOP_SEEK(vp, ooff, noffp));
901*0Sstevel@tonic-gate }
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate static int
904*0Sstevel@tonic-gate lo_cmp(vnode_t *vp1, vnode_t *vp2)
905*0Sstevel@tonic-gate {
906*0Sstevel@tonic-gate 	while (vn_matchops(vp1, lo_vnodeops))
907*0Sstevel@tonic-gate 		vp1 = realvp(vp1);
908*0Sstevel@tonic-gate 	while (vn_matchops(vp2, lo_vnodeops))
909*0Sstevel@tonic-gate 		vp2 = realvp(vp2);
910*0Sstevel@tonic-gate 	return (VOP_CMP(vp1, vp2));
911*0Sstevel@tonic-gate }
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate static int
914*0Sstevel@tonic-gate lo_frlock(
915*0Sstevel@tonic-gate 	vnode_t *vp,
916*0Sstevel@tonic-gate 	int cmd,
917*0Sstevel@tonic-gate 	struct flock64 *bfp,
918*0Sstevel@tonic-gate 	int flag,
919*0Sstevel@tonic-gate 	offset_t offset,
920*0Sstevel@tonic-gate 	struct flk_callback *flk_cbp,
921*0Sstevel@tonic-gate 	cred_t *cr)
922*0Sstevel@tonic-gate {
923*0Sstevel@tonic-gate 	vp = realvp(vp);
924*0Sstevel@tonic-gate 	return (VOP_FRLOCK(vp, cmd, bfp, flag, offset, flk_cbp, cr));
925*0Sstevel@tonic-gate }
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate static int
928*0Sstevel@tonic-gate lo_space(
929*0Sstevel@tonic-gate 	vnode_t *vp,
930*0Sstevel@tonic-gate 	int cmd,
931*0Sstevel@tonic-gate 	struct flock64 *bfp,
932*0Sstevel@tonic-gate 	int flag,
933*0Sstevel@tonic-gate 	offset_t offset,
934*0Sstevel@tonic-gate 	struct cred *cr,
935*0Sstevel@tonic-gate 	caller_context_t *ct)
936*0Sstevel@tonic-gate {
937*0Sstevel@tonic-gate 	vp = realvp(vp);
938*0Sstevel@tonic-gate 	return (VOP_SPACE(vp, cmd, bfp, flag, offset, cr, ct));
939*0Sstevel@tonic-gate }
940*0Sstevel@tonic-gate 
941*0Sstevel@tonic-gate static int
942*0Sstevel@tonic-gate lo_getpage(
943*0Sstevel@tonic-gate 	vnode_t *vp,
944*0Sstevel@tonic-gate 	offset_t off,
945*0Sstevel@tonic-gate 	size_t len,
946*0Sstevel@tonic-gate 	uint_t *prot,
947*0Sstevel@tonic-gate 	struct page *parr[],
948*0Sstevel@tonic-gate 	size_t psz,
949*0Sstevel@tonic-gate 	struct seg *seg,
950*0Sstevel@tonic-gate 	caddr_t addr,
951*0Sstevel@tonic-gate 	enum seg_rw rw,
952*0Sstevel@tonic-gate 	struct cred *cr)
953*0Sstevel@tonic-gate {
954*0Sstevel@tonic-gate 	vp = realvp(vp);
955*0Sstevel@tonic-gate 	return (VOP_GETPAGE(vp, off, len, prot, parr, psz, seg, addr, rw, cr));
956*0Sstevel@tonic-gate }
957*0Sstevel@tonic-gate 
958*0Sstevel@tonic-gate static int
959*0Sstevel@tonic-gate lo_putpage(vnode_t *vp, offset_t off, size_t len, int flags, struct cred *cr)
960*0Sstevel@tonic-gate {
961*0Sstevel@tonic-gate 	vp = realvp(vp);
962*0Sstevel@tonic-gate 	return (VOP_PUTPAGE(vp, off, len, flags, cr));
963*0Sstevel@tonic-gate }
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate static int
966*0Sstevel@tonic-gate lo_map(
967*0Sstevel@tonic-gate 	vnode_t *vp,
968*0Sstevel@tonic-gate 	offset_t off,
969*0Sstevel@tonic-gate 	struct as *as,
970*0Sstevel@tonic-gate 	caddr_t *addrp,
971*0Sstevel@tonic-gate 	size_t len,
972*0Sstevel@tonic-gate 	uchar_t prot,
973*0Sstevel@tonic-gate 	uchar_t maxprot,
974*0Sstevel@tonic-gate 	uint_t flags,
975*0Sstevel@tonic-gate 	struct cred *cr)
976*0Sstevel@tonic-gate {
977*0Sstevel@tonic-gate 	vp = realvp(vp);
978*0Sstevel@tonic-gate 	return (VOP_MAP(vp, off, as, addrp, len, prot, maxprot, flags, cr));
979*0Sstevel@tonic-gate }
980*0Sstevel@tonic-gate 
981*0Sstevel@tonic-gate static int
982*0Sstevel@tonic-gate lo_addmap(
983*0Sstevel@tonic-gate 	vnode_t *vp,
984*0Sstevel@tonic-gate 	offset_t off,
985*0Sstevel@tonic-gate 	struct as *as,
986*0Sstevel@tonic-gate 	caddr_t addr,
987*0Sstevel@tonic-gate 	size_t len,
988*0Sstevel@tonic-gate 	uchar_t prot,
989*0Sstevel@tonic-gate 	uchar_t maxprot,
990*0Sstevel@tonic-gate 	uint_t flags,
991*0Sstevel@tonic-gate 	struct cred *cr)
992*0Sstevel@tonic-gate {
993*0Sstevel@tonic-gate 	vp = realvp(vp);
994*0Sstevel@tonic-gate 	return (VOP_ADDMAP(vp, off, as, addr, len, prot, maxprot, flags, cr));
995*0Sstevel@tonic-gate }
996*0Sstevel@tonic-gate 
997*0Sstevel@tonic-gate static int
998*0Sstevel@tonic-gate lo_delmap(
999*0Sstevel@tonic-gate 	vnode_t *vp,
1000*0Sstevel@tonic-gate 	offset_t off,
1001*0Sstevel@tonic-gate 	struct as *as,
1002*0Sstevel@tonic-gate 	caddr_t addr,
1003*0Sstevel@tonic-gate 	size_t len,
1004*0Sstevel@tonic-gate 	uint_t prot,
1005*0Sstevel@tonic-gate 	uint_t maxprot,
1006*0Sstevel@tonic-gate 	uint_t flags,
1007*0Sstevel@tonic-gate 	struct cred *cr)
1008*0Sstevel@tonic-gate {
1009*0Sstevel@tonic-gate 	vp = realvp(vp);
1010*0Sstevel@tonic-gate 	return (VOP_DELMAP(vp, off, as, addr, len, prot, maxprot, flags, cr));
1011*0Sstevel@tonic-gate }
1012*0Sstevel@tonic-gate 
1013*0Sstevel@tonic-gate static int
1014*0Sstevel@tonic-gate lo_poll(
1015*0Sstevel@tonic-gate 	vnode_t *vp,
1016*0Sstevel@tonic-gate 	short events,
1017*0Sstevel@tonic-gate 	int anyyet,
1018*0Sstevel@tonic-gate 	short *reventsp,
1019*0Sstevel@tonic-gate 	struct pollhead **phpp)
1020*0Sstevel@tonic-gate {
1021*0Sstevel@tonic-gate 	vp = realvp(vp);
1022*0Sstevel@tonic-gate 	return (VOP_POLL(vp, events, anyyet, reventsp, phpp));
1023*0Sstevel@tonic-gate }
1024*0Sstevel@tonic-gate 
1025*0Sstevel@tonic-gate static int
1026*0Sstevel@tonic-gate lo_dump(vnode_t *vp, caddr_t addr, int bn, int count)
1027*0Sstevel@tonic-gate {
1028*0Sstevel@tonic-gate 	vp = realvp(vp);
1029*0Sstevel@tonic-gate 	return (VOP_DUMP(vp, addr, bn, count));
1030*0Sstevel@tonic-gate }
1031*0Sstevel@tonic-gate 
1032*0Sstevel@tonic-gate static int
1033*0Sstevel@tonic-gate lo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, struct cred *cr)
1034*0Sstevel@tonic-gate {
1035*0Sstevel@tonic-gate 	vp = realvp(vp);
1036*0Sstevel@tonic-gate 	return (VOP_PATHCONF(vp, cmd, valp, cr));
1037*0Sstevel@tonic-gate }
1038*0Sstevel@tonic-gate 
1039*0Sstevel@tonic-gate static int
1040*0Sstevel@tonic-gate lo_pageio(
1041*0Sstevel@tonic-gate 	vnode_t *vp,
1042*0Sstevel@tonic-gate 	struct page *pp,
1043*0Sstevel@tonic-gate 	u_offset_t io_off,
1044*0Sstevel@tonic-gate 	size_t io_len,
1045*0Sstevel@tonic-gate 	int flags,
1046*0Sstevel@tonic-gate 	cred_t *cr)
1047*0Sstevel@tonic-gate {
1048*0Sstevel@tonic-gate 	vp = realvp(vp);
1049*0Sstevel@tonic-gate 	return (VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr));
1050*0Sstevel@tonic-gate }
1051*0Sstevel@tonic-gate 
1052*0Sstevel@tonic-gate static void
1053*0Sstevel@tonic-gate lo_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr)
1054*0Sstevel@tonic-gate {
1055*0Sstevel@tonic-gate 	vp = realvp(vp);
1056*0Sstevel@tonic-gate 	if (vp != NULL && vp != &kvp)
1057*0Sstevel@tonic-gate 		VOP_DISPOSE(vp, pp, fl, dn, cr);
1058*0Sstevel@tonic-gate }
1059*0Sstevel@tonic-gate 
1060*0Sstevel@tonic-gate static int
1061*0Sstevel@tonic-gate lo_setsecattr(vnode_t *vp, vsecattr_t *secattr, int flags, struct cred *cr)
1062*0Sstevel@tonic-gate {
1063*0Sstevel@tonic-gate 	if (vn_is_readonly(vp))
1064*0Sstevel@tonic-gate 		return (EROFS);
1065*0Sstevel@tonic-gate 	vp = realvp(vp);
1066*0Sstevel@tonic-gate 	return (VOP_SETSECATTR(vp, secattr, flags, cr));
1067*0Sstevel@tonic-gate }
1068*0Sstevel@tonic-gate 
1069*0Sstevel@tonic-gate static int
1070*0Sstevel@tonic-gate lo_getsecattr(vnode_t *vp, vsecattr_t *secattr, int flags, struct cred *cr)
1071*0Sstevel@tonic-gate {
1072*0Sstevel@tonic-gate 	vp = realvp(vp);
1073*0Sstevel@tonic-gate 	return (VOP_GETSECATTR(vp, secattr, flags, cr));
1074*0Sstevel@tonic-gate }
1075*0Sstevel@tonic-gate 
1076*0Sstevel@tonic-gate static int
1077*0Sstevel@tonic-gate lo_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
1078*0Sstevel@tonic-gate {
1079*0Sstevel@tonic-gate 	vp = realvp(vp);
1080*0Sstevel@tonic-gate 	return (VOP_SHRLOCK(vp, cmd, shr, flag, cr));
1081*0Sstevel@tonic-gate }
1082*0Sstevel@tonic-gate 
1083*0Sstevel@tonic-gate /*
1084*0Sstevel@tonic-gate  * Loopback vnode operations vector.
1085*0Sstevel@tonic-gate  */
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate struct vnodeops *lo_vnodeops;
1088*0Sstevel@tonic-gate 
1089*0Sstevel@tonic-gate const fs_operation_def_t lo_vnodeops_template[] = {
1090*0Sstevel@tonic-gate 	VOPNAME_OPEN, lo_open,
1091*0Sstevel@tonic-gate 	VOPNAME_CLOSE, lo_close,
1092*0Sstevel@tonic-gate 	VOPNAME_READ, lo_read,
1093*0Sstevel@tonic-gate 	VOPNAME_WRITE, lo_write,
1094*0Sstevel@tonic-gate 	VOPNAME_IOCTL, lo_ioctl,
1095*0Sstevel@tonic-gate 	VOPNAME_SETFL, lo_setfl,
1096*0Sstevel@tonic-gate 	VOPNAME_GETATTR, lo_getattr,
1097*0Sstevel@tonic-gate 	VOPNAME_SETATTR, lo_setattr,
1098*0Sstevel@tonic-gate 	VOPNAME_ACCESS, lo_access,
1099*0Sstevel@tonic-gate 	VOPNAME_LOOKUP, lo_lookup,
1100*0Sstevel@tonic-gate 	VOPNAME_CREATE, lo_create,
1101*0Sstevel@tonic-gate 	VOPNAME_REMOVE, lo_remove,
1102*0Sstevel@tonic-gate 	VOPNAME_LINK, lo_link,
1103*0Sstevel@tonic-gate 	VOPNAME_RENAME, lo_rename,
1104*0Sstevel@tonic-gate 	VOPNAME_MKDIR, lo_mkdir,
1105*0Sstevel@tonic-gate 	VOPNAME_RMDIR, lo_rmdir,
1106*0Sstevel@tonic-gate 	VOPNAME_READDIR, lo_readdir,
1107*0Sstevel@tonic-gate 	VOPNAME_SYMLINK, lo_symlink,
1108*0Sstevel@tonic-gate 	VOPNAME_READLINK, lo_readlink,
1109*0Sstevel@tonic-gate 	VOPNAME_FSYNC, lo_fsync,
1110*0Sstevel@tonic-gate 	VOPNAME_INACTIVE, (fs_generic_func_p) lo_inactive,
1111*0Sstevel@tonic-gate 	VOPNAME_FID, lo_fid,
1112*0Sstevel@tonic-gate 	VOPNAME_RWLOCK, lo_rwlock,
1113*0Sstevel@tonic-gate 	VOPNAME_RWUNLOCK, (fs_generic_func_p) lo_rwunlock,
1114*0Sstevel@tonic-gate 	VOPNAME_SEEK, lo_seek,
1115*0Sstevel@tonic-gate 	VOPNAME_CMP, lo_cmp,
1116*0Sstevel@tonic-gate 	VOPNAME_FRLOCK, lo_frlock,
1117*0Sstevel@tonic-gate 	VOPNAME_SPACE, lo_space,
1118*0Sstevel@tonic-gate 	VOPNAME_REALVP, lo_realvp,
1119*0Sstevel@tonic-gate 	VOPNAME_GETPAGE, lo_getpage,
1120*0Sstevel@tonic-gate 	VOPNAME_PUTPAGE, lo_putpage,
1121*0Sstevel@tonic-gate 	VOPNAME_MAP, (fs_generic_func_p) lo_map,
1122*0Sstevel@tonic-gate 	VOPNAME_ADDMAP, (fs_generic_func_p) lo_addmap,
1123*0Sstevel@tonic-gate 	VOPNAME_DELMAP, lo_delmap,
1124*0Sstevel@tonic-gate 	VOPNAME_POLL, (fs_generic_func_p) lo_poll,
1125*0Sstevel@tonic-gate 	VOPNAME_DUMP, lo_dump,
1126*0Sstevel@tonic-gate 	VOPNAME_DUMPCTL, fs_error,		/* XXX - why? */
1127*0Sstevel@tonic-gate 	VOPNAME_PATHCONF, lo_pathconf,
1128*0Sstevel@tonic-gate 	VOPNAME_PAGEIO, lo_pageio,
1129*0Sstevel@tonic-gate 	VOPNAME_DISPOSE, (fs_generic_func_p) lo_dispose,
1130*0Sstevel@tonic-gate 	VOPNAME_SETSECATTR, lo_setsecattr,
1131*0Sstevel@tonic-gate 	VOPNAME_GETSECATTR, lo_getsecattr,
1132*0Sstevel@tonic-gate 	VOPNAME_SHRLOCK, lo_shrlock,
1133*0Sstevel@tonic-gate 	NULL, NULL
1134*0Sstevel@tonic-gate };
1135