10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51314Sowenr * Common Development and Distribution License (the "License").
61314Sowenr * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*6264Srm15945 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/errno.h>
310Sstevel@tonic-gate #include <sys/vnode.h>
320Sstevel@tonic-gate #include <sys/vfs.h>
333898Srsb #include <sys/vfs_opreg.h>
340Sstevel@tonic-gate #include <sys/uio.h>
350Sstevel@tonic-gate #include <sys/cred.h>
360Sstevel@tonic-gate #include <sys/pathname.h>
370Sstevel@tonic-gate #include <sys/debug.h>
380Sstevel@tonic-gate #include <sys/fs/lofs_node.h>
390Sstevel@tonic-gate #include <sys/fs/lofs_info.h>
400Sstevel@tonic-gate #include <fs/fs_subr.h>
410Sstevel@tonic-gate #include <vm/as.h>
420Sstevel@tonic-gate #include <vm/seg.h>
430Sstevel@tonic-gate
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate * These are the vnode ops routines which implement the vnode interface to
460Sstevel@tonic-gate * the looped-back file system. These routines just take their parameters,
470Sstevel@tonic-gate * and then calling the appropriate real vnode routine(s) to do the work.
480Sstevel@tonic-gate */
490Sstevel@tonic-gate
500Sstevel@tonic-gate static int
lo_open(vnode_t ** vpp,int flag,struct cred * cr,caller_context_t * ct)515331Samw lo_open(vnode_t **vpp, int flag, struct cred *cr, caller_context_t *ct)
520Sstevel@tonic-gate {
530Sstevel@tonic-gate vnode_t *vp = *vpp;
540Sstevel@tonic-gate vnode_t *rvp;
550Sstevel@tonic-gate vnode_t *oldvp;
560Sstevel@tonic-gate int error;
570Sstevel@tonic-gate
580Sstevel@tonic-gate #ifdef LODEBUG
590Sstevel@tonic-gate lo_dprint(4, "lo_open vp %p cnt=%d realvp %p cnt=%d\n",
60*6264Srm15945 vp, vp->v_count, realvp(vp), realvp(vp)->v_count);
610Sstevel@tonic-gate #endif
620Sstevel@tonic-gate
630Sstevel@tonic-gate oldvp = vp;
640Sstevel@tonic-gate vp = rvp = realvp(vp);
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate * Need to hold new reference to vp since VOP_OPEN() may
670Sstevel@tonic-gate * decide to release it.
680Sstevel@tonic-gate */
690Sstevel@tonic-gate VN_HOLD(vp);
705331Samw error = VOP_OPEN(&rvp, flag, cr, ct);
710Sstevel@tonic-gate
720Sstevel@tonic-gate if (!error && rvp != vp) {
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate * the FS which we called should have released the
750Sstevel@tonic-gate * new reference on vp
760Sstevel@tonic-gate */
77324Sowenr *vpp = makelonode(rvp, vtoli(oldvp->v_vfsp), 0);
781314Sowenr if ((*vpp)->v_type == VDIR) {
791314Sowenr /*
801314Sowenr * Copy over any looping flags to the new lnode.
811314Sowenr */
821314Sowenr (vtol(*vpp))->lo_looping |= (vtol(oldvp))->lo_looping;
831314Sowenr }
840Sstevel@tonic-gate if (IS_DEVVP(*vpp)) {
850Sstevel@tonic-gate vnode_t *svp;
860Sstevel@tonic-gate
870Sstevel@tonic-gate svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
880Sstevel@tonic-gate VN_RELE(*vpp);
890Sstevel@tonic-gate if (svp == NULL)
900Sstevel@tonic-gate error = ENOSYS;
910Sstevel@tonic-gate else
920Sstevel@tonic-gate *vpp = svp;
930Sstevel@tonic-gate }
940Sstevel@tonic-gate VN_RELE(oldvp);
950Sstevel@tonic-gate } else {
960Sstevel@tonic-gate ASSERT(rvp->v_count > 1);
970Sstevel@tonic-gate VN_RELE(rvp);
980Sstevel@tonic-gate }
990Sstevel@tonic-gate
1000Sstevel@tonic-gate return (error);
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate static int
lo_close(vnode_t * vp,int flag,int count,offset_t offset,struct cred * cr,caller_context_t * ct)1040Sstevel@tonic-gate lo_close(
1050Sstevel@tonic-gate vnode_t *vp,
1060Sstevel@tonic-gate int flag,
1070Sstevel@tonic-gate int count,
1080Sstevel@tonic-gate offset_t offset,
1095331Samw struct cred *cr,
1105331Samw caller_context_t *ct)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate #ifdef LODEBUG
1130Sstevel@tonic-gate lo_dprint(4, "lo_close vp %p realvp %p\n", vp, realvp(vp));
1140Sstevel@tonic-gate #endif
1150Sstevel@tonic-gate vp = realvp(vp);
1165331Samw return (VOP_CLOSE(vp, flag, count, offset, cr, ct));
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate static int
lo_read(vnode_t * vp,struct uio * uiop,int ioflag,struct cred * cr,caller_context_t * ct)1200Sstevel@tonic-gate lo_read(vnode_t *vp, struct uio *uiop, int ioflag, struct cred *cr,
1210Sstevel@tonic-gate caller_context_t *ct)
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate #ifdef LODEBUG
1240Sstevel@tonic-gate lo_dprint(4, "lo_read vp %p realvp %p\n", vp, realvp(vp));
1250Sstevel@tonic-gate #endif
1260Sstevel@tonic-gate vp = realvp(vp);
1270Sstevel@tonic-gate return (VOP_READ(vp, uiop, ioflag, cr, ct));
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate static int
lo_write(vnode_t * vp,struct uio * uiop,int ioflag,struct cred * cr,caller_context_t * ct)1310Sstevel@tonic-gate lo_write(vnode_t *vp, struct uio *uiop, int ioflag, struct cred *cr,
1320Sstevel@tonic-gate caller_context_t *ct)
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate #ifdef LODEBUG
1350Sstevel@tonic-gate lo_dprint(4, "lo_write vp %p realvp %p\n", vp, realvp(vp));
1360Sstevel@tonic-gate #endif
1370Sstevel@tonic-gate vp = realvp(vp);
1380Sstevel@tonic-gate return (VOP_WRITE(vp, uiop, ioflag, cr, ct));
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate static int
lo_ioctl(vnode_t * vp,int cmd,intptr_t arg,int flag,struct cred * cr,int * rvalp,caller_context_t * ct)1420Sstevel@tonic-gate lo_ioctl(
1430Sstevel@tonic-gate vnode_t *vp,
1440Sstevel@tonic-gate int cmd,
1450Sstevel@tonic-gate intptr_t arg,
1460Sstevel@tonic-gate int flag,
1470Sstevel@tonic-gate struct cred *cr,
1485331Samw int *rvalp,
1495331Samw caller_context_t *ct)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate #ifdef LODEBUG
1520Sstevel@tonic-gate lo_dprint(4, "lo_ioctl vp %p realvp %p\n", vp, realvp(vp));
1530Sstevel@tonic-gate #endif
1540Sstevel@tonic-gate vp = realvp(vp);
1555331Samw return (VOP_IOCTL(vp, cmd, arg, flag, cr, rvalp, ct));
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate static int
lo_setfl(vnode_t * vp,int oflags,int nflags,cred_t * cr,caller_context_t * ct)1595331Samw lo_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct)
1600Sstevel@tonic-gate {
1610Sstevel@tonic-gate vp = realvp(vp);
1625331Samw return (VOP_SETFL(vp, oflags, nflags, cr, ct));
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate static int
lo_getattr(vnode_t * vp,struct vattr * vap,int flags,struct cred * cr,caller_context_t * ct)1660Sstevel@tonic-gate lo_getattr(
1670Sstevel@tonic-gate vnode_t *vp,
1680Sstevel@tonic-gate struct vattr *vap,
1690Sstevel@tonic-gate int flags,
1705331Samw struct cred *cr,
1715331Samw caller_context_t *ct)
1720Sstevel@tonic-gate {
1730Sstevel@tonic-gate int error;
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate #ifdef LODEBUG
1760Sstevel@tonic-gate lo_dprint(4, "lo_getattr vp %p realvp %p\n", vp, realvp(vp));
1770Sstevel@tonic-gate #endif
1785331Samw if (error = VOP_GETATTR(realvp(vp), vap, flags, cr, ct))
1790Sstevel@tonic-gate return (error);
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate return (0);
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate static int
lo_setattr(vnode_t * vp,struct vattr * vap,int flags,struct cred * cr,caller_context_t * ct)1850Sstevel@tonic-gate lo_setattr(
1860Sstevel@tonic-gate vnode_t *vp,
1870Sstevel@tonic-gate struct vattr *vap,
1880Sstevel@tonic-gate int flags,
1890Sstevel@tonic-gate struct cred *cr,
1900Sstevel@tonic-gate caller_context_t *ct)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate #ifdef LODEBUG
1930Sstevel@tonic-gate lo_dprint(4, "lo_setattr vp %p realvp %p\n", vp, realvp(vp));
1940Sstevel@tonic-gate #endif
1950Sstevel@tonic-gate vp = realvp(vp);
1960Sstevel@tonic-gate return (VOP_SETATTR(vp, vap, flags, cr, ct));
1970Sstevel@tonic-gate }
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate static int
lo_access(vnode_t * vp,int mode,int flags,struct cred * cr,caller_context_t * ct)2005331Samw lo_access(
2015331Samw vnode_t *vp,
2025331Samw int mode,
2035331Samw int flags,
2045331Samw struct cred *cr,
2055331Samw caller_context_t *ct)
2060Sstevel@tonic-gate {
2070Sstevel@tonic-gate #ifdef LODEBUG
2080Sstevel@tonic-gate lo_dprint(4, "lo_access vp %p realvp %p\n", vp, realvp(vp));
2090Sstevel@tonic-gate #endif
2100Sstevel@tonic-gate if (mode & VWRITE) {
2110Sstevel@tonic-gate if (vp->v_type == VREG && vn_is_readonly(vp))
2120Sstevel@tonic-gate return (EROFS);
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate vp = realvp(vp);
2155331Samw return (VOP_ACCESS(vp, mode, flags, cr, ct));
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate static int
lo_fsync(vnode_t * vp,int syncflag,struct cred * cr,caller_context_t * ct)2195331Samw lo_fsync(vnode_t *vp, int syncflag, struct cred *cr, caller_context_t *ct)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate #ifdef LODEBUG
2220Sstevel@tonic-gate lo_dprint(4, "lo_fsync vp %p realvp %p\n", vp, realvp(vp));
2230Sstevel@tonic-gate #endif
2240Sstevel@tonic-gate vp = realvp(vp);
2255331Samw return (VOP_FSYNC(vp, syncflag, cr, ct));
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate /*ARGSUSED*/
2290Sstevel@tonic-gate static void
lo_inactive(vnode_t * vp,struct cred * cr,caller_context_t * ct)2305331Samw lo_inactive(vnode_t *vp, struct cred *cr, caller_context_t *ct)
2310Sstevel@tonic-gate {
2320Sstevel@tonic-gate #ifdef LODEBUG
2330Sstevel@tonic-gate lo_dprint(4, "lo_inactive %p, realvp %p\n", vp, realvp(vp));
2340Sstevel@tonic-gate #endif
2350Sstevel@tonic-gate freelonode(vtol(vp));
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate /* ARGSUSED */
2390Sstevel@tonic-gate static int
lo_fid(vnode_t * vp,struct fid * fidp,caller_context_t * ct)2405331Samw lo_fid(vnode_t *vp, struct fid *fidp, caller_context_t *ct)
2410Sstevel@tonic-gate {
2420Sstevel@tonic-gate #ifdef LODEBUG
2430Sstevel@tonic-gate lo_dprint(4, "lo_fid %p, realvp %p\n", vp, realvp(vp));
2440Sstevel@tonic-gate #endif
2450Sstevel@tonic-gate vp = realvp(vp);
2465331Samw return (VOP_FID(vp, fidp, ct));
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate /*
2500Sstevel@tonic-gate * Given a vnode of lofs type, lookup nm name and
2510Sstevel@tonic-gate * return a shadow vnode (of lofs type) of the
2520Sstevel@tonic-gate * real vnode found.
2530Sstevel@tonic-gate *
2540Sstevel@tonic-gate * Due to the nature of lofs, there is a potential
2550Sstevel@tonic-gate * looping in path traversal.
2560Sstevel@tonic-gate *
2570Sstevel@tonic-gate * starting from the mount point of an lofs;
2580Sstevel@tonic-gate * a loop is defined to be a traversal path
2590Sstevel@tonic-gate * where the mount point or the real vnode of
2600Sstevel@tonic-gate * the root of this lofs is encountered twice.
2610Sstevel@tonic-gate * Once at the start of traversal and second
2620Sstevel@tonic-gate * when the looping is found.
2630Sstevel@tonic-gate *
2640Sstevel@tonic-gate * When a loop is encountered, a shadow of the
2650Sstevel@tonic-gate * covered vnode is returned to stop the looping.
2660Sstevel@tonic-gate *
2670Sstevel@tonic-gate * This normally works, but with the advent of
2680Sstevel@tonic-gate * the new automounter, returning the shadow of the
2690Sstevel@tonic-gate * covered vnode (autonode, in this case) does not
2700Sstevel@tonic-gate * stop the loop. Because further lookup on this
2710Sstevel@tonic-gate * lonode will cause the autonode to call lo_lookup()
2720Sstevel@tonic-gate * on the lonode covering it.
2730Sstevel@tonic-gate *
2740Sstevel@tonic-gate * example "/net/jurassic/net/jurassic" is a loop.
2750Sstevel@tonic-gate * returning the shadow of the autonode corresponding to
2760Sstevel@tonic-gate * "/net/jurassic/net/jurassic" will not terminate the
2770Sstevel@tonic-gate * loop. To solve this problem we allow the loop to go
278324Sowenr * through one more level component lookup. Whichever
279324Sowenr * directory is then looked up in "/net/jurassic/net/jurassic"
280324Sowenr * the vnode returned is the vnode covered by the autonode
281324Sowenr * "net" and this will terminate the loop.
2820Sstevel@tonic-gate *
2830Sstevel@tonic-gate * Lookup for dot dot has to be dealt with separately.
2840Sstevel@tonic-gate * It will be nice to have a "one size fits all" kind
2850Sstevel@tonic-gate * of solution, so that we don't have so many ifs statement
2860Sstevel@tonic-gate * in the lo_lookup() to handle dotdot. But, since
2870Sstevel@tonic-gate * there are so many special cases to handle different
2880Sstevel@tonic-gate * kinds looping above, we need special codes to handle
2890Sstevel@tonic-gate * dotdot lookup as well.
2900Sstevel@tonic-gate */
2910Sstevel@tonic-gate static int
lo_lookup(vnode_t * dvp,char * nm,vnode_t ** vpp,struct pathname * pnp,int flags,vnode_t * rdir,struct cred * cr,caller_context_t * ct,int * direntflags,pathname_t * realpnp)2920Sstevel@tonic-gate lo_lookup(
2930Sstevel@tonic-gate vnode_t *dvp,
2940Sstevel@tonic-gate char *nm,
2950Sstevel@tonic-gate vnode_t **vpp,
2960Sstevel@tonic-gate struct pathname *pnp,
2970Sstevel@tonic-gate int flags,
2980Sstevel@tonic-gate vnode_t *rdir,
2995331Samw struct cred *cr,
3005331Samw caller_context_t *ct,
3015331Samw int *direntflags,
3025331Samw pathname_t *realpnp)
3030Sstevel@tonic-gate {
3040Sstevel@tonic-gate vnode_t *vp = NULL, *tvp = NULL, *nonlovp;
3050Sstevel@tonic-gate int error, is_indirectloop;
3060Sstevel@tonic-gate vnode_t *realdvp = realvp(dvp);
3070Sstevel@tonic-gate struct loinfo *li = vtoli(dvp->v_vfsp);
3080Sstevel@tonic-gate int looping = 0;
309324Sowenr int autoloop = 0;
3100Sstevel@tonic-gate int doingdotdot = 0;
3110Sstevel@tonic-gate int nosub = 0;
312324Sowenr int mkflag = 0;
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate /*
3150Sstevel@tonic-gate * If name is empty and no XATTR flags are set, then return
3160Sstevel@tonic-gate * dvp (empty name == lookup "."). If an XATTR flag is set
3170Sstevel@tonic-gate * then we need to call VOP_LOOKUP to get the xattr dir.
3180Sstevel@tonic-gate */
3190Sstevel@tonic-gate if (nm[0] == '\0' && ! (flags & (CREATE_XATTR_DIR|LOOKUP_XATTR))) {
3200Sstevel@tonic-gate VN_HOLD(dvp);
3210Sstevel@tonic-gate *vpp = dvp;
3220Sstevel@tonic-gate return (0);
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate if (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0') {
3260Sstevel@tonic-gate doingdotdot++;
3270Sstevel@tonic-gate /*
3280Sstevel@tonic-gate * Handle ".." out of mounted filesystem
3290Sstevel@tonic-gate */
3300Sstevel@tonic-gate while ((realdvp->v_flag & VROOT) && realdvp != rootdir) {
3310Sstevel@tonic-gate realdvp = realdvp->v_vfsp->vfs_vnodecovered;
3320Sstevel@tonic-gate ASSERT(realdvp != NULL);
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate *vpp = NULL; /* default(error) case */
3370Sstevel@tonic-gate
3380Sstevel@tonic-gate /*
3390Sstevel@tonic-gate * Do the normal lookup
3400Sstevel@tonic-gate */
3415331Samw if (error = VOP_LOOKUP(realdvp, nm, &vp, pnp, flags, rdir, cr,
3425331Samw ct, direntflags, realpnp)) {
3431085Smarks vp = NULL;
3440Sstevel@tonic-gate goto out;
3451085Smarks }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate /*
3480Sstevel@tonic-gate * We do this check here to avoid returning a stale file handle to the
3490Sstevel@tonic-gate * caller.
3500Sstevel@tonic-gate */
3510Sstevel@tonic-gate if (nm[0] == '.' && nm[1] == '\0') {
3520Sstevel@tonic-gate ASSERT(vp == realdvp);
3530Sstevel@tonic-gate VN_HOLD(dvp);
3540Sstevel@tonic-gate VN_RELE(vp);
3550Sstevel@tonic-gate *vpp = dvp;
3560Sstevel@tonic-gate return (0);
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate if (doingdotdot) {
360324Sowenr if ((vtol(dvp))->lo_looping & LO_LOOPING) {
3610Sstevel@tonic-gate vfs_t *vfsp;
3620Sstevel@tonic-gate
3631153Snr123932 error = vn_vfsrlock_wait(realdvp);
3640Sstevel@tonic-gate if (error)
3650Sstevel@tonic-gate goto out;
3660Sstevel@tonic-gate vfsp = vn_mountedvfs(realdvp);
367324Sowenr /*
368324Sowenr * In the standard case if the looping flag is set and
369324Sowenr * performing dotdot we would be returning from a
370324Sowenr * covered vnode, implying vfsp could not be null. The
371324Sowenr * exceptions being if we have looping and overlay
372324Sowenr * mounts or looping and covered file systems.
373324Sowenr */
374324Sowenr if (vfsp == NULL) {
3750Sstevel@tonic-gate /*
376324Sowenr * Overlay mount or covered file system,
377324Sowenr * so just make the shadow node.
3780Sstevel@tonic-gate */
3790Sstevel@tonic-gate vn_vfsunlock(realdvp);
380324Sowenr *vpp = makelonode(vp, li, 0);
381324Sowenr (vtol(*vpp))->lo_looping |= LO_LOOPING;
382324Sowenr return (0);
383324Sowenr }
384324Sowenr /*
385324Sowenr * When looping get the actual found vnode
386324Sowenr * instead of the vnode covered.
387324Sowenr * Here we have to hold the lock for realdvp
388324Sowenr * since an unmount during the traversal to the
389324Sowenr * root vnode would turn *vfsp into garbage
390324Sowenr * which would be fatal.
391324Sowenr */
3921153Snr123932 error = VFS_ROOT(vfsp, &tvp);
393324Sowenr vn_vfsunlock(realdvp);
3940Sstevel@tonic-gate
395324Sowenr if (error)
396324Sowenr goto out;
3971153Snr123932
398324Sowenr if ((tvp == li->li_rootvp) && (vp == realvp(tvp))) {
399324Sowenr /*
400324Sowenr * we're back at the real vnode
401324Sowenr * of the rootvp
402324Sowenr *
403324Sowenr * return the rootvp
404324Sowenr * Ex: /mnt/mnt/..
405324Sowenr * where / has been lofs-mounted
406324Sowenr * onto /mnt. Return the lofs
407324Sowenr * node mounted at /mnt.
408324Sowenr */
409324Sowenr *vpp = tvp;
410324Sowenr VN_RELE(vp);
411324Sowenr return (0);
4120Sstevel@tonic-gate } else {
4130Sstevel@tonic-gate /*
414324Sowenr * We are returning from a covered
415324Sowenr * node whose vfs_mountedhere is
416324Sowenr * not pointing to vfs of the current
417324Sowenr * root vnode.
418324Sowenr * This is a condn where in we
419324Sowenr * returned a covered node say Zc
420324Sowenr * but Zc is not the cover of current
421324Sowenr * root.
422324Sowenr * i.e.., if X is the root vnode
423324Sowenr * lookup(Zc,"..") is taking us to
424324Sowenr * X.
425324Sowenr * Ex: /net/X/net/X/Y
4260Sstevel@tonic-gate *
427324Sowenr * If LO_AUTOLOOP (autofs/lofs looping detected)
428324Sowenr * has been set then we are encountering the
429324Sowenr * cover of Y (Y being any directory vnode
430324Sowenr * under /net/X/net/X/).
431324Sowenr * When performing a dotdot set the
432324Sowenr * returned vp to the vnode covered
433324Sowenr * by the mounted lofs, ie /net/X/net/X
4340Sstevel@tonic-gate */
435324Sowenr VN_RELE(tvp);
436324Sowenr if ((vtol(dvp))->lo_looping & LO_AUTOLOOP) {
437324Sowenr VN_RELE(vp);
438324Sowenr vp = li->li_rootvp;
439324Sowenr vp = vp->v_vfsp->vfs_vnodecovered;
4400Sstevel@tonic-gate VN_HOLD(vp);
441324Sowenr *vpp = makelonode(vp, li, 0);
442324Sowenr (vtol(*vpp))->lo_looping |= LO_LOOPING;
443324Sowenr return (0);
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate } else {
4470Sstevel@tonic-gate /*
4480Sstevel@tonic-gate * No frills just make the shadow node.
4490Sstevel@tonic-gate */
450324Sowenr *vpp = makelonode(vp, li, 0);
4510Sstevel@tonic-gate return (0);
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate }
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate nosub = (vtoli(dvp->v_vfsp)->li_flag & LO_NOSUB);
4560Sstevel@tonic-gate
4570Sstevel@tonic-gate /*
4580Sstevel@tonic-gate * If this vnode is mounted on, then we
4590Sstevel@tonic-gate * traverse to the vnode which is the root of
4600Sstevel@tonic-gate * the mounted file system.
4610Sstevel@tonic-gate */
4620Sstevel@tonic-gate if (!nosub && (error = traverse(&vp)))
4630Sstevel@tonic-gate goto out;
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate /*
4660Sstevel@tonic-gate * Make a lnode for the real vnode.
4670Sstevel@tonic-gate */
4680Sstevel@tonic-gate if (vp->v_type != VDIR || nosub) {
469324Sowenr *vpp = makelonode(vp, li, 0);
4700Sstevel@tonic-gate if (IS_DEVVP(*vpp)) {
4710Sstevel@tonic-gate vnode_t *svp;
4720Sstevel@tonic-gate
4730Sstevel@tonic-gate svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
4740Sstevel@tonic-gate VN_RELE(*vpp);
4750Sstevel@tonic-gate if (svp == NULL)
4760Sstevel@tonic-gate error = ENOSYS;
4770Sstevel@tonic-gate else
4780Sstevel@tonic-gate *vpp = svp;
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate return (error);
4810Sstevel@tonic-gate }
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate /*
4840Sstevel@tonic-gate * if the found vnode (vp) is not of type lofs
4850Sstevel@tonic-gate * then we're just going to make a shadow of that
4860Sstevel@tonic-gate * vp and get out.
4870Sstevel@tonic-gate *
4880Sstevel@tonic-gate * If the found vnode (vp) is of lofs type, and
4890Sstevel@tonic-gate * we're not doing dotdot, check if we are
4900Sstevel@tonic-gate * looping.
4910Sstevel@tonic-gate */
4920Sstevel@tonic-gate if (!doingdotdot && vfs_matchops(vp->v_vfsp, lo_vfsops)) {
4930Sstevel@tonic-gate /*
4940Sstevel@tonic-gate * Check if we're looping, i.e.
4950Sstevel@tonic-gate * vp equals the root vp of the lofs, directly
4960Sstevel@tonic-gate * or indirectly, return the covered node.
4970Sstevel@tonic-gate */
4980Sstevel@tonic-gate
499324Sowenr if (!((vtol(dvp))->lo_looping & LO_LOOPING)) {
5000Sstevel@tonic-gate if (vp == li->li_rootvp) {
5010Sstevel@tonic-gate /*
5020Sstevel@tonic-gate * Direct looping condn.
5030Sstevel@tonic-gate * Ex:- X is / mounted directory so lookup of
5040Sstevel@tonic-gate * /X/X is a direct looping condn.
5050Sstevel@tonic-gate */
5060Sstevel@tonic-gate tvp = vp;
5070Sstevel@tonic-gate vp = vp->v_vfsp->vfs_vnodecovered;
5080Sstevel@tonic-gate VN_HOLD(vp);
5090Sstevel@tonic-gate VN_RELE(tvp);
5100Sstevel@tonic-gate looping++;
5110Sstevel@tonic-gate } else {
5120Sstevel@tonic-gate /*
5130Sstevel@tonic-gate * Indirect looping can be defined as
5140Sstevel@tonic-gate * real lookup returning rootvp of the current
5150Sstevel@tonic-gate * tree in any level of recursion.
5160Sstevel@tonic-gate *
5170Sstevel@tonic-gate * This check is useful if there are multiple
5180Sstevel@tonic-gate * levels of lofs indirections. Suppose vnode X
5190Sstevel@tonic-gate * in the current lookup has as its real vnode
5200Sstevel@tonic-gate * another lofs node. Y = realvp(X) Y should be
5210Sstevel@tonic-gate * a lofs node for the check to continue or Y
5220Sstevel@tonic-gate * is not the rootvp of X.
5230Sstevel@tonic-gate * Ex:- say X and Y are two vnodes
5240Sstevel@tonic-gate * say real(Y) is X and real(X) is Z
5250Sstevel@tonic-gate * parent vnode for X and Y is Z
5260Sstevel@tonic-gate * lookup(Y,"path") say we are looking for Y
5270Sstevel@tonic-gate * again under Y and we have to return Yc.
5280Sstevel@tonic-gate * but the lookup of Y under Y doesnot return
5290Sstevel@tonic-gate * Y the root vnode again here is why.
5300Sstevel@tonic-gate * 1. lookup(Y,"path of Y") will go to
5310Sstevel@tonic-gate * 2. lookup(real(Y),"path of Y") and then to
5320Sstevel@tonic-gate * 3. lookup(real(X),"path of Y").
5330Sstevel@tonic-gate * and now what lookup level 1 sees is the
5340Sstevel@tonic-gate * outcome of 2 but the vnode Y is due to
5350Sstevel@tonic-gate * lookup(Z,"path of Y") so we have to skip
5360Sstevel@tonic-gate * intermediate levels to find if in any level
5370Sstevel@tonic-gate * there is a looping.
5380Sstevel@tonic-gate */
5390Sstevel@tonic-gate is_indirectloop = 0;
5400Sstevel@tonic-gate nonlovp = vp;
5410Sstevel@tonic-gate while (
5420Sstevel@tonic-gate vfs_matchops(nonlovp->v_vfsp, lo_vfsops) &&
5430Sstevel@tonic-gate !(is_indirectloop)) {
5440Sstevel@tonic-gate if (li->li_rootvp == nonlovp) {
5450Sstevel@tonic-gate is_indirectloop++;
5460Sstevel@tonic-gate break;
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate nonlovp = realvp(nonlovp);
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate
5510Sstevel@tonic-gate if (is_indirectloop) {
5520Sstevel@tonic-gate VN_RELE(vp);
5530Sstevel@tonic-gate vp = nonlovp;
5540Sstevel@tonic-gate vp = vp->v_vfsp->vfs_vnodecovered;
5550Sstevel@tonic-gate VN_HOLD(vp);
5560Sstevel@tonic-gate looping++;
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate } else {
5600Sstevel@tonic-gate /*
5610Sstevel@tonic-gate * come here only because of the interaction between
5620Sstevel@tonic-gate * the autofs and lofs.
5630Sstevel@tonic-gate *
5640Sstevel@tonic-gate * Lookup of "/net/X/net/X" will return a shadow of
5650Sstevel@tonic-gate * an autonode X_a which we call X_l.
5660Sstevel@tonic-gate *
5670Sstevel@tonic-gate * Lookup of anything under X_l, will trigger a call to
5680Sstevel@tonic-gate * auto_lookup(X_a,nm) which will eventually call
5690Sstevel@tonic-gate * lo_lookup(X_lr,nm) where X_lr is the root vnode of
5700Sstevel@tonic-gate * the current lofs.
5710Sstevel@tonic-gate *
5720Sstevel@tonic-gate * We come here only when we are called with X_l as dvp
5730Sstevel@tonic-gate * and look for something underneath.
5740Sstevel@tonic-gate *
575324Sowenr * Now that an autofs/lofs looping condition has been
576324Sowenr * identified any directory vnode contained within
577324Sowenr * dvp will be set to the vnode covered by the
578324Sowenr * mounted autofs. Thus all directories within dvp
579324Sowenr * will appear empty hence teminating the looping.
580324Sowenr * The LO_AUTOLOOP flag is set on the returned lonode
581324Sowenr * to indicate the termination of the autofs/lofs
582324Sowenr * looping. This is required for the correct behaviour
583324Sowenr * when performing a dotdot.
5840Sstevel@tonic-gate */
5850Sstevel@tonic-gate realdvp = realvp(dvp);
5860Sstevel@tonic-gate while (vfs_matchops(realdvp->v_vfsp, lo_vfsops)) {
5870Sstevel@tonic-gate realdvp = realvp(realdvp);
5880Sstevel@tonic-gate }
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate error = VFS_ROOT(realdvp->v_vfsp, &tvp);
5910Sstevel@tonic-gate if (error)
5920Sstevel@tonic-gate goto out;
5930Sstevel@tonic-gate /*
5940Sstevel@tonic-gate * tvp now contains the rootvp of the vfs of the
595324Sowenr * real vnode of dvp. The directory vnode vp is set
596324Sowenr * to the covered vnode to terminate looping. No
597324Sowenr * distinction is made between any vp as all directory
598324Sowenr * vnodes contained in dvp are returned as the covered
599324Sowenr * vnode.
6000Sstevel@tonic-gate */
601324Sowenr VN_RELE(vp);
6021314Sowenr vp = tvp; /* possibly is an autonode */
6030Sstevel@tonic-gate
604324Sowenr /*
605324Sowenr * Need to find the covered vnode
606324Sowenr */
6071314Sowenr if (vp->v_vfsp->vfs_vnodecovered == NULL) {
6081314Sowenr /*
6091314Sowenr * We don't have a covered vnode so this isn't
6101314Sowenr * an autonode. To find the autonode simply
6111314Sowenr * find the vnode covered by the lofs rootvp.
6121314Sowenr */
6131314Sowenr vp = li->li_rootvp;
6141314Sowenr vp = vp->v_vfsp->vfs_vnodecovered;
6151314Sowenr VN_RELE(tvp);
6161314Sowenr error = VFS_ROOT(vp->v_vfsp, &tvp);
6171314Sowenr if (error)
6181314Sowenr goto out;
6191314Sowenr vp = tvp; /* now this is an autonode */
6201314Sowenr if (vp->v_vfsp->vfs_vnodecovered == NULL) {
6211314Sowenr /*
6221314Sowenr * Still can't find a covered vnode.
6231314Sowenr * Fail the lookup, or we'd loop.
6241314Sowenr */
6251314Sowenr error = ENOENT;
6261314Sowenr goto out;
6271314Sowenr }
6281314Sowenr }
629324Sowenr vp = vp->v_vfsp->vfs_vnodecovered;
630324Sowenr VN_HOLD(vp);
631324Sowenr VN_RELE(tvp);
632324Sowenr /*
633324Sowenr * Force the creation of a new lnode even if the hash
634324Sowenr * table contains a lnode that references this vnode.
635324Sowenr */
636324Sowenr mkflag = LOF_FORCE;
637324Sowenr autoloop++;
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate }
640324Sowenr *vpp = makelonode(vp, li, mkflag);
6410Sstevel@tonic-gate
642324Sowenr if ((looping) ||
643324Sowenr (((vtol(dvp))->lo_looping & LO_LOOPING) && !doingdotdot)) {
644324Sowenr (vtol(*vpp))->lo_looping |= LO_LOOPING;
645324Sowenr }
646324Sowenr
647324Sowenr if (autoloop) {
648324Sowenr (vtol(*vpp))->lo_looping |= LO_AUTOLOOP;
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate out:
6520Sstevel@tonic-gate if (error != 0 && vp != NULL)
6530Sstevel@tonic-gate VN_RELE(vp);
6540Sstevel@tonic-gate #ifdef LODEBUG
6550Sstevel@tonic-gate lo_dprint(4,
6560Sstevel@tonic-gate "lo_lookup dvp %x realdvp %x nm '%s' newvp %x real vp %x error %d\n",
657*6264Srm15945 dvp, realvp(dvp), nm, *vpp, vp, error);
6580Sstevel@tonic-gate #endif
6590Sstevel@tonic-gate return (error);
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate /*ARGSUSED*/
6630Sstevel@tonic-gate static int
lo_create(vnode_t * dvp,char * nm,struct vattr * va,enum vcexcl exclusive,int mode,vnode_t ** vpp,struct cred * cr,int flag,caller_context_t * ct,vsecattr_t * vsecp)6640Sstevel@tonic-gate lo_create(
6650Sstevel@tonic-gate vnode_t *dvp,
6660Sstevel@tonic-gate char *nm,
6670Sstevel@tonic-gate struct vattr *va,
6680Sstevel@tonic-gate enum vcexcl exclusive,
6690Sstevel@tonic-gate int mode,
6700Sstevel@tonic-gate vnode_t **vpp,
6710Sstevel@tonic-gate struct cred *cr,
6725331Samw int flag,
6735331Samw caller_context_t *ct,
6745331Samw vsecattr_t *vsecp)
6750Sstevel@tonic-gate {
6760Sstevel@tonic-gate int error;
6770Sstevel@tonic-gate vnode_t *vp = NULL;
6780Sstevel@tonic-gate
6790Sstevel@tonic-gate #ifdef LODEBUG
6800Sstevel@tonic-gate lo_dprint(4, "lo_create vp %p realvp %p\n", dvp, realvp(dvp));
6810Sstevel@tonic-gate #endif
6820Sstevel@tonic-gate if (*nm == '\0') {
6830Sstevel@tonic-gate ASSERT(vpp && dvp == *vpp);
6840Sstevel@tonic-gate vp = realvp(*vpp);
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate
6875331Samw error = VOP_CREATE(realvp(dvp), nm, va, exclusive, mode, &vp, cr, flag,
688*6264Srm15945 ct, vsecp);
6890Sstevel@tonic-gate if (!error) {
690324Sowenr *vpp = makelonode(vp, vtoli(dvp->v_vfsp), 0);
6910Sstevel@tonic-gate if (IS_DEVVP(*vpp)) {
6920Sstevel@tonic-gate vnode_t *svp;
6930Sstevel@tonic-gate
6940Sstevel@tonic-gate svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
6950Sstevel@tonic-gate VN_RELE(*vpp);
6960Sstevel@tonic-gate if (svp == NULL)
6970Sstevel@tonic-gate error = ENOSYS;
6980Sstevel@tonic-gate else
6990Sstevel@tonic-gate *vpp = svp;
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate return (error);
7030Sstevel@tonic-gate }
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate static int
lo_remove(vnode_t * dvp,char * nm,struct cred * cr,caller_context_t * ct,int flags)7065331Samw lo_remove(
7075331Samw vnode_t *dvp,
7085331Samw char *nm,
7095331Samw struct cred *cr,
7105331Samw caller_context_t *ct,
7115331Samw int flags)
7120Sstevel@tonic-gate {
7130Sstevel@tonic-gate #ifdef LODEBUG
7140Sstevel@tonic-gate lo_dprint(4, "lo_remove vp %p realvp %p\n", dvp, realvp(dvp));
7150Sstevel@tonic-gate #endif
7160Sstevel@tonic-gate dvp = realvp(dvp);
7175331Samw return (VOP_REMOVE(dvp, nm, cr, ct, flags));
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate static int
lo_link(vnode_t * tdvp,vnode_t * vp,char * tnm,struct cred * cr,caller_context_t * ct,int flags)7215331Samw lo_link(
7225331Samw vnode_t *tdvp,
7235331Samw vnode_t *vp,
7245331Samw char *tnm,
7255331Samw struct cred *cr,
7265331Samw caller_context_t *ct,
7275331Samw int flags)
7280Sstevel@tonic-gate {
7293640Sbatschul vnode_t *realvp;
7303640Sbatschul
7310Sstevel@tonic-gate #ifdef LODEBUG
7320Sstevel@tonic-gate lo_dprint(4, "lo_link vp %p realvp %p\n", vp, realvp(vp));
7330Sstevel@tonic-gate #endif
7343372Ssjelinek
7353372Ssjelinek /*
7363372Ssjelinek * The source and destination vnodes may be in different lofs
7373372Ssjelinek * filesystems sharing the same underlying filesystem, so we need to
7383372Ssjelinek * make sure that the filesystem containing the source vnode is not
7393372Ssjelinek * mounted read-only (vn_link() has already checked the target vnode).
7403372Ssjelinek *
7413372Ssjelinek * In a situation such as:
7423372Ssjelinek *
7433372Ssjelinek * /data - regular filesystem
7443372Ssjelinek * /foo - lofs mount of /data/foo
7453372Ssjelinek * /bar - read-only lofs mount of /data/bar
7463372Ssjelinek *
7473372Ssjelinek * This disallows a link from /bar/somefile to /foo/somefile,
7483372Ssjelinek * which would otherwise allow changes to somefile on the read-only
7493372Ssjelinek * mounted /bar.
7503372Ssjelinek */
7513372Ssjelinek
7523372Ssjelinek if (vn_is_readonly(vp)) {
7533372Ssjelinek return (EROFS);
7543372Ssjelinek }
7550Sstevel@tonic-gate while (vn_matchops(vp, lo_vnodeops)) {
7560Sstevel@tonic-gate vp = realvp(vp);
7570Sstevel@tonic-gate }
7583640Sbatschul
7593640Sbatschul /*
7603640Sbatschul * In the case where the source vnode is on another stacking
7613640Sbatschul * filesystem (such as specfs), the loop above will
7623640Sbatschul * terminate before finding the true underlying vnode.
7633640Sbatschul *
7643640Sbatschul * We use VOP_REALVP here to continue the search.
7653640Sbatschul */
7665331Samw if (VOP_REALVP(vp, &realvp, ct) == 0)
7673640Sbatschul vp = realvp;
7683640Sbatschul
7690Sstevel@tonic-gate while (vn_matchops(tdvp, lo_vnodeops)) {
7700Sstevel@tonic-gate tdvp = realvp(tdvp);
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate if (vp->v_vfsp != tdvp->v_vfsp)
7730Sstevel@tonic-gate return (EXDEV);
7745331Samw return (VOP_LINK(tdvp, vp, tnm, cr, ct, flags));
7750Sstevel@tonic-gate }
7760Sstevel@tonic-gate
7770Sstevel@tonic-gate static int
lo_rename(vnode_t * odvp,char * onm,vnode_t * ndvp,char * nnm,struct cred * cr,caller_context_t * ct,int flags)7780Sstevel@tonic-gate lo_rename(
7790Sstevel@tonic-gate vnode_t *odvp,
7800Sstevel@tonic-gate char *onm,
7810Sstevel@tonic-gate vnode_t *ndvp,
7820Sstevel@tonic-gate char *nnm,
7835331Samw struct cred *cr,
7845331Samw caller_context_t *ct,
7855331Samw int flags)
7860Sstevel@tonic-gate {
7870Sstevel@tonic-gate vnode_t *tnvp;
7880Sstevel@tonic-gate
7890Sstevel@tonic-gate #ifdef LODEBUG
7900Sstevel@tonic-gate lo_dprint(4, "lo_rename vp %p realvp %p\n", odvp, realvp(odvp));
7910Sstevel@tonic-gate #endif
7920Sstevel@tonic-gate /*
7931800Ssjelinek * If we are coming from a loop back mounted fs, that has been
7941800Ssjelinek * mounted in the same filesystem as where we want to move to,
7951800Ssjelinek * and that filesystem is read/write, but the lofs filesystem is
7961800Ssjelinek * read only, we don't want to allow a rename of the file. The
7971800Ssjelinek * vn_rename code checks to be sure the target is read/write already
7981800Ssjelinek * so that is not necessary here. However, consider the following
7991800Ssjelinek * example:
8001800Ssjelinek * / - regular root fs
8011800Ssjelinek * /foo - directory in root
8021800Ssjelinek * /foo/bar - file in foo directory(in root fs)
8031800Ssjelinek * /baz - directory in root
8041800Ssjelinek * mount -F lofs -o ro /foo /baz - all still in root
8051800Ssjelinek * directory
8061800Ssjelinek * The fact that we mounted /foo on /baz read only should stop us
8071800Ssjelinek * from renaming the file /foo/bar /bar, but it doesn't since
8081800Ssjelinek * / is read/write. We are still renaming here since we are still
8091800Ssjelinek * in the same filesystem, it is just that we do not check to see
8101800Ssjelinek * if the filesystem we are coming from in this case is read only.
8111800Ssjelinek */
8121800Ssjelinek if (odvp->v_vfsp->vfs_flag & VFS_RDONLY)
8131800Ssjelinek return (EROFS);
8141800Ssjelinek /*
8150Sstevel@tonic-gate * We need to make sure we're not trying to remove a mount point for a
8160Sstevel@tonic-gate * filesystem mounted on top of lofs, which only we know about.
8170Sstevel@tonic-gate */
8180Sstevel@tonic-gate if (vn_matchops(ndvp, lo_vnodeops)) /* Not our problem. */
8190Sstevel@tonic-gate goto rename;
8205331Samw
8215331Samw /*
8225331Samw * XXXci - Once case-insensitive behavior is implemented, it should
8235331Samw * be added here.
8245331Samw */
8255331Samw if (VOP_LOOKUP(ndvp, nnm, &tnvp, NULL, 0, NULL, cr,
8265331Samw ct, NULL, NULL) != 0)
8270Sstevel@tonic-gate goto rename;
8280Sstevel@tonic-gate if (tnvp->v_type != VDIR) {
8290Sstevel@tonic-gate VN_RELE(tnvp);
8300Sstevel@tonic-gate goto rename;
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate if (vn_mountedvfs(tnvp)) {
8330Sstevel@tonic-gate VN_RELE(tnvp);
8340Sstevel@tonic-gate return (EBUSY);
8350Sstevel@tonic-gate }
8360Sstevel@tonic-gate VN_RELE(tnvp);
8370Sstevel@tonic-gate rename:
8380Sstevel@tonic-gate /*
8390Sstevel@tonic-gate * Since the case we're dealing with above can happen at any layer in
8400Sstevel@tonic-gate * the stack of lofs filesystems, we need to recurse down the stack,
8410Sstevel@tonic-gate * checking to see if there are any instances of a filesystem mounted on
8420Sstevel@tonic-gate * top of lofs. In order to keep on using the lofs version of
8430Sstevel@tonic-gate * VOP_RENAME(), we make sure that while the target directory is of type
8440Sstevel@tonic-gate * lofs, the source directory (the one used for getting the fs-specific
8450Sstevel@tonic-gate * version of VOP_RENAME()) is also of type lofs.
8460Sstevel@tonic-gate */
8470Sstevel@tonic-gate if (vn_matchops(ndvp, lo_vnodeops)) {
8480Sstevel@tonic-gate ndvp = realvp(ndvp); /* Check the next layer */
8490Sstevel@tonic-gate } else {
8500Sstevel@tonic-gate /*
8510Sstevel@tonic-gate * We can go fast here
8520Sstevel@tonic-gate */
8530Sstevel@tonic-gate while (vn_matchops(odvp, lo_vnodeops)) {
8540Sstevel@tonic-gate odvp = realvp(odvp);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate if (odvp->v_vfsp != ndvp->v_vfsp)
8570Sstevel@tonic-gate return (EXDEV);
8580Sstevel@tonic-gate }
8595331Samw return (VOP_RENAME(odvp, onm, ndvp, nnm, cr, ct, flags));
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate
8620Sstevel@tonic-gate static int
lo_mkdir(vnode_t * dvp,char * nm,struct vattr * va,vnode_t ** vpp,struct cred * cr,caller_context_t * ct,int flags,vsecattr_t * vsecp)8630Sstevel@tonic-gate lo_mkdir(
8640Sstevel@tonic-gate vnode_t *dvp,
8650Sstevel@tonic-gate char *nm,
8660Sstevel@tonic-gate struct vattr *va,
8670Sstevel@tonic-gate vnode_t **vpp,
8685331Samw struct cred *cr,
8695331Samw caller_context_t *ct,
8705331Samw int flags,
8715331Samw vsecattr_t *vsecp)
8720Sstevel@tonic-gate {
8730Sstevel@tonic-gate int error;
8740Sstevel@tonic-gate
8750Sstevel@tonic-gate #ifdef LODEBUG
8760Sstevel@tonic-gate lo_dprint(4, "lo_mkdir vp %p realvp %p\n", dvp, realvp(dvp));
8770Sstevel@tonic-gate #endif
8785331Samw error = VOP_MKDIR(realvp(dvp), nm, va, vpp, cr, ct, flags, vsecp);
8790Sstevel@tonic-gate if (!error)
880324Sowenr *vpp = makelonode(*vpp, vtoli(dvp->v_vfsp), 0);
8810Sstevel@tonic-gate return (error);
8820Sstevel@tonic-gate }
8830Sstevel@tonic-gate
8840Sstevel@tonic-gate static int
lo_realvp(vnode_t * vp,vnode_t ** vpp,caller_context_t * ct)8855331Samw lo_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
8860Sstevel@tonic-gate {
8870Sstevel@tonic-gate #ifdef LODEBUG
8880Sstevel@tonic-gate lo_dprint(4, "lo_realvp %p\n", vp);
8890Sstevel@tonic-gate #endif
8900Sstevel@tonic-gate while (vn_matchops(vp, lo_vnodeops))
8910Sstevel@tonic-gate vp = realvp(vp);
8920Sstevel@tonic-gate
8935331Samw if (VOP_REALVP(vp, vpp, ct) != 0)
8940Sstevel@tonic-gate *vpp = vp;
8950Sstevel@tonic-gate return (0);
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate static int
lo_rmdir(vnode_t * dvp,char * nm,vnode_t * cdir,struct cred * cr,caller_context_t * ct,int flags)8990Sstevel@tonic-gate lo_rmdir(
9000Sstevel@tonic-gate vnode_t *dvp,
9010Sstevel@tonic-gate char *nm,
9020Sstevel@tonic-gate vnode_t *cdir,
9035331Samw struct cred *cr,
9045331Samw caller_context_t *ct,
9055331Samw int flags)
9060Sstevel@tonic-gate {
9070Sstevel@tonic-gate vnode_t *rvp = cdir;
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate #ifdef LODEBUG
9100Sstevel@tonic-gate lo_dprint(4, "lo_rmdir vp %p realvp %p\n", dvp, realvp(dvp));
9110Sstevel@tonic-gate #endif
9120Sstevel@tonic-gate /* if cdir is lofs vnode ptr get its real vnode ptr */
9130Sstevel@tonic-gate if (vn_matchops(dvp, vn_getops(rvp)))
9145331Samw (void) lo_realvp(cdir, &rvp, ct);
9150Sstevel@tonic-gate dvp = realvp(dvp);
9165331Samw return (VOP_RMDIR(dvp, nm, rvp, cr, ct, flags));
9170Sstevel@tonic-gate }
9180Sstevel@tonic-gate
9190Sstevel@tonic-gate static int
lo_symlink(vnode_t * dvp,char * lnm,struct vattr * tva,char * tnm,struct cred * cr,caller_context_t * ct,int flags)9200Sstevel@tonic-gate lo_symlink(
9210Sstevel@tonic-gate vnode_t *dvp,
9220Sstevel@tonic-gate char *lnm,
9230Sstevel@tonic-gate struct vattr *tva,
9240Sstevel@tonic-gate char *tnm,
9255331Samw struct cred *cr,
9265331Samw caller_context_t *ct,
9275331Samw int flags)
9280Sstevel@tonic-gate {
9290Sstevel@tonic-gate #ifdef LODEBUG
9300Sstevel@tonic-gate lo_dprint(4, "lo_symlink vp %p realvp %p\n", dvp, realvp(dvp));
9310Sstevel@tonic-gate #endif
9320Sstevel@tonic-gate dvp = realvp(dvp);
9335331Samw return (VOP_SYMLINK(dvp, lnm, tva, tnm, cr, ct, flags));
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate
9360Sstevel@tonic-gate static int
lo_readlink(vnode_t * vp,struct uio * uiop,struct cred * cr,caller_context_t * ct)9375331Samw lo_readlink(
9385331Samw vnode_t *vp,
9395331Samw struct uio *uiop,
9405331Samw struct cred *cr,
9415331Samw caller_context_t *ct)
9420Sstevel@tonic-gate {
9430Sstevel@tonic-gate vp = realvp(vp);
9445331Samw return (VOP_READLINK(vp, uiop, cr, ct));
9450Sstevel@tonic-gate }
9460Sstevel@tonic-gate
9470Sstevel@tonic-gate static int
lo_readdir(vnode_t * vp,struct uio * uiop,struct cred * cr,int * eofp,caller_context_t * ct,int flags)9485331Samw lo_readdir(
9495331Samw vnode_t *vp,
9505331Samw struct uio *uiop,
9515331Samw struct cred *cr,
9525331Samw int *eofp,
9535331Samw caller_context_t *ct,
9545331Samw int flags)
9550Sstevel@tonic-gate {
9560Sstevel@tonic-gate #ifdef LODEBUG
9570Sstevel@tonic-gate lo_dprint(4, "lo_readdir vp %p realvp %p\n", vp, realvp(vp));
9580Sstevel@tonic-gate #endif
9590Sstevel@tonic-gate vp = realvp(vp);
9605331Samw return (VOP_READDIR(vp, uiop, cr, eofp, ct, flags));
9610Sstevel@tonic-gate }
9620Sstevel@tonic-gate
9630Sstevel@tonic-gate static int
lo_rwlock(vnode_t * vp,int write_lock,caller_context_t * ct)9640Sstevel@tonic-gate lo_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct)
9650Sstevel@tonic-gate {
9660Sstevel@tonic-gate vp = realvp(vp);
9670Sstevel@tonic-gate return (VOP_RWLOCK(vp, write_lock, ct));
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate
9700Sstevel@tonic-gate static void
lo_rwunlock(vnode_t * vp,int write_lock,caller_context_t * ct)9710Sstevel@tonic-gate lo_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
9720Sstevel@tonic-gate {
9730Sstevel@tonic-gate vp = realvp(vp);
9740Sstevel@tonic-gate VOP_RWUNLOCK(vp, write_lock, ct);
9750Sstevel@tonic-gate }
9760Sstevel@tonic-gate
9770Sstevel@tonic-gate static int
lo_seek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)9785331Samw lo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
9790Sstevel@tonic-gate {
9800Sstevel@tonic-gate vp = realvp(vp);
9815331Samw return (VOP_SEEK(vp, ooff, noffp, ct));
9820Sstevel@tonic-gate }
9830Sstevel@tonic-gate
9840Sstevel@tonic-gate static int
lo_cmp(vnode_t * vp1,vnode_t * vp2,caller_context_t * ct)9855331Samw lo_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
9860Sstevel@tonic-gate {
9870Sstevel@tonic-gate while (vn_matchops(vp1, lo_vnodeops))
9880Sstevel@tonic-gate vp1 = realvp(vp1);
9890Sstevel@tonic-gate while (vn_matchops(vp2, lo_vnodeops))
9900Sstevel@tonic-gate vp2 = realvp(vp2);
9915331Samw return (VOP_CMP(vp1, vp2, ct));
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate
9940Sstevel@tonic-gate static int
lo_frlock(vnode_t * vp,int cmd,struct flock64 * bfp,int flag,offset_t offset,struct flk_callback * flk_cbp,cred_t * cr,caller_context_t * ct)9950Sstevel@tonic-gate lo_frlock(
9960Sstevel@tonic-gate vnode_t *vp,
9970Sstevel@tonic-gate int cmd,
9980Sstevel@tonic-gate struct flock64 *bfp,
9990Sstevel@tonic-gate int flag,
10000Sstevel@tonic-gate offset_t offset,
10010Sstevel@tonic-gate struct flk_callback *flk_cbp,
10025331Samw cred_t *cr,
10035331Samw caller_context_t *ct)
10040Sstevel@tonic-gate {
10050Sstevel@tonic-gate vp = realvp(vp);
10065331Samw return (VOP_FRLOCK(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
10070Sstevel@tonic-gate }
10080Sstevel@tonic-gate
10090Sstevel@tonic-gate static int
lo_space(vnode_t * vp,int cmd,struct flock64 * bfp,int flag,offset_t offset,struct cred * cr,caller_context_t * ct)10100Sstevel@tonic-gate lo_space(
10110Sstevel@tonic-gate vnode_t *vp,
10120Sstevel@tonic-gate int cmd,
10130Sstevel@tonic-gate struct flock64 *bfp,
10140Sstevel@tonic-gate int flag,
10150Sstevel@tonic-gate offset_t offset,
10160Sstevel@tonic-gate struct cred *cr,
10170Sstevel@tonic-gate caller_context_t *ct)
10180Sstevel@tonic-gate {
10190Sstevel@tonic-gate vp = realvp(vp);
10200Sstevel@tonic-gate return (VOP_SPACE(vp, cmd, bfp, flag, offset, cr, ct));
10210Sstevel@tonic-gate }
10220Sstevel@tonic-gate
10230Sstevel@tonic-gate static int
lo_getpage(vnode_t * vp,offset_t off,size_t len,uint_t * prot,struct page * parr[],size_t psz,struct seg * seg,caddr_t addr,enum seg_rw rw,struct cred * cr,caller_context_t * ct)10240Sstevel@tonic-gate lo_getpage(
10250Sstevel@tonic-gate vnode_t *vp,
10260Sstevel@tonic-gate offset_t off,
10270Sstevel@tonic-gate size_t len,
10280Sstevel@tonic-gate uint_t *prot,
10290Sstevel@tonic-gate struct page *parr[],
10300Sstevel@tonic-gate size_t psz,
10310Sstevel@tonic-gate struct seg *seg,
10320Sstevel@tonic-gate caddr_t addr,
10330Sstevel@tonic-gate enum seg_rw rw,
10345331Samw struct cred *cr,
10355331Samw caller_context_t *ct)
10360Sstevel@tonic-gate {
10370Sstevel@tonic-gate vp = realvp(vp);
10385331Samw return (VOP_GETPAGE(vp, off, len, prot, parr, psz, seg, addr, rw, cr,
1039*6264Srm15945 ct));
10400Sstevel@tonic-gate }
10410Sstevel@tonic-gate
10420Sstevel@tonic-gate static int
lo_putpage(vnode_t * vp,offset_t off,size_t len,int flags,struct cred * cr,caller_context_t * ct)10435331Samw lo_putpage(
10445331Samw vnode_t *vp,
10455331Samw offset_t off,
10465331Samw size_t len,
10475331Samw int flags,
10485331Samw struct cred *cr,
10495331Samw caller_context_t *ct)
10500Sstevel@tonic-gate {
10510Sstevel@tonic-gate vp = realvp(vp);
10525331Samw return (VOP_PUTPAGE(vp, off, len, flags, cr, ct));
10530Sstevel@tonic-gate }
10540Sstevel@tonic-gate
10550Sstevel@tonic-gate static int
lo_map(vnode_t * vp,offset_t off,struct as * as,caddr_t * addrp,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)10560Sstevel@tonic-gate lo_map(
10570Sstevel@tonic-gate vnode_t *vp,
10580Sstevel@tonic-gate offset_t off,
10590Sstevel@tonic-gate struct as *as,
10600Sstevel@tonic-gate caddr_t *addrp,
10610Sstevel@tonic-gate size_t len,
10620Sstevel@tonic-gate uchar_t prot,
10630Sstevel@tonic-gate uchar_t maxprot,
10640Sstevel@tonic-gate uint_t flags,
10655331Samw struct cred *cr,
10665331Samw caller_context_t *ct)
10670Sstevel@tonic-gate {
10680Sstevel@tonic-gate vp = realvp(vp);
10695331Samw return (VOP_MAP(vp, off, as, addrp, len, prot, maxprot, flags, cr, ct));
10700Sstevel@tonic-gate }
10710Sstevel@tonic-gate
10720Sstevel@tonic-gate static int
lo_addmap(vnode_t * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)10730Sstevel@tonic-gate lo_addmap(
10740Sstevel@tonic-gate vnode_t *vp,
10750Sstevel@tonic-gate offset_t off,
10760Sstevel@tonic-gate struct as *as,
10770Sstevel@tonic-gate caddr_t addr,
10780Sstevel@tonic-gate size_t len,
10790Sstevel@tonic-gate uchar_t prot,
10800Sstevel@tonic-gate uchar_t maxprot,
10810Sstevel@tonic-gate uint_t flags,
10825331Samw struct cred *cr,
10835331Samw caller_context_t *ct)
10840Sstevel@tonic-gate {
10850Sstevel@tonic-gate vp = realvp(vp);
10865331Samw return (VOP_ADDMAP(vp, off, as, addr, len, prot, maxprot, flags, cr,
1087*6264Srm15945 ct));
10880Sstevel@tonic-gate }
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate static int
lo_delmap(vnode_t * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uint_t prot,uint_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)10910Sstevel@tonic-gate lo_delmap(
10920Sstevel@tonic-gate vnode_t *vp,
10930Sstevel@tonic-gate offset_t off,
10940Sstevel@tonic-gate struct as *as,
10950Sstevel@tonic-gate caddr_t addr,
10960Sstevel@tonic-gate size_t len,
10970Sstevel@tonic-gate uint_t prot,
10980Sstevel@tonic-gate uint_t maxprot,
10990Sstevel@tonic-gate uint_t flags,
11005331Samw struct cred *cr,
11015331Samw caller_context_t *ct)
11020Sstevel@tonic-gate {
11030Sstevel@tonic-gate vp = realvp(vp);
11045331Samw return (VOP_DELMAP(vp, off, as, addr, len, prot, maxprot, flags, cr,
1105*6264Srm15945 ct));
11060Sstevel@tonic-gate }
11070Sstevel@tonic-gate
11080Sstevel@tonic-gate static int
lo_poll(vnode_t * vp,short events,int anyyet,short * reventsp,struct pollhead ** phpp,caller_context_t * ct)11090Sstevel@tonic-gate lo_poll(
11100Sstevel@tonic-gate vnode_t *vp,
11110Sstevel@tonic-gate short events,
11120Sstevel@tonic-gate int anyyet,
11130Sstevel@tonic-gate short *reventsp,
11145331Samw struct pollhead **phpp,
11155331Samw caller_context_t *ct)
11160Sstevel@tonic-gate {
11170Sstevel@tonic-gate vp = realvp(vp);
11185331Samw return (VOP_POLL(vp, events, anyyet, reventsp, phpp, ct));
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate
11210Sstevel@tonic-gate static int
lo_dump(vnode_t * vp,caddr_t addr,offset_t bn,offset_t count,caller_context_t * ct)1122*6264Srm15945 lo_dump(vnode_t *vp, caddr_t addr, offset_t bn, offset_t count,
1123*6264Srm15945 caller_context_t *ct)
11240Sstevel@tonic-gate {
11250Sstevel@tonic-gate vp = realvp(vp);
11265331Samw return (VOP_DUMP(vp, addr, bn, count, ct));
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate
11290Sstevel@tonic-gate static int
lo_pathconf(vnode_t * vp,int cmd,ulong_t * valp,struct cred * cr,caller_context_t * ct)11305331Samw lo_pathconf(
11315331Samw vnode_t *vp,
11325331Samw int cmd,
11335331Samw ulong_t *valp,
11345331Samw struct cred *cr,
11355331Samw caller_context_t *ct)
11360Sstevel@tonic-gate {
11370Sstevel@tonic-gate vp = realvp(vp);
11385331Samw return (VOP_PATHCONF(vp, cmd, valp, cr, ct));
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate
11410Sstevel@tonic-gate static int
lo_pageio(vnode_t * vp,struct page * pp,u_offset_t io_off,size_t io_len,int flags,cred_t * cr,caller_context_t * ct)11420Sstevel@tonic-gate lo_pageio(
11430Sstevel@tonic-gate vnode_t *vp,
11440Sstevel@tonic-gate struct page *pp,
11450Sstevel@tonic-gate u_offset_t io_off,
11460Sstevel@tonic-gate size_t io_len,
11470Sstevel@tonic-gate int flags,
11485331Samw cred_t *cr,
11495331Samw caller_context_t *ct)
11500Sstevel@tonic-gate {
11510Sstevel@tonic-gate vp = realvp(vp);
11525331Samw return (VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr, ct));
11530Sstevel@tonic-gate }
11540Sstevel@tonic-gate
11550Sstevel@tonic-gate static void
lo_dispose(vnode_t * vp,page_t * pp,int fl,int dn,cred_t * cr,caller_context_t * ct)11565331Samw lo_dispose(
11575331Samw vnode_t *vp,
11585331Samw page_t *pp,
11595331Samw int fl,
11605331Samw int dn,
11615331Samw cred_t *cr,
11625331Samw caller_context_t *ct)
11630Sstevel@tonic-gate {
11640Sstevel@tonic-gate vp = realvp(vp);
11653290Sjohansen if (vp != NULL && !VN_ISKAS(vp))
11665331Samw VOP_DISPOSE(vp, pp, fl, dn, cr, ct);
11670Sstevel@tonic-gate }
11680Sstevel@tonic-gate
11690Sstevel@tonic-gate static int
lo_setsecattr(vnode_t * vp,vsecattr_t * secattr,int flags,struct cred * cr,caller_context_t * ct)11705331Samw lo_setsecattr(
11715331Samw vnode_t *vp,
11725331Samw vsecattr_t *secattr,
11735331Samw int flags,
11745331Samw struct cred *cr,
11755331Samw caller_context_t *ct)
11760Sstevel@tonic-gate {
11770Sstevel@tonic-gate if (vn_is_readonly(vp))
11780Sstevel@tonic-gate return (EROFS);
11790Sstevel@tonic-gate vp = realvp(vp);
11805331Samw return (VOP_SETSECATTR(vp, secattr, flags, cr, ct));
11810Sstevel@tonic-gate }
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate static int
lo_getsecattr(vnode_t * vp,vsecattr_t * secattr,int flags,struct cred * cr,caller_context_t * ct)11845331Samw lo_getsecattr(
11855331Samw vnode_t *vp,
11865331Samw vsecattr_t *secattr,
11875331Samw int flags,
11885331Samw struct cred *cr,
11895331Samw caller_context_t *ct)
11900Sstevel@tonic-gate {
11910Sstevel@tonic-gate vp = realvp(vp);
11925331Samw return (VOP_GETSECATTR(vp, secattr, flags, cr, ct));
11930Sstevel@tonic-gate }
11940Sstevel@tonic-gate
11950Sstevel@tonic-gate static int
lo_shrlock(vnode_t * vp,int cmd,struct shrlock * shr,int flag,cred_t * cr,caller_context_t * ct)11965331Samw lo_shrlock(
11975331Samw vnode_t *vp,
11985331Samw int cmd,
11995331Samw struct shrlock *shr,
12005331Samw int flag,
12015331Samw cred_t *cr,
12025331Samw caller_context_t *ct)
12030Sstevel@tonic-gate {
12040Sstevel@tonic-gate vp = realvp(vp);
12055331Samw return (VOP_SHRLOCK(vp, cmd, shr, flag, cr, ct));
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate
12080Sstevel@tonic-gate /*
12090Sstevel@tonic-gate * Loopback vnode operations vector.
12100Sstevel@tonic-gate */
12110Sstevel@tonic-gate
12120Sstevel@tonic-gate struct vnodeops *lo_vnodeops;
12130Sstevel@tonic-gate
12140Sstevel@tonic-gate const fs_operation_def_t lo_vnodeops_template[] = {
12153898Srsb VOPNAME_OPEN, { .vop_open = lo_open },
12163898Srsb VOPNAME_CLOSE, { .vop_close = lo_close },
12173898Srsb VOPNAME_READ, { .vop_read = lo_read },
12183898Srsb VOPNAME_WRITE, { .vop_write = lo_write },
12193898Srsb VOPNAME_IOCTL, { .vop_ioctl = lo_ioctl },
12203898Srsb VOPNAME_SETFL, { .vop_setfl = lo_setfl },
12213898Srsb VOPNAME_GETATTR, { .vop_getattr = lo_getattr },
12223898Srsb VOPNAME_SETATTR, { .vop_setattr = lo_setattr },
12233898Srsb VOPNAME_ACCESS, { .vop_access = lo_access },
12243898Srsb VOPNAME_LOOKUP, { .vop_lookup = lo_lookup },
12253898Srsb VOPNAME_CREATE, { .vop_create = lo_create },
12263898Srsb VOPNAME_REMOVE, { .vop_remove = lo_remove },
12273898Srsb VOPNAME_LINK, { .vop_link = lo_link },
12283898Srsb VOPNAME_RENAME, { .vop_rename = lo_rename },
12293898Srsb VOPNAME_MKDIR, { .vop_mkdir = lo_mkdir },
12303898Srsb VOPNAME_RMDIR, { .vop_rmdir = lo_rmdir },
12313898Srsb VOPNAME_READDIR, { .vop_readdir = lo_readdir },
12323898Srsb VOPNAME_SYMLINK, { .vop_symlink = lo_symlink },
12333898Srsb VOPNAME_READLINK, { .vop_readlink = lo_readlink },
12343898Srsb VOPNAME_FSYNC, { .vop_fsync = lo_fsync },
12353898Srsb VOPNAME_INACTIVE, { .vop_inactive = lo_inactive },
12363898Srsb VOPNAME_FID, { .vop_fid = lo_fid },
12373898Srsb VOPNAME_RWLOCK, { .vop_rwlock = lo_rwlock },
12383898Srsb VOPNAME_RWUNLOCK, { .vop_rwunlock = lo_rwunlock },
12393898Srsb VOPNAME_SEEK, { .vop_seek = lo_seek },
12403898Srsb VOPNAME_CMP, { .vop_cmp = lo_cmp },
12413898Srsb VOPNAME_FRLOCK, { .vop_frlock = lo_frlock },
12423898Srsb VOPNAME_SPACE, { .vop_space = lo_space },
12433898Srsb VOPNAME_REALVP, { .vop_realvp = lo_realvp },
12443898Srsb VOPNAME_GETPAGE, { .vop_getpage = lo_getpage },
12453898Srsb VOPNAME_PUTPAGE, { .vop_putpage = lo_putpage },
12463898Srsb VOPNAME_MAP, { .vop_map = lo_map },
12473898Srsb VOPNAME_ADDMAP, { .vop_addmap = lo_addmap },
12483898Srsb VOPNAME_DELMAP, { .vop_delmap = lo_delmap },
12493898Srsb VOPNAME_POLL, { .vop_poll = lo_poll },
12503898Srsb VOPNAME_DUMP, { .vop_dump = lo_dump },
12513898Srsb VOPNAME_DUMPCTL, { .error = fs_error }, /* XXX - why? */
12523898Srsb VOPNAME_PATHCONF, { .vop_pathconf = lo_pathconf },
12533898Srsb VOPNAME_PAGEIO, { .vop_pageio = lo_pageio },
12543898Srsb VOPNAME_DISPOSE, { .vop_dispose = lo_dispose },
12553898Srsb VOPNAME_SETSECATTR, { .vop_setsecattr = lo_setsecattr },
12563898Srsb VOPNAME_GETSECATTR, { .vop_getsecattr = lo_getsecattr },
12573898Srsb VOPNAME_SHRLOCK, { .vop_shrlock = lo_shrlock },
12583898Srsb NULL, NULL
12590Sstevel@tonic-gate };
1260