17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*8f71b825Sowenr  * Common Development and Distribution License (the "License").
6*8f71b825Sowenr  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22c7688ab0Srd  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/param.h>
297c478bd9Sstevel@tonic-gate #include <sys/systm.h>
307c478bd9Sstevel@tonic-gate #include <sys/errno.h>
317c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
327c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
337c478bd9Sstevel@tonic-gate #include <sys/uio.h>
347c478bd9Sstevel@tonic-gate #include <sys/cred.h>
357c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
367c478bd9Sstevel@tonic-gate #include <sys/debug.h>
377c478bd9Sstevel@tonic-gate #include <sys/fs/lofs_node.h>
387c478bd9Sstevel@tonic-gate #include <sys/fs/lofs_info.h>
397c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
407c478bd9Sstevel@tonic-gate #include <vm/as.h>
417c478bd9Sstevel@tonic-gate #include <vm/seg.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #define	IS_ZONEDEVFS(vp) \
447c478bd9Sstevel@tonic-gate 	(vtoli((vp)->v_vfsp)->li_flag & LO_ZONEDEVFS)
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * These are the vnode ops routines which implement the vnode interface to
487c478bd9Sstevel@tonic-gate  * the looped-back file system.  These routines just take their parameters,
497c478bd9Sstevel@tonic-gate  * and then calling the appropriate real vnode routine(s) to do the work.
507c478bd9Sstevel@tonic-gate  */
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate static int
537c478bd9Sstevel@tonic-gate lo_open(vnode_t **vpp, int flag, struct cred *cr)
547c478bd9Sstevel@tonic-gate {
557c478bd9Sstevel@tonic-gate 	vnode_t *vp = *vpp;
567c478bd9Sstevel@tonic-gate 	vnode_t *rvp;
577c478bd9Sstevel@tonic-gate 	vnode_t *oldvp;
587c478bd9Sstevel@tonic-gate 	int error;
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #ifdef LODEBUG
617c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_open vp %p cnt=%d realvp %p cnt=%d\n",
627c478bd9Sstevel@tonic-gate 		vp, vp->v_count, realvp(vp), realvp(vp)->v_count);
637c478bd9Sstevel@tonic-gate #endif
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	oldvp = vp;
667c478bd9Sstevel@tonic-gate 	vp = rvp = realvp(vp);
677c478bd9Sstevel@tonic-gate 	/*
687c478bd9Sstevel@tonic-gate 	 * Need to hold new reference to vp since VOP_OPEN() may
697c478bd9Sstevel@tonic-gate 	 * decide to release it.
707c478bd9Sstevel@tonic-gate 	 */
717c478bd9Sstevel@tonic-gate 	VN_HOLD(vp);
727c478bd9Sstevel@tonic-gate 	error = VOP_OPEN(&rvp, flag, cr);
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	if (!error && rvp != vp) {
757c478bd9Sstevel@tonic-gate 		/*
767c478bd9Sstevel@tonic-gate 		 * the FS which we called should have released the
777c478bd9Sstevel@tonic-gate 		 * new reference on vp
787c478bd9Sstevel@tonic-gate 		 */
79b431137cSowenr 		*vpp = makelonode(rvp, vtoli(oldvp->v_vfsp), 0);
80*8f71b825Sowenr 		if ((*vpp)->v_type == VDIR) {
81*8f71b825Sowenr 			/*
82*8f71b825Sowenr 			 * Copy over any looping flags to the new lnode.
83*8f71b825Sowenr 			 */
84*8f71b825Sowenr 			(vtol(*vpp))->lo_looping |= (vtol(oldvp))->lo_looping;
85*8f71b825Sowenr 		}
867c478bd9Sstevel@tonic-gate 		if (IS_DEVVP(*vpp)) {
877c478bd9Sstevel@tonic-gate 			vnode_t *svp;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 			svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
907c478bd9Sstevel@tonic-gate 			VN_RELE(*vpp);
917c478bd9Sstevel@tonic-gate 			if (svp == NULL)
927c478bd9Sstevel@tonic-gate 				error = ENOSYS;
937c478bd9Sstevel@tonic-gate 			else
947c478bd9Sstevel@tonic-gate 				*vpp = svp;
957c478bd9Sstevel@tonic-gate 		}
967c478bd9Sstevel@tonic-gate 		VN_RELE(oldvp);
977c478bd9Sstevel@tonic-gate 	} else {
987c478bd9Sstevel@tonic-gate 		ASSERT(rvp->v_count > 1);
997c478bd9Sstevel@tonic-gate 		VN_RELE(rvp);
1007c478bd9Sstevel@tonic-gate 	}
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	return (error);
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate static int
1067c478bd9Sstevel@tonic-gate lo_close(
1077c478bd9Sstevel@tonic-gate 	vnode_t *vp,
1087c478bd9Sstevel@tonic-gate 	int flag,
1097c478bd9Sstevel@tonic-gate 	int count,
1107c478bd9Sstevel@tonic-gate 	offset_t offset,
1117c478bd9Sstevel@tonic-gate 	struct cred *cr)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate #ifdef LODEBUG
1147c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_close vp %p realvp %p\n", vp, realvp(vp));
1157c478bd9Sstevel@tonic-gate #endif
1167c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
1177c478bd9Sstevel@tonic-gate 	return (VOP_CLOSE(vp, flag, count, offset, cr));
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate static int
1217c478bd9Sstevel@tonic-gate lo_read(vnode_t *vp, struct uio *uiop, int ioflag, struct cred *cr,
1227c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate #ifdef LODEBUG
1257c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_read vp %p realvp %p\n", vp, realvp(vp));
1267c478bd9Sstevel@tonic-gate #endif
1277c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
1287c478bd9Sstevel@tonic-gate 	return (VOP_READ(vp, uiop, ioflag, cr, ct));
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate static int
1327c478bd9Sstevel@tonic-gate lo_write(vnode_t *vp, struct uio *uiop, int ioflag, struct cred *cr,
1337c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate #ifdef LODEBUG
1367c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_write vp %p realvp %p\n", vp, realvp(vp));
1377c478bd9Sstevel@tonic-gate #endif
1387c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
1397c478bd9Sstevel@tonic-gate 	return (VOP_WRITE(vp, uiop, ioflag, cr, ct));
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate static int
1437c478bd9Sstevel@tonic-gate lo_ioctl(
1447c478bd9Sstevel@tonic-gate 	vnode_t *vp,
1457c478bd9Sstevel@tonic-gate 	int cmd,
1467c478bd9Sstevel@tonic-gate 	intptr_t arg,
1477c478bd9Sstevel@tonic-gate 	int flag,
1487c478bd9Sstevel@tonic-gate 	struct cred *cr,
1497c478bd9Sstevel@tonic-gate 	int *rvalp)
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate #ifdef LODEBUG
1527c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_ioctl vp %p realvp %p\n", vp, realvp(vp));
1537c478bd9Sstevel@tonic-gate #endif
1547c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
1557c478bd9Sstevel@tonic-gate 	return (VOP_IOCTL(vp, cmd, arg, flag, cr, rvalp));
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate static int
1597c478bd9Sstevel@tonic-gate lo_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
1627c478bd9Sstevel@tonic-gate 	return (VOP_SETFL(vp, oflags, nflags, cr));
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static int
1667c478bd9Sstevel@tonic-gate lo_getattr(
1677c478bd9Sstevel@tonic-gate 	vnode_t *vp,
1687c478bd9Sstevel@tonic-gate 	struct vattr *vap,
1697c478bd9Sstevel@tonic-gate 	int flags,
1707c478bd9Sstevel@tonic-gate 	struct cred *cr)
1717c478bd9Sstevel@tonic-gate {
1727c478bd9Sstevel@tonic-gate 	int error;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate #ifdef LODEBUG
1757c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_getattr vp %p realvp %p\n", vp, realvp(vp));
1767c478bd9Sstevel@tonic-gate #endif
1777c478bd9Sstevel@tonic-gate 	if (error = VOP_GETATTR(realvp(vp), vap, flags, cr))
1787c478bd9Sstevel@tonic-gate 		return (error);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/*
1817c478bd9Sstevel@tonic-gate 	 * In zonedevfs mode, we pull a nasty trick; we make sure that
1827c478bd9Sstevel@tonic-gate 	 * the dev_t does *not* reflect the underlying device, so that
1837c478bd9Sstevel@tonic-gate 	 * no renames can occur to or from the /dev hierarchy.
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 	if (IS_ZONEDEVFS(vp)) {
1867c478bd9Sstevel@tonic-gate 		vap->va_fsid = expldev(vp->v_vfsp->vfs_fsid.val[0]);
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	return (0);
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate static int
1937c478bd9Sstevel@tonic-gate lo_setattr(
1947c478bd9Sstevel@tonic-gate 	vnode_t *vp,
1957c478bd9Sstevel@tonic-gate 	struct vattr *vap,
1967c478bd9Sstevel@tonic-gate 	int flags,
1977c478bd9Sstevel@tonic-gate 	struct cred *cr,
1987c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate #ifdef LODEBUG
2017c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_setattr vp %p realvp %p\n", vp, realvp(vp));
2027c478bd9Sstevel@tonic-gate #endif
2037c478bd9Sstevel@tonic-gate 	if (IS_ZONEDEVFS(vp) && !IS_DEVVP(vp)) {
2047c478bd9Sstevel@tonic-gate 		return (EACCES);
2057c478bd9Sstevel@tonic-gate 	}
2067c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
2077c478bd9Sstevel@tonic-gate 	return (VOP_SETATTR(vp, vap, flags, cr, ct));
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate static int
2117c478bd9Sstevel@tonic-gate lo_access(vnode_t *vp, int mode, int flags, struct cred *cr)
2127c478bd9Sstevel@tonic-gate {
2137c478bd9Sstevel@tonic-gate #ifdef LODEBUG
2147c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_access vp %p realvp %p\n", vp, realvp(vp));
2157c478bd9Sstevel@tonic-gate #endif
2167c478bd9Sstevel@tonic-gate 	if (mode & VWRITE) {
2177c478bd9Sstevel@tonic-gate 		if (vp->v_type == VREG && vn_is_readonly(vp))
2187c478bd9Sstevel@tonic-gate 			return (EROFS);
2197c478bd9Sstevel@tonic-gate 		if (IS_ZONEDEVFS(vp) && !IS_DEVVP(vp))
2207c478bd9Sstevel@tonic-gate 			return (EACCES);
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
2237c478bd9Sstevel@tonic-gate 	return (VOP_ACCESS(vp, mode, flags, cr));
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate static int
2277c478bd9Sstevel@tonic-gate lo_fsync(vnode_t *vp, int syncflag, struct cred *cr)
2287c478bd9Sstevel@tonic-gate {
2297c478bd9Sstevel@tonic-gate #ifdef LODEBUG
2307c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_fsync vp %p realvp %p\n", vp, realvp(vp));
2317c478bd9Sstevel@tonic-gate #endif
2327c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
2337c478bd9Sstevel@tonic-gate 	return (VOP_FSYNC(vp, syncflag, cr));
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2377c478bd9Sstevel@tonic-gate static void
2387c478bd9Sstevel@tonic-gate lo_inactive(vnode_t *vp, struct cred *cr)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate #ifdef LODEBUG
2417c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_inactive %p, realvp %p\n", vp, realvp(vp));
2427c478bd9Sstevel@tonic-gate #endif
2437c478bd9Sstevel@tonic-gate 	freelonode(vtol(vp));
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate /* ARGSUSED */
2477c478bd9Sstevel@tonic-gate static int
2487c478bd9Sstevel@tonic-gate lo_fid(vnode_t *vp, struct fid *fidp)
2497c478bd9Sstevel@tonic-gate {
2507c478bd9Sstevel@tonic-gate #ifdef LODEBUG
2517c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_fid %p, realvp %p\n", vp, realvp(vp));
2527c478bd9Sstevel@tonic-gate #endif
2537c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
2547c478bd9Sstevel@tonic-gate 	return (VOP_FID(vp, fidp));
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate  * Given a vnode of lofs type, lookup nm name and
2597c478bd9Sstevel@tonic-gate  * return a shadow vnode (of lofs type) of the
2607c478bd9Sstevel@tonic-gate  * real vnode found.
2617c478bd9Sstevel@tonic-gate  *
2627c478bd9Sstevel@tonic-gate  * Due to the nature of lofs, there is a potential
2637c478bd9Sstevel@tonic-gate  * looping in path traversal.
2647c478bd9Sstevel@tonic-gate  *
2657c478bd9Sstevel@tonic-gate  * starting from the mount point of an lofs;
2667c478bd9Sstevel@tonic-gate  * a loop is defined to be a traversal path
2677c478bd9Sstevel@tonic-gate  * where the mount point or the real vnode of
2687c478bd9Sstevel@tonic-gate  * the root of this lofs is encountered twice.
2697c478bd9Sstevel@tonic-gate  * Once at the start of traversal and second
2707c478bd9Sstevel@tonic-gate  * when the looping is found.
2717c478bd9Sstevel@tonic-gate  *
2727c478bd9Sstevel@tonic-gate  * When a loop is encountered, a shadow of the
2737c478bd9Sstevel@tonic-gate  * covered vnode is returned to stop the looping.
2747c478bd9Sstevel@tonic-gate  *
2757c478bd9Sstevel@tonic-gate  * This normally works, but with the advent of
2767c478bd9Sstevel@tonic-gate  * the new automounter, returning the shadow of the
2777c478bd9Sstevel@tonic-gate  * covered vnode (autonode, in this case) does not
2787c478bd9Sstevel@tonic-gate  * stop the loop.  Because further lookup on this
2797c478bd9Sstevel@tonic-gate  * lonode will cause the autonode to call lo_lookup()
2807c478bd9Sstevel@tonic-gate  * on the lonode covering it.
2817c478bd9Sstevel@tonic-gate  *
2827c478bd9Sstevel@tonic-gate  * example "/net/jurassic/net/jurassic" is a loop.
2837c478bd9Sstevel@tonic-gate  * returning the shadow of the autonode corresponding to
2847c478bd9Sstevel@tonic-gate  * "/net/jurassic/net/jurassic" will not terminate the
2857c478bd9Sstevel@tonic-gate  * loop.   To solve this problem we allow the loop to go
286b431137cSowenr  * through one more level component lookup.  Whichever
287b431137cSowenr  * directory is then looked up in "/net/jurassic/net/jurassic"
288b431137cSowenr  * the vnode returned is the vnode covered by the autonode
289b431137cSowenr  * "net" and this will terminate the loop.
2907c478bd9Sstevel@tonic-gate  *
2917c478bd9Sstevel@tonic-gate  * Lookup for dot dot has to be dealt with separately.
2927c478bd9Sstevel@tonic-gate  * It will be nice to have a "one size fits all" kind
2937c478bd9Sstevel@tonic-gate  * of solution, so that we don't have so many ifs statement
2947c478bd9Sstevel@tonic-gate  * in the lo_lookup() to handle dotdot.  But, since
2957c478bd9Sstevel@tonic-gate  * there are so many special cases to handle different
2967c478bd9Sstevel@tonic-gate  * kinds looping above, we need special codes to handle
2977c478bd9Sstevel@tonic-gate  * dotdot lookup as well.
2987c478bd9Sstevel@tonic-gate  */
2997c478bd9Sstevel@tonic-gate static int
3007c478bd9Sstevel@tonic-gate lo_lookup(
3017c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
3027c478bd9Sstevel@tonic-gate 	char *nm,
3037c478bd9Sstevel@tonic-gate 	vnode_t **vpp,
3047c478bd9Sstevel@tonic-gate 	struct pathname *pnp,
3057c478bd9Sstevel@tonic-gate 	int flags,
3067c478bd9Sstevel@tonic-gate 	vnode_t *rdir,
3077c478bd9Sstevel@tonic-gate 	struct cred *cr)
3087c478bd9Sstevel@tonic-gate {
3097c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL, *tvp = NULL, *nonlovp;
3107c478bd9Sstevel@tonic-gate 	int error, is_indirectloop;
3117c478bd9Sstevel@tonic-gate 	vnode_t *realdvp = realvp(dvp);
3127c478bd9Sstevel@tonic-gate 	struct loinfo *li = vtoli(dvp->v_vfsp);
3137c478bd9Sstevel@tonic-gate 	int looping = 0;
314b431137cSowenr 	int autoloop = 0;
3157c478bd9Sstevel@tonic-gate 	int doingdotdot = 0;
3167c478bd9Sstevel@tonic-gate 	int nosub = 0;
317b431137cSowenr 	int mkflag = 0;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/*
3207c478bd9Sstevel@tonic-gate 	 * If name is empty and no XATTR flags are set, then return
3217c478bd9Sstevel@tonic-gate 	 * dvp (empty name == lookup ".").  If an XATTR flag is set
3227c478bd9Sstevel@tonic-gate 	 * then we need to call VOP_LOOKUP to get the xattr dir.
3237c478bd9Sstevel@tonic-gate 	 */
3247c478bd9Sstevel@tonic-gate 	if (nm[0] == '\0' && ! (flags & (CREATE_XATTR_DIR|LOOKUP_XATTR))) {
3257c478bd9Sstevel@tonic-gate 		VN_HOLD(dvp);
3267c478bd9Sstevel@tonic-gate 		*vpp = dvp;
3277c478bd9Sstevel@tonic-gate 		return (0);
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0') {
3317c478bd9Sstevel@tonic-gate 		doingdotdot++;
3327c478bd9Sstevel@tonic-gate 		/*
3337c478bd9Sstevel@tonic-gate 		 * Handle ".." out of mounted filesystem
3347c478bd9Sstevel@tonic-gate 		 */
3357c478bd9Sstevel@tonic-gate 		while ((realdvp->v_flag & VROOT) && realdvp != rootdir) {
3367c478bd9Sstevel@tonic-gate 			realdvp = realdvp->v_vfsp->vfs_vnodecovered;
3377c478bd9Sstevel@tonic-gate 			ASSERT(realdvp != NULL);
3387c478bd9Sstevel@tonic-gate 		}
3397c478bd9Sstevel@tonic-gate 	}
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	*vpp = NULL;	/* default(error) case */
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	/*
3447c478bd9Sstevel@tonic-gate 	 * Do the normal lookup
3457c478bd9Sstevel@tonic-gate 	 */
346d13f2f50Smarks 	if (error = VOP_LOOKUP(realdvp, nm, &vp, pnp, flags, rdir, cr)) {
347d13f2f50Smarks 		vp = NULL;
3487c478bd9Sstevel@tonic-gate 		goto out;
349d13f2f50Smarks 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	/*
3527c478bd9Sstevel@tonic-gate 	 * We do this check here to avoid returning a stale file handle to the
3537c478bd9Sstevel@tonic-gate 	 * caller.
3547c478bd9Sstevel@tonic-gate 	 */
3557c478bd9Sstevel@tonic-gate 	if (nm[0] == '.' && nm[1] == '\0') {
3567c478bd9Sstevel@tonic-gate 		ASSERT(vp == realdvp);
3577c478bd9Sstevel@tonic-gate 		VN_HOLD(dvp);
3587c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
3597c478bd9Sstevel@tonic-gate 		*vpp = dvp;
3607c478bd9Sstevel@tonic-gate 		return (0);
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	if (doingdotdot) {
364b431137cSowenr 		if ((vtol(dvp))->lo_looping & LO_LOOPING) {
3657c478bd9Sstevel@tonic-gate 			vfs_t *vfsp;
3667c478bd9Sstevel@tonic-gate 
36795b97885Snr 			error = vn_vfsrlock_wait(realdvp);
3687c478bd9Sstevel@tonic-gate 			if (error)
3697c478bd9Sstevel@tonic-gate 				goto out;
3707c478bd9Sstevel@tonic-gate 			vfsp = vn_mountedvfs(realdvp);
371b431137cSowenr 			/*
372b431137cSowenr 			 * In the standard case if the looping flag is set and
373b431137cSowenr 			 * performing dotdot we would be returning from a
374b431137cSowenr 			 * covered vnode, implying vfsp could not be null. The
375b431137cSowenr 			 * exceptions being if we have looping and overlay
376b431137cSowenr 			 * mounts or looping and covered file systems.
377b431137cSowenr 			 */
378b431137cSowenr 			if (vfsp == NULL) {
3797c478bd9Sstevel@tonic-gate 				/*
380b431137cSowenr 				 * Overlay mount or covered file system,
381b431137cSowenr 				 * so just make the shadow node.
3827c478bd9Sstevel@tonic-gate 				 */
3837c478bd9Sstevel@tonic-gate 				vn_vfsunlock(realdvp);
384b431137cSowenr 				*vpp = makelonode(vp, li, 0);
385b431137cSowenr 				(vtol(*vpp))->lo_looping |= LO_LOOPING;
386b431137cSowenr 				return (0);
387b431137cSowenr 			}
388b431137cSowenr 			/*
389b431137cSowenr 			 * When looping get the actual found vnode
390b431137cSowenr 			 * instead of the vnode covered.
391b431137cSowenr 			 * Here we have to hold the lock for realdvp
392b431137cSowenr 			 * since an unmount during the traversal to the
393b431137cSowenr 			 * root vnode would turn *vfsp into garbage
394b431137cSowenr 			 * which would be fatal.
395b431137cSowenr 			 */
396b431137cSowenr 			error = VFS_ROOT(vfsp, &tvp);
39795b97885Snr 			vn_vfsunlock(realdvp);
398b431137cSowenr 
399b431137cSowenr 			if (error)
400b431137cSowenr 				goto out;
40195b97885Snr 
402b431137cSowenr 			if ((tvp == li->li_rootvp) && (vp == realvp(tvp))) {
4037c478bd9Sstevel@tonic-gate 				/*
404b431137cSowenr 				 * we're back at the real vnode
405b431137cSowenr 				 * of the rootvp
4067c478bd9Sstevel@tonic-gate 				 *
407b431137cSowenr 				 * return the rootvp
408b431137cSowenr 				 * Ex: /mnt/mnt/..
409b431137cSowenr 				 * where / has been lofs-mounted
410b431137cSowenr 				 * onto /mnt.  Return the lofs
411b431137cSowenr 				 * node mounted at /mnt.
412b431137cSowenr 				 */
413b431137cSowenr 				*vpp = tvp;
414b431137cSowenr 				VN_RELE(vp);
415b431137cSowenr 				return (0);
416b431137cSowenr 			} else {
417b431137cSowenr 				/*
418b431137cSowenr 				 * We are returning from a covered
419b431137cSowenr 				 * node whose vfs_mountedhere is
420b431137cSowenr 				 * not pointing to vfs of the current
421b431137cSowenr 				 * root vnode.
422b431137cSowenr 				 * This is a condn where in we
423b431137cSowenr 				 * returned a covered node say Zc
424b431137cSowenr 				 * but Zc is not the cover of current
425b431137cSowenr 				 * root.
426b431137cSowenr 				 * i.e.., if X is the root vnode
427b431137cSowenr 				 * lookup(Zc,"..") is taking us to
428b431137cSowenr 				 * X.
429b431137cSowenr 				 * Ex: /net/X/net/X/Y
4307c478bd9Sstevel@tonic-gate 				 *
431b431137cSowenr 				 * If LO_AUTOLOOP (autofs/lofs looping detected)
432b431137cSowenr 				 * has been set then we are encountering the
433b431137cSowenr 				 * cover of Y (Y being any directory vnode
434b431137cSowenr 				 * under /net/X/net/X/).
435b431137cSowenr 				 * When performing a dotdot set the
436b431137cSowenr 				 * returned vp to the vnode covered
437b431137cSowenr 				 * by the mounted lofs, ie /net/X/net/X
4387c478bd9Sstevel@tonic-gate 				 */
439b431137cSowenr 				VN_RELE(tvp);
440b431137cSowenr 				if ((vtol(dvp))->lo_looping & LO_AUTOLOOP) {
441b431137cSowenr 					VN_RELE(vp);
442b431137cSowenr 					vp = li->li_rootvp;
443b431137cSowenr 					vp = vp->v_vfsp->vfs_vnodecovered;
4447c478bd9Sstevel@tonic-gate 					VN_HOLD(vp);
445b431137cSowenr 					*vpp = makelonode(vp, li, 0);
446b431137cSowenr 					(vtol(*vpp))->lo_looping |= LO_LOOPING;
447b431137cSowenr 					return (0);
4487c478bd9Sstevel@tonic-gate 				}
4497c478bd9Sstevel@tonic-gate 			}
4507c478bd9Sstevel@tonic-gate 		} else {
4517c478bd9Sstevel@tonic-gate 			/*
4527c478bd9Sstevel@tonic-gate 			 * No frills just make the shadow node.
4537c478bd9Sstevel@tonic-gate 			 */
454b431137cSowenr 			*vpp = makelonode(vp, li, 0);
4557c478bd9Sstevel@tonic-gate 			return (0);
4567c478bd9Sstevel@tonic-gate 		}
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	nosub = (vtoli(dvp->v_vfsp)->li_flag & LO_NOSUB);
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	/*
4627c478bd9Sstevel@tonic-gate 	 * If this vnode is mounted on, then we
4637c478bd9Sstevel@tonic-gate 	 * traverse to the vnode which is the root of
4647c478bd9Sstevel@tonic-gate 	 * the mounted file system.
4657c478bd9Sstevel@tonic-gate 	 */
4667c478bd9Sstevel@tonic-gate 	if (!nosub && (error = traverse(&vp)))
4677c478bd9Sstevel@tonic-gate 		goto out;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	/*
4707c478bd9Sstevel@tonic-gate 	 * Make a lnode for the real vnode.
4717c478bd9Sstevel@tonic-gate 	 */
4727c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDIR || nosub) {
473b431137cSowenr 		*vpp = makelonode(vp, li, 0);
4747c478bd9Sstevel@tonic-gate 		if (IS_DEVVP(*vpp)) {
4757c478bd9Sstevel@tonic-gate 			vnode_t *svp;
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 			svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
4787c478bd9Sstevel@tonic-gate 			VN_RELE(*vpp);
4797c478bd9Sstevel@tonic-gate 			if (svp == NULL)
4807c478bd9Sstevel@tonic-gate 				error = ENOSYS;
4817c478bd9Sstevel@tonic-gate 			else
4827c478bd9Sstevel@tonic-gate 				*vpp = svp;
4837c478bd9Sstevel@tonic-gate 		}
4847c478bd9Sstevel@tonic-gate 		return (error);
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	/*
4887c478bd9Sstevel@tonic-gate 	 * if the found vnode (vp) is not of type lofs
4897c478bd9Sstevel@tonic-gate 	 * then we're just going to make a shadow of that
4907c478bd9Sstevel@tonic-gate 	 * vp and get out.
4917c478bd9Sstevel@tonic-gate 	 *
4927c478bd9Sstevel@tonic-gate 	 * If the found vnode (vp) is of lofs type, and
4937c478bd9Sstevel@tonic-gate 	 * we're not doing dotdot, check if we are
4947c478bd9Sstevel@tonic-gate 	 * looping.
4957c478bd9Sstevel@tonic-gate 	 */
4967c478bd9Sstevel@tonic-gate 	if (!doingdotdot && vfs_matchops(vp->v_vfsp, lo_vfsops)) {
4977c478bd9Sstevel@tonic-gate 		/*
4987c478bd9Sstevel@tonic-gate 		 * Check if we're looping, i.e.
4997c478bd9Sstevel@tonic-gate 		 * vp equals the root vp of the lofs, directly
5007c478bd9Sstevel@tonic-gate 		 * or indirectly, return the covered node.
5017c478bd9Sstevel@tonic-gate 		 */
5027c478bd9Sstevel@tonic-gate 
503b431137cSowenr 		if (!((vtol(dvp))->lo_looping & LO_LOOPING)) {
5047c478bd9Sstevel@tonic-gate 			if (vp == li->li_rootvp) {
5057c478bd9Sstevel@tonic-gate 				/*
5067c478bd9Sstevel@tonic-gate 				 * Direct looping condn.
5077c478bd9Sstevel@tonic-gate 				 * Ex:- X is / mounted directory so lookup of
5087c478bd9Sstevel@tonic-gate 				 * /X/X is a direct looping condn.
5097c478bd9Sstevel@tonic-gate 				 */
5107c478bd9Sstevel@tonic-gate 				tvp = vp;
5117c478bd9Sstevel@tonic-gate 				vp = vp->v_vfsp->vfs_vnodecovered;
5127c478bd9Sstevel@tonic-gate 				VN_HOLD(vp);
5137c478bd9Sstevel@tonic-gate 				VN_RELE(tvp);
5147c478bd9Sstevel@tonic-gate 				looping++;
5157c478bd9Sstevel@tonic-gate 			} else {
5167c478bd9Sstevel@tonic-gate 				/*
5177c478bd9Sstevel@tonic-gate 				 * Indirect looping can be defined as
5187c478bd9Sstevel@tonic-gate 				 * real lookup returning rootvp of the current
5197c478bd9Sstevel@tonic-gate 				 * tree in any level of recursion.
5207c478bd9Sstevel@tonic-gate 				 *
5217c478bd9Sstevel@tonic-gate 				 * This check is useful if there are multiple
5227c478bd9Sstevel@tonic-gate 				 * levels of lofs indirections. Suppose vnode X
5237c478bd9Sstevel@tonic-gate 				 * in the current lookup has as its real vnode
5247c478bd9Sstevel@tonic-gate 				 * another lofs node. Y = realvp(X) Y should be
5257c478bd9Sstevel@tonic-gate 				 * a lofs node for the check to continue or Y
5267c478bd9Sstevel@tonic-gate 				 * is not the rootvp of X.
5277c478bd9Sstevel@tonic-gate 				 * Ex:- say X and Y are two vnodes
5287c478bd9Sstevel@tonic-gate 				 * say real(Y) is X and real(X) is Z
5297c478bd9Sstevel@tonic-gate 				 * parent vnode for X and Y is Z
5307c478bd9Sstevel@tonic-gate 				 * lookup(Y,"path") say we are looking for Y
5317c478bd9Sstevel@tonic-gate 				 * again under Y and we have to return Yc.
5327c478bd9Sstevel@tonic-gate 				 * but the lookup of Y under Y doesnot return
5337c478bd9Sstevel@tonic-gate 				 * Y the root vnode again here is why.
5347c478bd9Sstevel@tonic-gate 				 * 1. lookup(Y,"path of Y") will go to
5357c478bd9Sstevel@tonic-gate 				 * 2. lookup(real(Y),"path of Y") and then to
5367c478bd9Sstevel@tonic-gate 				 * 3. lookup(real(X),"path of Y").
5377c478bd9Sstevel@tonic-gate 				 * and now what lookup level 1 sees is the
5387c478bd9Sstevel@tonic-gate 				 * outcome of 2 but the vnode Y is due to
5397c478bd9Sstevel@tonic-gate 				 * lookup(Z,"path of Y") so we have to skip
5407c478bd9Sstevel@tonic-gate 				 * intermediate levels to find if in any level
5417c478bd9Sstevel@tonic-gate 				 * there is a looping.
5427c478bd9Sstevel@tonic-gate 				 */
5437c478bd9Sstevel@tonic-gate 				is_indirectloop = 0;
5447c478bd9Sstevel@tonic-gate 				nonlovp = vp;
5457c478bd9Sstevel@tonic-gate 				while (
5467c478bd9Sstevel@tonic-gate 				    vfs_matchops(nonlovp->v_vfsp, lo_vfsops) &&
5477c478bd9Sstevel@tonic-gate 				    !(is_indirectloop)) {
5487c478bd9Sstevel@tonic-gate 					if (li->li_rootvp  == nonlovp) {
5497c478bd9Sstevel@tonic-gate 						is_indirectloop++;
5507c478bd9Sstevel@tonic-gate 						break;
5517c478bd9Sstevel@tonic-gate 					}
5527c478bd9Sstevel@tonic-gate 					nonlovp = realvp(nonlovp);
5537c478bd9Sstevel@tonic-gate 				}
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 				if (is_indirectloop) {
5567c478bd9Sstevel@tonic-gate 					VN_RELE(vp);
5577c478bd9Sstevel@tonic-gate 					vp = nonlovp;
5587c478bd9Sstevel@tonic-gate 					vp = vp->v_vfsp->vfs_vnodecovered;
5597c478bd9Sstevel@tonic-gate 					VN_HOLD(vp);
5607c478bd9Sstevel@tonic-gate 					looping++;
5617c478bd9Sstevel@tonic-gate 				}
5627c478bd9Sstevel@tonic-gate 			}
5637c478bd9Sstevel@tonic-gate 		} else {
5647c478bd9Sstevel@tonic-gate 			/*
5657c478bd9Sstevel@tonic-gate 			 * come here only because of the interaction between
5667c478bd9Sstevel@tonic-gate 			 * the autofs and lofs.
5677c478bd9Sstevel@tonic-gate 			 *
5687c478bd9Sstevel@tonic-gate 			 * Lookup of "/net/X/net/X" will return a shadow of
5697c478bd9Sstevel@tonic-gate 			 * an autonode X_a which we call X_l.
5707c478bd9Sstevel@tonic-gate 			 *
5717c478bd9Sstevel@tonic-gate 			 * Lookup of anything under X_l, will trigger a call to
5727c478bd9Sstevel@tonic-gate 			 * auto_lookup(X_a,nm) which will eventually call
5737c478bd9Sstevel@tonic-gate 			 * lo_lookup(X_lr,nm) where X_lr is the root vnode of
5747c478bd9Sstevel@tonic-gate 			 * the current lofs.
5757c478bd9Sstevel@tonic-gate 			 *
5767c478bd9Sstevel@tonic-gate 			 * We come here only when we are called with X_l as dvp
5777c478bd9Sstevel@tonic-gate 			 * and look for something underneath.
5787c478bd9Sstevel@tonic-gate 			 *
579b431137cSowenr 			 * Now that an autofs/lofs looping condition has been
580b431137cSowenr 			 * identified any directory vnode contained within
581b431137cSowenr 			 * dvp will be set to the vnode covered by the
582b431137cSowenr 			 * mounted autofs. Thus all directories within dvp
583b431137cSowenr 			 * will appear empty hence teminating the looping.
584b431137cSowenr 			 * The LO_AUTOLOOP flag is set on the returned lonode
585b431137cSowenr 			 * to indicate the termination of the autofs/lofs
586b431137cSowenr 			 * looping. This is required for the correct behaviour
587b431137cSowenr 			 * when performing a dotdot.
5887c478bd9Sstevel@tonic-gate 			 */
5897c478bd9Sstevel@tonic-gate 			realdvp = realvp(dvp);
5907c478bd9Sstevel@tonic-gate 			while (vfs_matchops(realdvp->v_vfsp, lo_vfsops)) {
5917c478bd9Sstevel@tonic-gate 				realdvp = realvp(realdvp);
5927c478bd9Sstevel@tonic-gate 			}
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 			error = VFS_ROOT(realdvp->v_vfsp, &tvp);
5957c478bd9Sstevel@tonic-gate 			if (error)
5967c478bd9Sstevel@tonic-gate 				goto out;
5977c478bd9Sstevel@tonic-gate 			/*
5987c478bd9Sstevel@tonic-gate 			 * tvp now contains the rootvp of the vfs of the
599b431137cSowenr 			 * real vnode of dvp. The directory vnode vp is set
600b431137cSowenr 			 * to the covered vnode to terminate looping. No
601b431137cSowenr 			 * distinction is made between any vp as all directory
602b431137cSowenr 			 * vnodes contained in dvp are returned as the covered
603b431137cSowenr 			 * vnode.
6047c478bd9Sstevel@tonic-gate 			 */
605b431137cSowenr 			VN_RELE(vp);
606*8f71b825Sowenr 			vp = tvp;	/* possibly is an autonode */
6077c478bd9Sstevel@tonic-gate 
608b431137cSowenr 			/*
609b431137cSowenr 			 * Need to find the covered vnode
610b431137cSowenr 			 */
611*8f71b825Sowenr 			if (vp->v_vfsp->vfs_vnodecovered == NULL) {
612*8f71b825Sowenr 				/*
613*8f71b825Sowenr 				 * We don't have a covered vnode so this isn't
614*8f71b825Sowenr 				 * an autonode. To find the autonode simply
615*8f71b825Sowenr 				 * find the vnode covered by the lofs rootvp.
616*8f71b825Sowenr 				 */
617*8f71b825Sowenr 				vp = li->li_rootvp;
618*8f71b825Sowenr 				vp = vp->v_vfsp->vfs_vnodecovered;
619*8f71b825Sowenr 				VN_RELE(tvp);
620*8f71b825Sowenr 				error = VFS_ROOT(vp->v_vfsp, &tvp);
621*8f71b825Sowenr 				if (error)
622*8f71b825Sowenr 					goto out;
623*8f71b825Sowenr 				vp = tvp;	/* now this is an autonode */
624*8f71b825Sowenr 				if (vp->v_vfsp->vfs_vnodecovered == NULL) {
625*8f71b825Sowenr 					/*
626*8f71b825Sowenr 					 * Still can't find a covered vnode.
627*8f71b825Sowenr 					 * Fail the lookup, or we'd loop.
628*8f71b825Sowenr 					 */
629*8f71b825Sowenr 					error = ENOENT;
630*8f71b825Sowenr 					goto out;
631*8f71b825Sowenr 				}
632*8f71b825Sowenr 			}
633b431137cSowenr 			vp = vp->v_vfsp->vfs_vnodecovered;
634b431137cSowenr 			VN_HOLD(vp);
635b431137cSowenr 			VN_RELE(tvp);
636b431137cSowenr 			/*
637b431137cSowenr 			 * Force the creation of a new lnode even if the hash
638b431137cSowenr 			 * table contains a lnode that references this vnode.
639b431137cSowenr 			 */
640b431137cSowenr 			mkflag = LOF_FORCE;
641b431137cSowenr 			autoloop++;
6427c478bd9Sstevel@tonic-gate 		}
6437c478bd9Sstevel@tonic-gate 	}
644b431137cSowenr 	*vpp = makelonode(vp, li, mkflag);
645b431137cSowenr 
646b431137cSowenr 	if ((looping) ||
647b431137cSowenr 	    (((vtol(dvp))->lo_looping & LO_LOOPING) && !doingdotdot)) {
648b431137cSowenr 		(vtol(*vpp))->lo_looping |= LO_LOOPING;
649b431137cSowenr 	}
6507c478bd9Sstevel@tonic-gate 
651b431137cSowenr 	if (autoloop) {
652b431137cSowenr 		(vtol(*vpp))->lo_looping |= LO_AUTOLOOP;
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate out:
6567c478bd9Sstevel@tonic-gate 	if (error != 0 && vp != NULL)
6577c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
6587c478bd9Sstevel@tonic-gate #ifdef LODEBUG
6597c478bd9Sstevel@tonic-gate 	lo_dprint(4,
6607c478bd9Sstevel@tonic-gate 	"lo_lookup dvp %x realdvp %x nm '%s' newvp %x real vp %x error %d\n",
6617c478bd9Sstevel@tonic-gate 		dvp, realvp(dvp), nm, *vpp, vp, error);
6627c478bd9Sstevel@tonic-gate #endif
6637c478bd9Sstevel@tonic-gate 	return (error);
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6677c478bd9Sstevel@tonic-gate static int
6687c478bd9Sstevel@tonic-gate lo_create(
6697c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
6707c478bd9Sstevel@tonic-gate 	char *nm,
6717c478bd9Sstevel@tonic-gate 	struct vattr *va,
6727c478bd9Sstevel@tonic-gate 	enum vcexcl exclusive,
6737c478bd9Sstevel@tonic-gate 	int mode,
6747c478bd9Sstevel@tonic-gate 	vnode_t **vpp,
6757c478bd9Sstevel@tonic-gate 	struct cred *cr,
6767c478bd9Sstevel@tonic-gate 	int flag)
6777c478bd9Sstevel@tonic-gate {
6787c478bd9Sstevel@tonic-gate 	int error;
6797c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL;
680c7688ab0Srd 	vnode_t *tvp = NULL;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate #ifdef LODEBUG
6837c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_create vp %p realvp %p\n", dvp, realvp(dvp));
6847c478bd9Sstevel@tonic-gate #endif
6857c478bd9Sstevel@tonic-gate 	if (*nm == '\0') {
6867c478bd9Sstevel@tonic-gate 		ASSERT(vpp && dvp == *vpp);
6877c478bd9Sstevel@tonic-gate 		vp = realvp(*vpp);
6887c478bd9Sstevel@tonic-gate 	}
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	if (IS_ZONEDEVFS(dvp)) {
691c7688ab0Srd 
692c7688ab0Srd 		/*
693c7688ab0Srd 		 * In the case of an exclusive create, *vpp will not
694c7688ab0Srd 		 * be populated.  We must check to see if the file exists.
695c7688ab0Srd 		 */
696c7688ab0Srd 		if ((exclusive == EXCL) && (*nm != '\0')) {
697c7688ab0Srd 			(void) VOP_LOOKUP(dvp, nm, &tvp, NULL, 0, NULL, cr);
698c7688ab0Srd 		}
699c7688ab0Srd 
7007c478bd9Sstevel@tonic-gate 		/* Is this truly a create?  If so, fail */
701c7688ab0Srd 		if ((*vpp == NULL) && (tvp == NULL))
7027c478bd9Sstevel@tonic-gate 			return (EACCES);
7037c478bd9Sstevel@tonic-gate 
704c7688ab0Srd 		if (tvp != NULL)
705c7688ab0Srd 			VN_RELE(tvp);
706c7688ab0Srd 
7077c478bd9Sstevel@tonic-gate 		/* Is this an open of a non-special for writing?  If so, fail */
7087c478bd9Sstevel@tonic-gate 		if (*vpp != NULL && (mode & VWRITE) && !IS_DEVVP(*vpp))
7097c478bd9Sstevel@tonic-gate 			return (EACCES);
7107c478bd9Sstevel@tonic-gate 	}
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	error = VOP_CREATE(realvp(dvp), nm, va, exclusive, mode, &vp, cr, flag);
7137c478bd9Sstevel@tonic-gate 	if (!error) {
714b431137cSowenr 		*vpp = makelonode(vp, vtoli(dvp->v_vfsp), 0);
7157c478bd9Sstevel@tonic-gate 		if (IS_DEVVP(*vpp)) {
7167c478bd9Sstevel@tonic-gate 			vnode_t *svp;
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 			svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
7197c478bd9Sstevel@tonic-gate 			VN_RELE(*vpp);
7207c478bd9Sstevel@tonic-gate 			if (svp == NULL)
7217c478bd9Sstevel@tonic-gate 				error = ENOSYS;
7227c478bd9Sstevel@tonic-gate 			else
7237c478bd9Sstevel@tonic-gate 				*vpp = svp;
7247c478bd9Sstevel@tonic-gate 		}
7257c478bd9Sstevel@tonic-gate 	}
7267c478bd9Sstevel@tonic-gate 	return (error);
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate static int
7307c478bd9Sstevel@tonic-gate lo_remove(vnode_t *dvp, char *nm, struct cred *cr)
7317c478bd9Sstevel@tonic-gate {
7327c478bd9Sstevel@tonic-gate #ifdef LODEBUG
7337c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_remove vp %p realvp %p\n", dvp, realvp(dvp));
7347c478bd9Sstevel@tonic-gate #endif
7357c478bd9Sstevel@tonic-gate 	if (IS_ZONEDEVFS(dvp))
7367c478bd9Sstevel@tonic-gate 		return (EACCES);
7377c478bd9Sstevel@tonic-gate 	dvp = realvp(dvp);
7387c478bd9Sstevel@tonic-gate 	return (VOP_REMOVE(dvp, nm, cr));
7397c478bd9Sstevel@tonic-gate }
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate static int
7427c478bd9Sstevel@tonic-gate lo_link(vnode_t *tdvp, vnode_t *vp, char *tnm, struct cred *cr)
7437c478bd9Sstevel@tonic-gate {
7447c478bd9Sstevel@tonic-gate #ifdef LODEBUG
7457c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_link vp %p realvp %p\n", vp, realvp(vp));
7467c478bd9Sstevel@tonic-gate #endif
7477c478bd9Sstevel@tonic-gate 	while (vn_matchops(vp, lo_vnodeops)) {
7487c478bd9Sstevel@tonic-gate 		if (IS_ZONEDEVFS(vp))
7497c478bd9Sstevel@tonic-gate 			return (EACCES);
7507c478bd9Sstevel@tonic-gate 		vp = realvp(vp);
7517c478bd9Sstevel@tonic-gate 	}
7527c478bd9Sstevel@tonic-gate 	while (vn_matchops(tdvp, lo_vnodeops)) {
7537c478bd9Sstevel@tonic-gate 		if (IS_ZONEDEVFS(tdvp))
7547c478bd9Sstevel@tonic-gate 			return (EACCES);
7557c478bd9Sstevel@tonic-gate 		tdvp = realvp(tdvp);
7567c478bd9Sstevel@tonic-gate 	}
7577c478bd9Sstevel@tonic-gate 	if (vp->v_vfsp != tdvp->v_vfsp)
7587c478bd9Sstevel@tonic-gate 		return (EXDEV);
7597c478bd9Sstevel@tonic-gate 	return (VOP_LINK(tdvp, vp, tnm, cr));
7607c478bd9Sstevel@tonic-gate }
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate static int
7637c478bd9Sstevel@tonic-gate lo_rename(
7647c478bd9Sstevel@tonic-gate 	vnode_t *odvp,
7657c478bd9Sstevel@tonic-gate 	char *onm,
7667c478bd9Sstevel@tonic-gate 	vnode_t *ndvp,
7677c478bd9Sstevel@tonic-gate 	char *nnm,
7687c478bd9Sstevel@tonic-gate 	struct cred *cr)
7697c478bd9Sstevel@tonic-gate {
7707c478bd9Sstevel@tonic-gate 	vnode_t *tnvp;
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate #ifdef LODEBUG
7737c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_rename vp %p realvp %p\n", odvp, realvp(odvp));
7747c478bd9Sstevel@tonic-gate #endif
7757c478bd9Sstevel@tonic-gate 	if (IS_ZONEDEVFS(odvp))
7767c478bd9Sstevel@tonic-gate 		return (EACCES);
7777c478bd9Sstevel@tonic-gate 	/*
7787c478bd9Sstevel@tonic-gate 	 * We need to make sure we're not trying to remove a mount point for a
7797c478bd9Sstevel@tonic-gate 	 * filesystem mounted on top of lofs, which only we know about.
7807c478bd9Sstevel@tonic-gate 	 */
7817c478bd9Sstevel@tonic-gate 	if (vn_matchops(ndvp, lo_vnodeops))	/* Not our problem. */
7827c478bd9Sstevel@tonic-gate 		goto rename;
7837c478bd9Sstevel@tonic-gate 	if (VOP_LOOKUP(ndvp, nnm, &tnvp, NULL, 0, NULL, cr) != 0)
7847c478bd9Sstevel@tonic-gate 		goto rename;
7857c478bd9Sstevel@tonic-gate 	if (tnvp->v_type != VDIR) {
7867c478bd9Sstevel@tonic-gate 		VN_RELE(tnvp);
7877c478bd9Sstevel@tonic-gate 		goto rename;
7887c478bd9Sstevel@tonic-gate 	}
7897c478bd9Sstevel@tonic-gate 	if (vn_mountedvfs(tnvp)) {
7907c478bd9Sstevel@tonic-gate 		VN_RELE(tnvp);
7917c478bd9Sstevel@tonic-gate 		return (EBUSY);
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 	VN_RELE(tnvp);
7947c478bd9Sstevel@tonic-gate rename:
7957c478bd9Sstevel@tonic-gate 	/*
7967c478bd9Sstevel@tonic-gate 	 * Since the case we're dealing with above can happen at any layer in
7977c478bd9Sstevel@tonic-gate 	 * the stack of lofs filesystems, we need to recurse down the stack,
7987c478bd9Sstevel@tonic-gate 	 * checking to see if there are any instances of a filesystem mounted on
7997c478bd9Sstevel@tonic-gate 	 * top of lofs. In order to keep on using the lofs version of
8007c478bd9Sstevel@tonic-gate 	 * VOP_RENAME(), we make sure that while the target directory is of type
8017c478bd9Sstevel@tonic-gate 	 * lofs, the source directory (the one used for getting the fs-specific
8027c478bd9Sstevel@tonic-gate 	 * version of VOP_RENAME()) is also of type lofs.
8037c478bd9Sstevel@tonic-gate 	 */
8047c478bd9Sstevel@tonic-gate 	if (vn_matchops(ndvp, lo_vnodeops)) {
8057c478bd9Sstevel@tonic-gate 		if (IS_ZONEDEVFS(ndvp))
8067c478bd9Sstevel@tonic-gate 			return (EACCES);
8077c478bd9Sstevel@tonic-gate 		ndvp = realvp(ndvp);	/* Check the next layer */
8087c478bd9Sstevel@tonic-gate 	} else {
8097c478bd9Sstevel@tonic-gate 		/*
8107c478bd9Sstevel@tonic-gate 		 * We can go fast here
8117c478bd9Sstevel@tonic-gate 		 */
8127c478bd9Sstevel@tonic-gate 		while (vn_matchops(odvp, lo_vnodeops)) {
8137c478bd9Sstevel@tonic-gate 			if (IS_ZONEDEVFS(odvp))
8147c478bd9Sstevel@tonic-gate 				return (EACCES);
8157c478bd9Sstevel@tonic-gate 			odvp = realvp(odvp);
8167c478bd9Sstevel@tonic-gate 		}
8177c478bd9Sstevel@tonic-gate 		if (odvp->v_vfsp != ndvp->v_vfsp)
8187c478bd9Sstevel@tonic-gate 			return (EXDEV);
8197c478bd9Sstevel@tonic-gate 	}
8207c478bd9Sstevel@tonic-gate 	return (VOP_RENAME(odvp, onm, ndvp, nnm, cr));
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate static int
8247c478bd9Sstevel@tonic-gate lo_mkdir(
8257c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
8267c478bd9Sstevel@tonic-gate 	char *nm,
8277c478bd9Sstevel@tonic-gate 	struct vattr *va,
8287c478bd9Sstevel@tonic-gate 	vnode_t **vpp,
8297c478bd9Sstevel@tonic-gate 	struct cred *cr)
8307c478bd9Sstevel@tonic-gate {
8317c478bd9Sstevel@tonic-gate 	int error;
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate #ifdef LODEBUG
8347c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_mkdir vp %p realvp %p\n", dvp, realvp(dvp));
8357c478bd9Sstevel@tonic-gate #endif
8367c478bd9Sstevel@tonic-gate 	if (IS_ZONEDEVFS(dvp))
8377c478bd9Sstevel@tonic-gate 		return (EACCES);
8387c478bd9Sstevel@tonic-gate 	error = VOP_MKDIR(realvp(dvp), nm, va, vpp, cr);
8397c478bd9Sstevel@tonic-gate 	if (!error)
840b431137cSowenr 		*vpp = makelonode(*vpp, vtoli(dvp->v_vfsp), 0);
8417c478bd9Sstevel@tonic-gate 	return (error);
8427c478bd9Sstevel@tonic-gate }
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate static int
8457c478bd9Sstevel@tonic-gate lo_realvp(vnode_t *vp, vnode_t **vpp)
8467c478bd9Sstevel@tonic-gate {
8477c478bd9Sstevel@tonic-gate #ifdef LODEBUG
8487c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_realvp %p\n", vp);
8497c478bd9Sstevel@tonic-gate #endif
8507c478bd9Sstevel@tonic-gate 	while (vn_matchops(vp, lo_vnodeops))
8517c478bd9Sstevel@tonic-gate 		vp = realvp(vp);
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	if (VOP_REALVP(vp, vpp) != 0)
8547c478bd9Sstevel@tonic-gate 		*vpp = vp;
8557c478bd9Sstevel@tonic-gate 	return (0);
8567c478bd9Sstevel@tonic-gate }
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate static int
8597c478bd9Sstevel@tonic-gate lo_rmdir(
8607c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
8617c478bd9Sstevel@tonic-gate 	char *nm,
8627c478bd9Sstevel@tonic-gate 	vnode_t *cdir,
8637c478bd9Sstevel@tonic-gate 	struct cred *cr)
8647c478bd9Sstevel@tonic-gate {
8657c478bd9Sstevel@tonic-gate 	vnode_t *rvp = cdir;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate #ifdef LODEBUG
8687c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_rmdir vp %p realvp %p\n", dvp, realvp(dvp));
8697c478bd9Sstevel@tonic-gate #endif
8707c478bd9Sstevel@tonic-gate 	if (IS_ZONEDEVFS(dvp))
8717c478bd9Sstevel@tonic-gate 		return (EACCES);
8727c478bd9Sstevel@tonic-gate 	/* if cdir is lofs vnode ptr get its real vnode ptr */
8737c478bd9Sstevel@tonic-gate 	if (vn_matchops(dvp, vn_getops(rvp)))
8747c478bd9Sstevel@tonic-gate 		(void) lo_realvp(cdir, &rvp);
8757c478bd9Sstevel@tonic-gate 	dvp = realvp(dvp);
8767c478bd9Sstevel@tonic-gate 	return (VOP_RMDIR(dvp, nm, rvp, cr));
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate static int
8807c478bd9Sstevel@tonic-gate lo_symlink(
8817c478bd9Sstevel@tonic-gate 	vnode_t *dvp,
8827c478bd9Sstevel@tonic-gate 	char *lnm,
8837c478bd9Sstevel@tonic-gate 	struct vattr *tva,
8847c478bd9Sstevel@tonic-gate 	char *tnm,
8857c478bd9Sstevel@tonic-gate 	struct cred *cr)
8867c478bd9Sstevel@tonic-gate {
8877c478bd9Sstevel@tonic-gate #ifdef LODEBUG
8887c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_symlink vp %p realvp %p\n", dvp, realvp(dvp));
8897c478bd9Sstevel@tonic-gate #endif
8907c478bd9Sstevel@tonic-gate 	if (IS_ZONEDEVFS(dvp))
8917c478bd9Sstevel@tonic-gate 		return (EACCES);
8927c478bd9Sstevel@tonic-gate 	dvp = realvp(dvp);
8937c478bd9Sstevel@tonic-gate 	return (VOP_SYMLINK(dvp, lnm, tva, tnm, cr));
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate static int
8977c478bd9Sstevel@tonic-gate lo_readlink(vnode_t *vp, struct uio *uiop, struct cred *cr)
8987c478bd9Sstevel@tonic-gate {
8997c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
9007c478bd9Sstevel@tonic-gate 	return (VOP_READLINK(vp, uiop, cr));
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate static int
9047c478bd9Sstevel@tonic-gate lo_readdir(vnode_t *vp, struct uio *uiop, struct cred *cr, int *eofp)
9057c478bd9Sstevel@tonic-gate {
9067c478bd9Sstevel@tonic-gate #ifdef LODEBUG
9077c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lo_readdir vp %p realvp %p\n", vp, realvp(vp));
9087c478bd9Sstevel@tonic-gate #endif
9097c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
9107c478bd9Sstevel@tonic-gate 	return (VOP_READDIR(vp, uiop, cr, eofp));
9117c478bd9Sstevel@tonic-gate }
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate static int
9147c478bd9Sstevel@tonic-gate lo_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct)
9157c478bd9Sstevel@tonic-gate {
9167c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
9177c478bd9Sstevel@tonic-gate 	return (VOP_RWLOCK(vp, write_lock, ct));
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate static void
9217c478bd9Sstevel@tonic-gate lo_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
9247c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, write_lock, ct);
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate static int
9287c478bd9Sstevel@tonic-gate lo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
9297c478bd9Sstevel@tonic-gate {
9307c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
9317c478bd9Sstevel@tonic-gate 	return (VOP_SEEK(vp, ooff, noffp));
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate static int
9357c478bd9Sstevel@tonic-gate lo_cmp(vnode_t *vp1, vnode_t *vp2)
9367c478bd9Sstevel@tonic-gate {
9377c478bd9Sstevel@tonic-gate 	while (vn_matchops(vp1, lo_vnodeops))
9387c478bd9Sstevel@tonic-gate 		vp1 = realvp(vp1);
9397c478bd9Sstevel@tonic-gate 	while (vn_matchops(vp2, lo_vnodeops))
9407c478bd9Sstevel@tonic-gate 		vp2 = realvp(vp2);
9417c478bd9Sstevel@tonic-gate 	return (VOP_CMP(vp1, vp2));
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate static int
9457c478bd9Sstevel@tonic-gate lo_frlock(
9467c478bd9Sstevel@tonic-gate 	vnode_t *vp,
9477c478bd9Sstevel@tonic-gate 	int cmd,
9487c478bd9Sstevel@tonic-gate 	struct flock64 *bfp,
9497c478bd9Sstevel@tonic-gate 	int flag,
9507c478bd9Sstevel@tonic-gate 	offset_t offset,
9517c478bd9Sstevel@tonic-gate 	struct flk_callback *flk_cbp,
9527c478bd9Sstevel@tonic-gate 	cred_t *cr)
9537c478bd9Sstevel@tonic-gate {
9547c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
9557c478bd9Sstevel@tonic-gate 	return (VOP_FRLOCK(vp, cmd, bfp, flag, offset, flk_cbp, cr));
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate static int
9597c478bd9Sstevel@tonic-gate lo_space(
9607c478bd9Sstevel@tonic-gate 	vnode_t *vp,
9617c478bd9Sstevel@tonic-gate 	int cmd,
9627c478bd9Sstevel@tonic-gate 	struct flock64 *bfp,
9637c478bd9Sstevel@tonic-gate 	int flag,
9647c478bd9Sstevel@tonic-gate 	offset_t offset,
9657c478bd9Sstevel@tonic-gate 	struct cred *cr,
9667c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
9677c478bd9Sstevel@tonic-gate {
9687c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
9697c478bd9Sstevel@tonic-gate 	return (VOP_SPACE(vp, cmd, bfp, flag, offset, cr, ct));
9707c478bd9Sstevel@tonic-gate }
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate static int
9737c478bd9Sstevel@tonic-gate lo_getpage(
9747c478bd9Sstevel@tonic-gate 	vnode_t *vp,
9757c478bd9Sstevel@tonic-gate 	offset_t off,
9767c478bd9Sstevel@tonic-gate 	size_t len,
9777c478bd9Sstevel@tonic-gate 	uint_t *prot,
9787c478bd9Sstevel@tonic-gate 	struct page *parr[],
9797c478bd9Sstevel@tonic-gate 	size_t psz,
9807c478bd9Sstevel@tonic-gate 	struct seg *seg,
9817c478bd9Sstevel@tonic-gate 	caddr_t addr,
9827c478bd9Sstevel@tonic-gate 	enum seg_rw rw,
9837c478bd9Sstevel@tonic-gate 	struct cred *cr)
9847c478bd9Sstevel@tonic-gate {
9857c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
9867c478bd9Sstevel@tonic-gate 	return (VOP_GETPAGE(vp, off, len, prot, parr, psz, seg, addr, rw, cr));
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate static int
9907c478bd9Sstevel@tonic-gate lo_putpage(vnode_t *vp, offset_t off, size_t len, int flags, struct cred *cr)
9917c478bd9Sstevel@tonic-gate {
9927c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
9937c478bd9Sstevel@tonic-gate 	return (VOP_PUTPAGE(vp, off, len, flags, cr));
9947c478bd9Sstevel@tonic-gate }
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate static int
9977c478bd9Sstevel@tonic-gate lo_map(
9987c478bd9Sstevel@tonic-gate 	vnode_t *vp,
9997c478bd9Sstevel@tonic-gate 	offset_t off,
10007c478bd9Sstevel@tonic-gate 	struct as *as,
10017c478bd9Sstevel@tonic-gate 	caddr_t *addrp,
10027c478bd9Sstevel@tonic-gate 	size_t len,
10037c478bd9Sstevel@tonic-gate 	uchar_t prot,
10047c478bd9Sstevel@tonic-gate 	uchar_t maxprot,
10057c478bd9Sstevel@tonic-gate 	uint_t flags,
10067c478bd9Sstevel@tonic-gate 	struct cred *cr)
10077c478bd9Sstevel@tonic-gate {
10087c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
10097c478bd9Sstevel@tonic-gate 	return (VOP_MAP(vp, off, as, addrp, len, prot, maxprot, flags, cr));
10107c478bd9Sstevel@tonic-gate }
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate static int
10137c478bd9Sstevel@tonic-gate lo_addmap(
10147c478bd9Sstevel@tonic-gate 	vnode_t *vp,
10157c478bd9Sstevel@tonic-gate 	offset_t off,
10167c478bd9Sstevel@tonic-gate 	struct as *as,
10177c478bd9Sstevel@tonic-gate 	caddr_t addr,
10187c478bd9Sstevel@tonic-gate 	size_t len,
10197c478bd9Sstevel@tonic-gate 	uchar_t prot,
10207c478bd9Sstevel@tonic-gate 	uchar_t maxprot,
10217c478bd9Sstevel@tonic-gate 	uint_t flags,
10227c478bd9Sstevel@tonic-gate 	struct cred *cr)
10237c478bd9Sstevel@tonic-gate {
10247c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
10257c478bd9Sstevel@tonic-gate 	return (VOP_ADDMAP(vp, off, as, addr, len, prot, maxprot, flags, cr));
10267c478bd9Sstevel@tonic-gate }
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate static int
10297c478bd9Sstevel@tonic-gate lo_delmap(
10307c478bd9Sstevel@tonic-gate 	vnode_t *vp,
10317c478bd9Sstevel@tonic-gate 	offset_t off,
10327c478bd9Sstevel@tonic-gate 	struct as *as,
10337c478bd9Sstevel@tonic-gate 	caddr_t addr,
10347c478bd9Sstevel@tonic-gate 	size_t len,
10357c478bd9Sstevel@tonic-gate 	uint_t prot,
10367c478bd9Sstevel@tonic-gate 	uint_t maxprot,
10377c478bd9Sstevel@tonic-gate 	uint_t flags,
10387c478bd9Sstevel@tonic-gate 	struct cred *cr)
10397c478bd9Sstevel@tonic-gate {
10407c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
10417c478bd9Sstevel@tonic-gate 	return (VOP_DELMAP(vp, off, as, addr, len, prot, maxprot, flags, cr));
10427c478bd9Sstevel@tonic-gate }
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate static int
10457c478bd9Sstevel@tonic-gate lo_poll(
10467c478bd9Sstevel@tonic-gate 	vnode_t *vp,
10477c478bd9Sstevel@tonic-gate 	short events,
10487c478bd9Sstevel@tonic-gate 	int anyyet,
10497c478bd9Sstevel@tonic-gate 	short *reventsp,
10507c478bd9Sstevel@tonic-gate 	struct pollhead **phpp)
10517c478bd9Sstevel@tonic-gate {
10527c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
10537c478bd9Sstevel@tonic-gate 	return (VOP_POLL(vp, events, anyyet, reventsp, phpp));
10547c478bd9Sstevel@tonic-gate }
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate static int
10577c478bd9Sstevel@tonic-gate lo_dump(vnode_t *vp, caddr_t addr, int bn, int count)
10587c478bd9Sstevel@tonic-gate {
10597c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
10607c478bd9Sstevel@tonic-gate 	return (VOP_DUMP(vp, addr, bn, count));
10617c478bd9Sstevel@tonic-gate }
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate static int
10647c478bd9Sstevel@tonic-gate lo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, struct cred *cr)
10657c478bd9Sstevel@tonic-gate {
10667c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
10677c478bd9Sstevel@tonic-gate 	return (VOP_PATHCONF(vp, cmd, valp, cr));
10687c478bd9Sstevel@tonic-gate }
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate static int
10717c478bd9Sstevel@tonic-gate lo_pageio(
10727c478bd9Sstevel@tonic-gate 	vnode_t *vp,
10737c478bd9Sstevel@tonic-gate 	struct page *pp,
10747c478bd9Sstevel@tonic-gate 	u_offset_t io_off,
10757c478bd9Sstevel@tonic-gate 	size_t io_len,
10767c478bd9Sstevel@tonic-gate 	int flags,
10777c478bd9Sstevel@tonic-gate 	cred_t *cr)
10787c478bd9Sstevel@tonic-gate {
10797c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
10807c478bd9Sstevel@tonic-gate 	return (VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr));
10817c478bd9Sstevel@tonic-gate }
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate static void
10847c478bd9Sstevel@tonic-gate lo_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr)
10857c478bd9Sstevel@tonic-gate {
10867c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
10877c478bd9Sstevel@tonic-gate 	if (vp != NULL && vp != &kvp)
10887c478bd9Sstevel@tonic-gate 		VOP_DISPOSE(vp, pp, fl, dn, cr);
10897c478bd9Sstevel@tonic-gate }
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate static int
10927c478bd9Sstevel@tonic-gate lo_setsecattr(vnode_t *vp, vsecattr_t *secattr, int flags, struct cred *cr)
10937c478bd9Sstevel@tonic-gate {
10947c478bd9Sstevel@tonic-gate 	if (vn_is_readonly(vp))
10957c478bd9Sstevel@tonic-gate 		return (EROFS);
10967c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
10977c478bd9Sstevel@tonic-gate 	return (VOP_SETSECATTR(vp, secattr, flags, cr));
10987c478bd9Sstevel@tonic-gate }
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate static int
11017c478bd9Sstevel@tonic-gate lo_getsecattr(vnode_t *vp, vsecattr_t *secattr, int flags, struct cred *cr)
11027c478bd9Sstevel@tonic-gate {
11037c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
11047c478bd9Sstevel@tonic-gate 	return (VOP_GETSECATTR(vp, secattr, flags, cr));
11057c478bd9Sstevel@tonic-gate }
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate static int
11087c478bd9Sstevel@tonic-gate lo_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
11097c478bd9Sstevel@tonic-gate {
11107c478bd9Sstevel@tonic-gate 	vp = realvp(vp);
11117c478bd9Sstevel@tonic-gate 	return (VOP_SHRLOCK(vp, cmd, shr, flag, cr));
11127c478bd9Sstevel@tonic-gate }
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate /*
11157c478bd9Sstevel@tonic-gate  * Loopback vnode operations vector.
11167c478bd9Sstevel@tonic-gate  */
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate struct vnodeops *lo_vnodeops;
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate const fs_operation_def_t lo_vnodeops_template[] = {
11217c478bd9Sstevel@tonic-gate 	VOPNAME_OPEN, lo_open,
11227c478bd9Sstevel@tonic-gate 	VOPNAME_CLOSE, lo_close,
11237c478bd9Sstevel@tonic-gate 	VOPNAME_READ, lo_read,
11247c478bd9Sstevel@tonic-gate 	VOPNAME_WRITE, lo_write,
11257c478bd9Sstevel@tonic-gate 	VOPNAME_IOCTL, lo_ioctl,
11267c478bd9Sstevel@tonic-gate 	VOPNAME_SETFL, lo_setfl,
11277c478bd9Sstevel@tonic-gate 	VOPNAME_GETATTR, lo_getattr,
11287c478bd9Sstevel@tonic-gate 	VOPNAME_SETATTR, lo_setattr,
11297c478bd9Sstevel@tonic-gate 	VOPNAME_ACCESS, lo_access,
11307c478bd9Sstevel@tonic-gate 	VOPNAME_LOOKUP, lo_lookup,
11317c478bd9Sstevel@tonic-gate 	VOPNAME_CREATE, lo_create,
11327c478bd9Sstevel@tonic-gate 	VOPNAME_REMOVE, lo_remove,
11337c478bd9Sstevel@tonic-gate 	VOPNAME_LINK, lo_link,
11347c478bd9Sstevel@tonic-gate 	VOPNAME_RENAME, lo_rename,
11357c478bd9Sstevel@tonic-gate 	VOPNAME_MKDIR, lo_mkdir,
11367c478bd9Sstevel@tonic-gate 	VOPNAME_RMDIR, lo_rmdir,
11377c478bd9Sstevel@tonic-gate 	VOPNAME_READDIR, lo_readdir,
11387c478bd9Sstevel@tonic-gate 	VOPNAME_SYMLINK, lo_symlink,
11397c478bd9Sstevel@tonic-gate 	VOPNAME_READLINK, lo_readlink,
11407c478bd9Sstevel@tonic-gate 	VOPNAME_FSYNC, lo_fsync,
11417c478bd9Sstevel@tonic-gate 	VOPNAME_INACTIVE, (fs_generic_func_p) lo_inactive,
11427c478bd9Sstevel@tonic-gate 	VOPNAME_FID, lo_fid,
11437c478bd9Sstevel@tonic-gate 	VOPNAME_RWLOCK, lo_rwlock,
11447c478bd9Sstevel@tonic-gate 	VOPNAME_RWUNLOCK, (fs_generic_func_p) lo_rwunlock,
11457c478bd9Sstevel@tonic-gate 	VOPNAME_SEEK, lo_seek,
11467c478bd9Sstevel@tonic-gate 	VOPNAME_CMP, lo_cmp,
11477c478bd9Sstevel@tonic-gate 	VOPNAME_FRLOCK, lo_frlock,
11487c478bd9Sstevel@tonic-gate 	VOPNAME_SPACE, lo_space,
11497c478bd9Sstevel@tonic-gate 	VOPNAME_REALVP, lo_realvp,
11507c478bd9Sstevel@tonic-gate 	VOPNAME_GETPAGE, lo_getpage,
11517c478bd9Sstevel@tonic-gate 	VOPNAME_PUTPAGE, lo_putpage,
11527c478bd9Sstevel@tonic-gate 	VOPNAME_MAP, (fs_generic_func_p) lo_map,
11537c478bd9Sstevel@tonic-gate 	VOPNAME_ADDMAP, (fs_generic_func_p) lo_addmap,
11547c478bd9Sstevel@tonic-gate 	VOPNAME_DELMAP, lo_delmap,
11557c478bd9Sstevel@tonic-gate 	VOPNAME_POLL, (fs_generic_func_p) lo_poll,
11567c478bd9Sstevel@tonic-gate 	VOPNAME_DUMP, lo_dump,
11577c478bd9Sstevel@tonic-gate 	VOPNAME_DUMPCTL, fs_error,		/* XXX - why? */
11587c478bd9Sstevel@tonic-gate 	VOPNAME_PATHCONF, lo_pathconf,
11597c478bd9Sstevel@tonic-gate 	VOPNAME_PAGEIO, lo_pageio,
11607c478bd9Sstevel@tonic-gate 	VOPNAME_DISPOSE, (fs_generic_func_p) lo_dispose,
11617c478bd9Sstevel@tonic-gate 	VOPNAME_SETSECATTR, lo_setsecattr,
11627c478bd9Sstevel@tonic-gate 	VOPNAME_GETSECATTR, lo_getsecattr,
11637c478bd9Sstevel@tonic-gate 	VOPNAME_SHRLOCK, lo_shrlock,
11647c478bd9Sstevel@tonic-gate 	NULL, NULL
11657c478bd9Sstevel@tonic-gate };
1166