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 58f71b825Sowenr * Common Development and Distribution License (the "License"). 68f71b825Sowenr * 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 /* 22*d7334e51Srm * Copyright 2008 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> 33aa59c4cbSrsb #include <sys/vfs_opreg.h> 347c478bd9Sstevel@tonic-gate #include <sys/uio.h> 357c478bd9Sstevel@tonic-gate #include <sys/cred.h> 367c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 377c478bd9Sstevel@tonic-gate #include <sys/debug.h> 387c478bd9Sstevel@tonic-gate #include <sys/fs/lofs_node.h> 397c478bd9Sstevel@tonic-gate #include <sys/fs/lofs_info.h> 407c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h> 417c478bd9Sstevel@tonic-gate #include <vm/as.h> 427c478bd9Sstevel@tonic-gate #include <vm/seg.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * These are the vnode ops routines which implement the vnode interface to 467c478bd9Sstevel@tonic-gate * the looped-back file system. These routines just take their parameters, 477c478bd9Sstevel@tonic-gate * and then calling the appropriate real vnode routine(s) to do the work. 487c478bd9Sstevel@tonic-gate */ 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate static int 51da6c28aaSamw lo_open(vnode_t **vpp, int flag, struct cred *cr, caller_context_t *ct) 527c478bd9Sstevel@tonic-gate { 537c478bd9Sstevel@tonic-gate vnode_t *vp = *vpp; 547c478bd9Sstevel@tonic-gate vnode_t *rvp; 557c478bd9Sstevel@tonic-gate vnode_t *oldvp; 567c478bd9Sstevel@tonic-gate int error; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #ifdef LODEBUG 597c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_open vp %p cnt=%d realvp %p cnt=%d\n", 60*d7334e51Srm vp, vp->v_count, realvp(vp), realvp(vp)->v_count); 617c478bd9Sstevel@tonic-gate #endif 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate oldvp = vp; 647c478bd9Sstevel@tonic-gate vp = rvp = realvp(vp); 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * Need to hold new reference to vp since VOP_OPEN() may 677c478bd9Sstevel@tonic-gate * decide to release it. 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate VN_HOLD(vp); 70da6c28aaSamw error = VOP_OPEN(&rvp, flag, cr, ct); 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate if (!error && rvp != vp) { 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * the FS which we called should have released the 757c478bd9Sstevel@tonic-gate * new reference on vp 767c478bd9Sstevel@tonic-gate */ 77b431137cSowenr *vpp = makelonode(rvp, vtoli(oldvp->v_vfsp), 0); 788f71b825Sowenr if ((*vpp)->v_type == VDIR) { 798f71b825Sowenr /* 808f71b825Sowenr * Copy over any looping flags to the new lnode. 818f71b825Sowenr */ 828f71b825Sowenr (vtol(*vpp))->lo_looping |= (vtol(oldvp))->lo_looping; 838f71b825Sowenr } 847c478bd9Sstevel@tonic-gate if (IS_DEVVP(*vpp)) { 857c478bd9Sstevel@tonic-gate vnode_t *svp; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr); 887c478bd9Sstevel@tonic-gate VN_RELE(*vpp); 897c478bd9Sstevel@tonic-gate if (svp == NULL) 907c478bd9Sstevel@tonic-gate error = ENOSYS; 917c478bd9Sstevel@tonic-gate else 927c478bd9Sstevel@tonic-gate *vpp = svp; 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate VN_RELE(oldvp); 957c478bd9Sstevel@tonic-gate } else { 967c478bd9Sstevel@tonic-gate ASSERT(rvp->v_count > 1); 977c478bd9Sstevel@tonic-gate VN_RELE(rvp); 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate return (error); 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate static int 1047c478bd9Sstevel@tonic-gate lo_close( 1057c478bd9Sstevel@tonic-gate vnode_t *vp, 1067c478bd9Sstevel@tonic-gate int flag, 1077c478bd9Sstevel@tonic-gate int count, 1087c478bd9Sstevel@tonic-gate offset_t offset, 109da6c28aaSamw struct cred *cr, 110da6c28aaSamw caller_context_t *ct) 1117c478bd9Sstevel@tonic-gate { 1127c478bd9Sstevel@tonic-gate #ifdef LODEBUG 1137c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_close vp %p realvp %p\n", vp, realvp(vp)); 1147c478bd9Sstevel@tonic-gate #endif 1157c478bd9Sstevel@tonic-gate vp = realvp(vp); 116da6c28aaSamw return (VOP_CLOSE(vp, flag, count, offset, cr, ct)); 1177c478bd9Sstevel@tonic-gate } 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate static int 1207c478bd9Sstevel@tonic-gate lo_read(vnode_t *vp, struct uio *uiop, int ioflag, struct cred *cr, 1217c478bd9Sstevel@tonic-gate caller_context_t *ct) 1227c478bd9Sstevel@tonic-gate { 1237c478bd9Sstevel@tonic-gate #ifdef LODEBUG 1247c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_read vp %p realvp %p\n", vp, realvp(vp)); 1257c478bd9Sstevel@tonic-gate #endif 1267c478bd9Sstevel@tonic-gate vp = realvp(vp); 1277c478bd9Sstevel@tonic-gate return (VOP_READ(vp, uiop, ioflag, cr, ct)); 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate static int 1317c478bd9Sstevel@tonic-gate lo_write(vnode_t *vp, struct uio *uiop, int ioflag, struct cred *cr, 1327c478bd9Sstevel@tonic-gate caller_context_t *ct) 1337c478bd9Sstevel@tonic-gate { 1347c478bd9Sstevel@tonic-gate #ifdef LODEBUG 1357c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_write vp %p realvp %p\n", vp, realvp(vp)); 1367c478bd9Sstevel@tonic-gate #endif 1377c478bd9Sstevel@tonic-gate vp = realvp(vp); 1387c478bd9Sstevel@tonic-gate return (VOP_WRITE(vp, uiop, ioflag, cr, ct)); 1397c478bd9Sstevel@tonic-gate } 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate static int 1427c478bd9Sstevel@tonic-gate lo_ioctl( 1437c478bd9Sstevel@tonic-gate vnode_t *vp, 1447c478bd9Sstevel@tonic-gate int cmd, 1457c478bd9Sstevel@tonic-gate intptr_t arg, 1467c478bd9Sstevel@tonic-gate int flag, 1477c478bd9Sstevel@tonic-gate struct cred *cr, 148da6c28aaSamw int *rvalp, 149da6c28aaSamw caller_context_t *ct) 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); 155da6c28aaSamw return (VOP_IOCTL(vp, cmd, arg, flag, cr, rvalp, ct)); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate static int 159da6c28aaSamw lo_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct) 1607c478bd9Sstevel@tonic-gate { 1617c478bd9Sstevel@tonic-gate vp = realvp(vp); 162da6c28aaSamw return (VOP_SETFL(vp, oflags, nflags, cr, ct)); 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, 170da6c28aaSamw struct cred *cr, 171da6c28aaSamw caller_context_t *ct) 1727c478bd9Sstevel@tonic-gate { 1737c478bd9Sstevel@tonic-gate int error; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate #ifdef LODEBUG 1767c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_getattr vp %p realvp %p\n", vp, realvp(vp)); 1777c478bd9Sstevel@tonic-gate #endif 178da6c28aaSamw if (error = VOP_GETATTR(realvp(vp), vap, flags, cr, ct)) 1797c478bd9Sstevel@tonic-gate return (error); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate return (0); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate static int 1857c478bd9Sstevel@tonic-gate lo_setattr( 1867c478bd9Sstevel@tonic-gate vnode_t *vp, 1877c478bd9Sstevel@tonic-gate struct vattr *vap, 1887c478bd9Sstevel@tonic-gate int flags, 1897c478bd9Sstevel@tonic-gate struct cred *cr, 1907c478bd9Sstevel@tonic-gate caller_context_t *ct) 1917c478bd9Sstevel@tonic-gate { 1927c478bd9Sstevel@tonic-gate #ifdef LODEBUG 1937c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_setattr vp %p realvp %p\n", vp, realvp(vp)); 1947c478bd9Sstevel@tonic-gate #endif 1957c478bd9Sstevel@tonic-gate vp = realvp(vp); 1967c478bd9Sstevel@tonic-gate return (VOP_SETATTR(vp, vap, flags, cr, ct)); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate static int 200da6c28aaSamw lo_access( 201da6c28aaSamw vnode_t *vp, 202da6c28aaSamw int mode, 203da6c28aaSamw int flags, 204da6c28aaSamw struct cred *cr, 205da6c28aaSamw caller_context_t *ct) 2067c478bd9Sstevel@tonic-gate { 2077c478bd9Sstevel@tonic-gate #ifdef LODEBUG 2087c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_access vp %p realvp %p\n", vp, realvp(vp)); 2097c478bd9Sstevel@tonic-gate #endif 2107c478bd9Sstevel@tonic-gate if (mode & VWRITE) { 2117c478bd9Sstevel@tonic-gate if (vp->v_type == VREG && vn_is_readonly(vp)) 2127c478bd9Sstevel@tonic-gate return (EROFS); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate vp = realvp(vp); 215da6c28aaSamw return (VOP_ACCESS(vp, mode, flags, cr, ct)); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate static int 219da6c28aaSamw lo_fsync(vnode_t *vp, int syncflag, struct cred *cr, caller_context_t *ct) 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate #ifdef LODEBUG 2227c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_fsync vp %p realvp %p\n", vp, realvp(vp)); 2237c478bd9Sstevel@tonic-gate #endif 2247c478bd9Sstevel@tonic-gate vp = realvp(vp); 225da6c28aaSamw return (VOP_FSYNC(vp, syncflag, cr, ct)); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2297c478bd9Sstevel@tonic-gate static void 230da6c28aaSamw lo_inactive(vnode_t *vp, struct cred *cr, caller_context_t *ct) 2317c478bd9Sstevel@tonic-gate { 2327c478bd9Sstevel@tonic-gate #ifdef LODEBUG 2337c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_inactive %p, realvp %p\n", vp, realvp(vp)); 2347c478bd9Sstevel@tonic-gate #endif 2357c478bd9Sstevel@tonic-gate freelonode(vtol(vp)); 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2397c478bd9Sstevel@tonic-gate static int 240da6c28aaSamw lo_fid(vnode_t *vp, struct fid *fidp, caller_context_t *ct) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate #ifdef LODEBUG 2437c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_fid %p, realvp %p\n", vp, realvp(vp)); 2447c478bd9Sstevel@tonic-gate #endif 2457c478bd9Sstevel@tonic-gate vp = realvp(vp); 246da6c28aaSamw return (VOP_FID(vp, fidp, ct)); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * Given a vnode of lofs type, lookup nm name and 2517c478bd9Sstevel@tonic-gate * return a shadow vnode (of lofs type) of the 2527c478bd9Sstevel@tonic-gate * real vnode found. 2537c478bd9Sstevel@tonic-gate * 2547c478bd9Sstevel@tonic-gate * Due to the nature of lofs, there is a potential 2557c478bd9Sstevel@tonic-gate * looping in path traversal. 2567c478bd9Sstevel@tonic-gate * 2577c478bd9Sstevel@tonic-gate * starting from the mount point of an lofs; 2587c478bd9Sstevel@tonic-gate * a loop is defined to be a traversal path 2597c478bd9Sstevel@tonic-gate * where the mount point or the real vnode of 2607c478bd9Sstevel@tonic-gate * the root of this lofs is encountered twice. 2617c478bd9Sstevel@tonic-gate * Once at the start of traversal and second 2627c478bd9Sstevel@tonic-gate * when the looping is found. 2637c478bd9Sstevel@tonic-gate * 2647c478bd9Sstevel@tonic-gate * When a loop is encountered, a shadow of the 2657c478bd9Sstevel@tonic-gate * covered vnode is returned to stop the looping. 2667c478bd9Sstevel@tonic-gate * 2677c478bd9Sstevel@tonic-gate * This normally works, but with the advent of 2687c478bd9Sstevel@tonic-gate * the new automounter, returning the shadow of the 2697c478bd9Sstevel@tonic-gate * covered vnode (autonode, in this case) does not 2707c478bd9Sstevel@tonic-gate * stop the loop. Because further lookup on this 2717c478bd9Sstevel@tonic-gate * lonode will cause the autonode to call lo_lookup() 2727c478bd9Sstevel@tonic-gate * on the lonode covering it. 2737c478bd9Sstevel@tonic-gate * 2747c478bd9Sstevel@tonic-gate * example "/net/jurassic/net/jurassic" is a loop. 2757c478bd9Sstevel@tonic-gate * returning the shadow of the autonode corresponding to 2767c478bd9Sstevel@tonic-gate * "/net/jurassic/net/jurassic" will not terminate the 2777c478bd9Sstevel@tonic-gate * loop. To solve this problem we allow the loop to go 278b431137cSowenr * through one more level component lookup. Whichever 279b431137cSowenr * directory is then looked up in "/net/jurassic/net/jurassic" 280b431137cSowenr * the vnode returned is the vnode covered by the autonode 281b431137cSowenr * "net" and this will terminate the loop. 2827c478bd9Sstevel@tonic-gate * 2837c478bd9Sstevel@tonic-gate * Lookup for dot dot has to be dealt with separately. 2847c478bd9Sstevel@tonic-gate * It will be nice to have a "one size fits all" kind 2857c478bd9Sstevel@tonic-gate * of solution, so that we don't have so many ifs statement 2867c478bd9Sstevel@tonic-gate * in the lo_lookup() to handle dotdot. But, since 2877c478bd9Sstevel@tonic-gate * there are so many special cases to handle different 2887c478bd9Sstevel@tonic-gate * kinds looping above, we need special codes to handle 2897c478bd9Sstevel@tonic-gate * dotdot lookup as well. 2907c478bd9Sstevel@tonic-gate */ 2917c478bd9Sstevel@tonic-gate static int 2927c478bd9Sstevel@tonic-gate lo_lookup( 2937c478bd9Sstevel@tonic-gate vnode_t *dvp, 2947c478bd9Sstevel@tonic-gate char *nm, 2957c478bd9Sstevel@tonic-gate vnode_t **vpp, 2967c478bd9Sstevel@tonic-gate struct pathname *pnp, 2977c478bd9Sstevel@tonic-gate int flags, 2987c478bd9Sstevel@tonic-gate vnode_t *rdir, 299da6c28aaSamw struct cred *cr, 300da6c28aaSamw caller_context_t *ct, 301da6c28aaSamw int *direntflags, 302da6c28aaSamw pathname_t *realpnp) 3037c478bd9Sstevel@tonic-gate { 3047c478bd9Sstevel@tonic-gate vnode_t *vp = NULL, *tvp = NULL, *nonlovp; 3057c478bd9Sstevel@tonic-gate int error, is_indirectloop; 3067c478bd9Sstevel@tonic-gate vnode_t *realdvp = realvp(dvp); 3077c478bd9Sstevel@tonic-gate struct loinfo *li = vtoli(dvp->v_vfsp); 3087c478bd9Sstevel@tonic-gate int looping = 0; 309b431137cSowenr int autoloop = 0; 3107c478bd9Sstevel@tonic-gate int doingdotdot = 0; 3117c478bd9Sstevel@tonic-gate int nosub = 0; 312b431137cSowenr int mkflag = 0; 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate /* 3157c478bd9Sstevel@tonic-gate * If name is empty and no XATTR flags are set, then return 3167c478bd9Sstevel@tonic-gate * dvp (empty name == lookup "."). If an XATTR flag is set 3177c478bd9Sstevel@tonic-gate * then we need to call VOP_LOOKUP to get the xattr dir. 3187c478bd9Sstevel@tonic-gate */ 3197c478bd9Sstevel@tonic-gate if (nm[0] == '\0' && ! (flags & (CREATE_XATTR_DIR|LOOKUP_XATTR))) { 3207c478bd9Sstevel@tonic-gate VN_HOLD(dvp); 3217c478bd9Sstevel@tonic-gate *vpp = dvp; 3227c478bd9Sstevel@tonic-gate return (0); 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate if (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0') { 3267c478bd9Sstevel@tonic-gate doingdotdot++; 3277c478bd9Sstevel@tonic-gate /* 3287c478bd9Sstevel@tonic-gate * Handle ".." out of mounted filesystem 3297c478bd9Sstevel@tonic-gate */ 3307c478bd9Sstevel@tonic-gate while ((realdvp->v_flag & VROOT) && realdvp != rootdir) { 3317c478bd9Sstevel@tonic-gate realdvp = realdvp->v_vfsp->vfs_vnodecovered; 3327c478bd9Sstevel@tonic-gate ASSERT(realdvp != NULL); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate *vpp = NULL; /* default(error) case */ 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /* 3397c478bd9Sstevel@tonic-gate * Do the normal lookup 3407c478bd9Sstevel@tonic-gate */ 341da6c28aaSamw if (error = VOP_LOOKUP(realdvp, nm, &vp, pnp, flags, rdir, cr, 342da6c28aaSamw ct, direntflags, realpnp)) { 343d13f2f50Smarks vp = NULL; 3447c478bd9Sstevel@tonic-gate goto out; 345d13f2f50Smarks } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* 3487c478bd9Sstevel@tonic-gate * We do this check here to avoid returning a stale file handle to the 3497c478bd9Sstevel@tonic-gate * caller. 3507c478bd9Sstevel@tonic-gate */ 3517c478bd9Sstevel@tonic-gate if (nm[0] == '.' && nm[1] == '\0') { 3527c478bd9Sstevel@tonic-gate ASSERT(vp == realdvp); 3537c478bd9Sstevel@tonic-gate VN_HOLD(dvp); 3547c478bd9Sstevel@tonic-gate VN_RELE(vp); 3557c478bd9Sstevel@tonic-gate *vpp = dvp; 3567c478bd9Sstevel@tonic-gate return (0); 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate if (doingdotdot) { 360b431137cSowenr if ((vtol(dvp))->lo_looping & LO_LOOPING) { 3617c478bd9Sstevel@tonic-gate vfs_t *vfsp; 3627c478bd9Sstevel@tonic-gate 36395b97885Snr error = vn_vfsrlock_wait(realdvp); 3647c478bd9Sstevel@tonic-gate if (error) 3657c478bd9Sstevel@tonic-gate goto out; 3667c478bd9Sstevel@tonic-gate vfsp = vn_mountedvfs(realdvp); 367b431137cSowenr /* 368b431137cSowenr * In the standard case if the looping flag is set and 369b431137cSowenr * performing dotdot we would be returning from a 370b431137cSowenr * covered vnode, implying vfsp could not be null. The 371b431137cSowenr * exceptions being if we have looping and overlay 372b431137cSowenr * mounts or looping and covered file systems. 373b431137cSowenr */ 374b431137cSowenr if (vfsp == NULL) { 3757c478bd9Sstevel@tonic-gate /* 376b431137cSowenr * Overlay mount or covered file system, 377b431137cSowenr * so just make the shadow node. 3787c478bd9Sstevel@tonic-gate */ 3797c478bd9Sstevel@tonic-gate vn_vfsunlock(realdvp); 380b431137cSowenr *vpp = makelonode(vp, li, 0); 381b431137cSowenr (vtol(*vpp))->lo_looping |= LO_LOOPING; 382b431137cSowenr return (0); 383b431137cSowenr } 384b431137cSowenr /* 385b431137cSowenr * When looping get the actual found vnode 386b431137cSowenr * instead of the vnode covered. 387b431137cSowenr * Here we have to hold the lock for realdvp 388b431137cSowenr * since an unmount during the traversal to the 389b431137cSowenr * root vnode would turn *vfsp into garbage 390b431137cSowenr * which would be fatal. 391b431137cSowenr */ 392b431137cSowenr error = VFS_ROOT(vfsp, &tvp); 39395b97885Snr vn_vfsunlock(realdvp); 394b431137cSowenr 395b431137cSowenr if (error) 396b431137cSowenr goto out; 39795b97885Snr 398b431137cSowenr if ((tvp == li->li_rootvp) && (vp == realvp(tvp))) { 3997c478bd9Sstevel@tonic-gate /* 400b431137cSowenr * we're back at the real vnode 401b431137cSowenr * of the rootvp 4027c478bd9Sstevel@tonic-gate * 403b431137cSowenr * return the rootvp 404b431137cSowenr * Ex: /mnt/mnt/.. 405b431137cSowenr * where / has been lofs-mounted 406b431137cSowenr * onto /mnt. Return the lofs 407b431137cSowenr * node mounted at /mnt. 408b431137cSowenr */ 409b431137cSowenr *vpp = tvp; 410b431137cSowenr VN_RELE(vp); 411b431137cSowenr return (0); 412b431137cSowenr } else { 413b431137cSowenr /* 414b431137cSowenr * We are returning from a covered 415b431137cSowenr * node whose vfs_mountedhere is 416b431137cSowenr * not pointing to vfs of the current 417b431137cSowenr * root vnode. 418b431137cSowenr * This is a condn where in we 419b431137cSowenr * returned a covered node say Zc 420b431137cSowenr * but Zc is not the cover of current 421b431137cSowenr * root. 422b431137cSowenr * i.e.., if X is the root vnode 423b431137cSowenr * lookup(Zc,"..") is taking us to 424b431137cSowenr * X. 425b431137cSowenr * Ex: /net/X/net/X/Y 4267c478bd9Sstevel@tonic-gate * 427b431137cSowenr * If LO_AUTOLOOP (autofs/lofs looping detected) 428b431137cSowenr * has been set then we are encountering the 429b431137cSowenr * cover of Y (Y being any directory vnode 430b431137cSowenr * under /net/X/net/X/). 431b431137cSowenr * When performing a dotdot set the 432b431137cSowenr * returned vp to the vnode covered 433b431137cSowenr * by the mounted lofs, ie /net/X/net/X 4347c478bd9Sstevel@tonic-gate */ 435b431137cSowenr VN_RELE(tvp); 436b431137cSowenr if ((vtol(dvp))->lo_looping & LO_AUTOLOOP) { 437b431137cSowenr VN_RELE(vp); 438b431137cSowenr vp = li->li_rootvp; 439b431137cSowenr vp = vp->v_vfsp->vfs_vnodecovered; 4407c478bd9Sstevel@tonic-gate VN_HOLD(vp); 441b431137cSowenr *vpp = makelonode(vp, li, 0); 442b431137cSowenr (vtol(*vpp))->lo_looping |= LO_LOOPING; 443b431137cSowenr return (0); 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate } else { 4477c478bd9Sstevel@tonic-gate /* 4487c478bd9Sstevel@tonic-gate * No frills just make the shadow node. 4497c478bd9Sstevel@tonic-gate */ 450b431137cSowenr *vpp = makelonode(vp, li, 0); 4517c478bd9Sstevel@tonic-gate return (0); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate nosub = (vtoli(dvp->v_vfsp)->li_flag & LO_NOSUB); 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate /* 4587c478bd9Sstevel@tonic-gate * If this vnode is mounted on, then we 4597c478bd9Sstevel@tonic-gate * traverse to the vnode which is the root of 4607c478bd9Sstevel@tonic-gate * the mounted file system. 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate if (!nosub && (error = traverse(&vp))) 4637c478bd9Sstevel@tonic-gate goto out; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* 4667c478bd9Sstevel@tonic-gate * Make a lnode for the real vnode. 4677c478bd9Sstevel@tonic-gate */ 4687c478bd9Sstevel@tonic-gate if (vp->v_type != VDIR || nosub) { 469b431137cSowenr *vpp = makelonode(vp, li, 0); 4707c478bd9Sstevel@tonic-gate if (IS_DEVVP(*vpp)) { 4717c478bd9Sstevel@tonic-gate vnode_t *svp; 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr); 4747c478bd9Sstevel@tonic-gate VN_RELE(*vpp); 4757c478bd9Sstevel@tonic-gate if (svp == NULL) 4767c478bd9Sstevel@tonic-gate error = ENOSYS; 4777c478bd9Sstevel@tonic-gate else 4787c478bd9Sstevel@tonic-gate *vpp = svp; 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate return (error); 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* 4847c478bd9Sstevel@tonic-gate * if the found vnode (vp) is not of type lofs 4857c478bd9Sstevel@tonic-gate * then we're just going to make a shadow of that 4867c478bd9Sstevel@tonic-gate * vp and get out. 4877c478bd9Sstevel@tonic-gate * 4887c478bd9Sstevel@tonic-gate * If the found vnode (vp) is of lofs type, and 4897c478bd9Sstevel@tonic-gate * we're not doing dotdot, check if we are 4907c478bd9Sstevel@tonic-gate * looping. 4917c478bd9Sstevel@tonic-gate */ 4927c478bd9Sstevel@tonic-gate if (!doingdotdot && vfs_matchops(vp->v_vfsp, lo_vfsops)) { 4937c478bd9Sstevel@tonic-gate /* 4947c478bd9Sstevel@tonic-gate * Check if we're looping, i.e. 4957c478bd9Sstevel@tonic-gate * vp equals the root vp of the lofs, directly 4967c478bd9Sstevel@tonic-gate * or indirectly, return the covered node. 4977c478bd9Sstevel@tonic-gate */ 4987c478bd9Sstevel@tonic-gate 499b431137cSowenr if (!((vtol(dvp))->lo_looping & LO_LOOPING)) { 5007c478bd9Sstevel@tonic-gate if (vp == li->li_rootvp) { 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * Direct looping condn. 5037c478bd9Sstevel@tonic-gate * Ex:- X is / mounted directory so lookup of 5047c478bd9Sstevel@tonic-gate * /X/X is a direct looping condn. 5057c478bd9Sstevel@tonic-gate */ 5067c478bd9Sstevel@tonic-gate tvp = vp; 5077c478bd9Sstevel@tonic-gate vp = vp->v_vfsp->vfs_vnodecovered; 5087c478bd9Sstevel@tonic-gate VN_HOLD(vp); 5097c478bd9Sstevel@tonic-gate VN_RELE(tvp); 5107c478bd9Sstevel@tonic-gate looping++; 5117c478bd9Sstevel@tonic-gate } else { 5127c478bd9Sstevel@tonic-gate /* 5137c478bd9Sstevel@tonic-gate * Indirect looping can be defined as 5147c478bd9Sstevel@tonic-gate * real lookup returning rootvp of the current 5157c478bd9Sstevel@tonic-gate * tree in any level of recursion. 5167c478bd9Sstevel@tonic-gate * 5177c478bd9Sstevel@tonic-gate * This check is useful if there are multiple 5187c478bd9Sstevel@tonic-gate * levels of lofs indirections. Suppose vnode X 5197c478bd9Sstevel@tonic-gate * in the current lookup has as its real vnode 5207c478bd9Sstevel@tonic-gate * another lofs node. Y = realvp(X) Y should be 5217c478bd9Sstevel@tonic-gate * a lofs node for the check to continue or Y 5227c478bd9Sstevel@tonic-gate * is not the rootvp of X. 5237c478bd9Sstevel@tonic-gate * Ex:- say X and Y are two vnodes 5247c478bd9Sstevel@tonic-gate * say real(Y) is X and real(X) is Z 5257c478bd9Sstevel@tonic-gate * parent vnode for X and Y is Z 5267c478bd9Sstevel@tonic-gate * lookup(Y,"path") say we are looking for Y 5277c478bd9Sstevel@tonic-gate * again under Y and we have to return Yc. 5287c478bd9Sstevel@tonic-gate * but the lookup of Y under Y doesnot return 5297c478bd9Sstevel@tonic-gate * Y the root vnode again here is why. 5307c478bd9Sstevel@tonic-gate * 1. lookup(Y,"path of Y") will go to 5317c478bd9Sstevel@tonic-gate * 2. lookup(real(Y),"path of Y") and then to 5327c478bd9Sstevel@tonic-gate * 3. lookup(real(X),"path of Y"). 5337c478bd9Sstevel@tonic-gate * and now what lookup level 1 sees is the 5347c478bd9Sstevel@tonic-gate * outcome of 2 but the vnode Y is due to 5357c478bd9Sstevel@tonic-gate * lookup(Z,"path of Y") so we have to skip 5367c478bd9Sstevel@tonic-gate * intermediate levels to find if in any level 5377c478bd9Sstevel@tonic-gate * there is a looping. 5387c478bd9Sstevel@tonic-gate */ 5397c478bd9Sstevel@tonic-gate is_indirectloop = 0; 5407c478bd9Sstevel@tonic-gate nonlovp = vp; 5417c478bd9Sstevel@tonic-gate while ( 5427c478bd9Sstevel@tonic-gate vfs_matchops(nonlovp->v_vfsp, lo_vfsops) && 5437c478bd9Sstevel@tonic-gate !(is_indirectloop)) { 5447c478bd9Sstevel@tonic-gate if (li->li_rootvp == nonlovp) { 5457c478bd9Sstevel@tonic-gate is_indirectloop++; 5467c478bd9Sstevel@tonic-gate break; 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate nonlovp = realvp(nonlovp); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate if (is_indirectloop) { 5527c478bd9Sstevel@tonic-gate VN_RELE(vp); 5537c478bd9Sstevel@tonic-gate vp = nonlovp; 5547c478bd9Sstevel@tonic-gate vp = vp->v_vfsp->vfs_vnodecovered; 5557c478bd9Sstevel@tonic-gate VN_HOLD(vp); 5567c478bd9Sstevel@tonic-gate looping++; 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate } else { 5607c478bd9Sstevel@tonic-gate /* 5617c478bd9Sstevel@tonic-gate * come here only because of the interaction between 5627c478bd9Sstevel@tonic-gate * the autofs and lofs. 5637c478bd9Sstevel@tonic-gate * 5647c478bd9Sstevel@tonic-gate * Lookup of "/net/X/net/X" will return a shadow of 5657c478bd9Sstevel@tonic-gate * an autonode X_a which we call X_l. 5667c478bd9Sstevel@tonic-gate * 5677c478bd9Sstevel@tonic-gate * Lookup of anything under X_l, will trigger a call to 5687c478bd9Sstevel@tonic-gate * auto_lookup(X_a,nm) which will eventually call 5697c478bd9Sstevel@tonic-gate * lo_lookup(X_lr,nm) where X_lr is the root vnode of 5707c478bd9Sstevel@tonic-gate * the current lofs. 5717c478bd9Sstevel@tonic-gate * 5727c478bd9Sstevel@tonic-gate * We come here only when we are called with X_l as dvp 5737c478bd9Sstevel@tonic-gate * and look for something underneath. 5747c478bd9Sstevel@tonic-gate * 575b431137cSowenr * Now that an autofs/lofs looping condition has been 576b431137cSowenr * identified any directory vnode contained within 577b431137cSowenr * dvp will be set to the vnode covered by the 578b431137cSowenr * mounted autofs. Thus all directories within dvp 579b431137cSowenr * will appear empty hence teminating the looping. 580b431137cSowenr * The LO_AUTOLOOP flag is set on the returned lonode 581b431137cSowenr * to indicate the termination of the autofs/lofs 582b431137cSowenr * looping. This is required for the correct behaviour 583b431137cSowenr * when performing a dotdot. 5847c478bd9Sstevel@tonic-gate */ 5857c478bd9Sstevel@tonic-gate realdvp = realvp(dvp); 5867c478bd9Sstevel@tonic-gate while (vfs_matchops(realdvp->v_vfsp, lo_vfsops)) { 5877c478bd9Sstevel@tonic-gate realdvp = realvp(realdvp); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate error = VFS_ROOT(realdvp->v_vfsp, &tvp); 5917c478bd9Sstevel@tonic-gate if (error) 5927c478bd9Sstevel@tonic-gate goto out; 5937c478bd9Sstevel@tonic-gate /* 5947c478bd9Sstevel@tonic-gate * tvp now contains the rootvp of the vfs of the 595b431137cSowenr * real vnode of dvp. The directory vnode vp is set 596b431137cSowenr * to the covered vnode to terminate looping. No 597b431137cSowenr * distinction is made between any vp as all directory 598b431137cSowenr * vnodes contained in dvp are returned as the covered 599b431137cSowenr * vnode. 6007c478bd9Sstevel@tonic-gate */ 601b431137cSowenr VN_RELE(vp); 6028f71b825Sowenr vp = tvp; /* possibly is an autonode */ 6037c478bd9Sstevel@tonic-gate 604b431137cSowenr /* 605b431137cSowenr * Need to find the covered vnode 606b431137cSowenr */ 6078f71b825Sowenr if (vp->v_vfsp->vfs_vnodecovered == NULL) { 6088f71b825Sowenr /* 6098f71b825Sowenr * We don't have a covered vnode so this isn't 6108f71b825Sowenr * an autonode. To find the autonode simply 6118f71b825Sowenr * find the vnode covered by the lofs rootvp. 6128f71b825Sowenr */ 6138f71b825Sowenr vp = li->li_rootvp; 6148f71b825Sowenr vp = vp->v_vfsp->vfs_vnodecovered; 6158f71b825Sowenr VN_RELE(tvp); 6168f71b825Sowenr error = VFS_ROOT(vp->v_vfsp, &tvp); 6178f71b825Sowenr if (error) 6188f71b825Sowenr goto out; 6198f71b825Sowenr vp = tvp; /* now this is an autonode */ 6208f71b825Sowenr if (vp->v_vfsp->vfs_vnodecovered == NULL) { 6218f71b825Sowenr /* 6228f71b825Sowenr * Still can't find a covered vnode. 6238f71b825Sowenr * Fail the lookup, or we'd loop. 6248f71b825Sowenr */ 6258f71b825Sowenr error = ENOENT; 6268f71b825Sowenr goto out; 6278f71b825Sowenr } 6288f71b825Sowenr } 629b431137cSowenr vp = vp->v_vfsp->vfs_vnodecovered; 630b431137cSowenr VN_HOLD(vp); 631b431137cSowenr VN_RELE(tvp); 632b431137cSowenr /* 633b431137cSowenr * Force the creation of a new lnode even if the hash 634b431137cSowenr * table contains a lnode that references this vnode. 635b431137cSowenr */ 636b431137cSowenr mkflag = LOF_FORCE; 637b431137cSowenr autoloop++; 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate } 640b431137cSowenr *vpp = makelonode(vp, li, mkflag); 641b431137cSowenr 642b431137cSowenr if ((looping) || 643b431137cSowenr (((vtol(dvp))->lo_looping & LO_LOOPING) && !doingdotdot)) { 644b431137cSowenr (vtol(*vpp))->lo_looping |= LO_LOOPING; 645b431137cSowenr } 6467c478bd9Sstevel@tonic-gate 647b431137cSowenr if (autoloop) { 648b431137cSowenr (vtol(*vpp))->lo_looping |= LO_AUTOLOOP; 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate out: 6527c478bd9Sstevel@tonic-gate if (error != 0 && vp != NULL) 6537c478bd9Sstevel@tonic-gate VN_RELE(vp); 6547c478bd9Sstevel@tonic-gate #ifdef LODEBUG 6557c478bd9Sstevel@tonic-gate lo_dprint(4, 6567c478bd9Sstevel@tonic-gate "lo_lookup dvp %x realdvp %x nm '%s' newvp %x real vp %x error %d\n", 657*d7334e51Srm dvp, realvp(dvp), nm, *vpp, vp, error); 6587c478bd9Sstevel@tonic-gate #endif 6597c478bd9Sstevel@tonic-gate return (error); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6637c478bd9Sstevel@tonic-gate static int 6647c478bd9Sstevel@tonic-gate lo_create( 6657c478bd9Sstevel@tonic-gate vnode_t *dvp, 6667c478bd9Sstevel@tonic-gate char *nm, 6677c478bd9Sstevel@tonic-gate struct vattr *va, 6687c478bd9Sstevel@tonic-gate enum vcexcl exclusive, 6697c478bd9Sstevel@tonic-gate int mode, 6707c478bd9Sstevel@tonic-gate vnode_t **vpp, 6717c478bd9Sstevel@tonic-gate struct cred *cr, 672da6c28aaSamw int flag, 673da6c28aaSamw caller_context_t *ct, 674da6c28aaSamw vsecattr_t *vsecp) 6757c478bd9Sstevel@tonic-gate { 6767c478bd9Sstevel@tonic-gate int error; 6777c478bd9Sstevel@tonic-gate vnode_t *vp = NULL; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate #ifdef LODEBUG 6807c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_create vp %p realvp %p\n", dvp, realvp(dvp)); 6817c478bd9Sstevel@tonic-gate #endif 6827c478bd9Sstevel@tonic-gate if (*nm == '\0') { 6837c478bd9Sstevel@tonic-gate ASSERT(vpp && dvp == *vpp); 6847c478bd9Sstevel@tonic-gate vp = realvp(*vpp); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 687da6c28aaSamw error = VOP_CREATE(realvp(dvp), nm, va, exclusive, mode, &vp, cr, flag, 688*d7334e51Srm ct, vsecp); 6897c478bd9Sstevel@tonic-gate if (!error) { 690b431137cSowenr *vpp = makelonode(vp, vtoli(dvp->v_vfsp), 0); 6917c478bd9Sstevel@tonic-gate if (IS_DEVVP(*vpp)) { 6927c478bd9Sstevel@tonic-gate vnode_t *svp; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr); 6957c478bd9Sstevel@tonic-gate VN_RELE(*vpp); 6967c478bd9Sstevel@tonic-gate if (svp == NULL) 6977c478bd9Sstevel@tonic-gate error = ENOSYS; 6987c478bd9Sstevel@tonic-gate else 6997c478bd9Sstevel@tonic-gate *vpp = svp; 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate return (error); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate static int 706da6c28aaSamw lo_remove( 707da6c28aaSamw vnode_t *dvp, 708da6c28aaSamw char *nm, 709da6c28aaSamw struct cred *cr, 710da6c28aaSamw caller_context_t *ct, 711da6c28aaSamw int flags) 7127c478bd9Sstevel@tonic-gate { 7137c478bd9Sstevel@tonic-gate #ifdef LODEBUG 7147c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_remove vp %p realvp %p\n", dvp, realvp(dvp)); 7157c478bd9Sstevel@tonic-gate #endif 7167c478bd9Sstevel@tonic-gate dvp = realvp(dvp); 717da6c28aaSamw return (VOP_REMOVE(dvp, nm, cr, ct, flags)); 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate static int 721da6c28aaSamw lo_link( 722da6c28aaSamw vnode_t *tdvp, 723da6c28aaSamw vnode_t *vp, 724da6c28aaSamw char *tnm, 725da6c28aaSamw struct cred *cr, 726da6c28aaSamw caller_context_t *ct, 727da6c28aaSamw int flags) 7287c478bd9Sstevel@tonic-gate { 729fa871852Sbatschul vnode_t *realvp; 730fa871852Sbatschul 7317c478bd9Sstevel@tonic-gate #ifdef LODEBUG 7327c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_link vp %p realvp %p\n", vp, realvp(vp)); 7337c478bd9Sstevel@tonic-gate #endif 73459cbbcadSsjelinek 73559cbbcadSsjelinek /* 73659cbbcadSsjelinek * The source and destination vnodes may be in different lofs 73759cbbcadSsjelinek * filesystems sharing the same underlying filesystem, so we need to 73859cbbcadSsjelinek * make sure that the filesystem containing the source vnode is not 73959cbbcadSsjelinek * mounted read-only (vn_link() has already checked the target vnode). 74059cbbcadSsjelinek * 74159cbbcadSsjelinek * In a situation such as: 74259cbbcadSsjelinek * 74359cbbcadSsjelinek * /data - regular filesystem 74459cbbcadSsjelinek * /foo - lofs mount of /data/foo 74559cbbcadSsjelinek * /bar - read-only lofs mount of /data/bar 74659cbbcadSsjelinek * 74759cbbcadSsjelinek * This disallows a link from /bar/somefile to /foo/somefile, 74859cbbcadSsjelinek * which would otherwise allow changes to somefile on the read-only 74959cbbcadSsjelinek * mounted /bar. 75059cbbcadSsjelinek */ 75159cbbcadSsjelinek 75259cbbcadSsjelinek if (vn_is_readonly(vp)) { 75359cbbcadSsjelinek return (EROFS); 75459cbbcadSsjelinek } 7557c478bd9Sstevel@tonic-gate while (vn_matchops(vp, lo_vnodeops)) { 7567c478bd9Sstevel@tonic-gate vp = realvp(vp); 7577c478bd9Sstevel@tonic-gate } 758fa871852Sbatschul 759fa871852Sbatschul /* 760fa871852Sbatschul * In the case where the source vnode is on another stacking 761fa871852Sbatschul * filesystem (such as specfs), the loop above will 762fa871852Sbatschul * terminate before finding the true underlying vnode. 763fa871852Sbatschul * 764fa871852Sbatschul * We use VOP_REALVP here to continue the search. 765fa871852Sbatschul */ 766da6c28aaSamw if (VOP_REALVP(vp, &realvp, ct) == 0) 767fa871852Sbatschul vp = realvp; 768fa871852Sbatschul 7697c478bd9Sstevel@tonic-gate while (vn_matchops(tdvp, lo_vnodeops)) { 7707c478bd9Sstevel@tonic-gate tdvp = realvp(tdvp); 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate if (vp->v_vfsp != tdvp->v_vfsp) 7737c478bd9Sstevel@tonic-gate return (EXDEV); 774da6c28aaSamw return (VOP_LINK(tdvp, vp, tnm, cr, ct, flags)); 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate static int 7787c478bd9Sstevel@tonic-gate lo_rename( 7797c478bd9Sstevel@tonic-gate vnode_t *odvp, 7807c478bd9Sstevel@tonic-gate char *onm, 7817c478bd9Sstevel@tonic-gate vnode_t *ndvp, 7827c478bd9Sstevel@tonic-gate char *nnm, 783da6c28aaSamw struct cred *cr, 784da6c28aaSamw caller_context_t *ct, 785da6c28aaSamw int flags) 7867c478bd9Sstevel@tonic-gate { 7877c478bd9Sstevel@tonic-gate vnode_t *tnvp; 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate #ifdef LODEBUG 7907c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_rename vp %p realvp %p\n", odvp, realvp(odvp)); 7917c478bd9Sstevel@tonic-gate #endif 7926bcc12b7Ssjelinek /* 7936bcc12b7Ssjelinek * If we are coming from a loop back mounted fs, that has been 7946bcc12b7Ssjelinek * mounted in the same filesystem as where we want to move to, 7956bcc12b7Ssjelinek * and that filesystem is read/write, but the lofs filesystem is 7966bcc12b7Ssjelinek * read only, we don't want to allow a rename of the file. The 7976bcc12b7Ssjelinek * vn_rename code checks to be sure the target is read/write already 7986bcc12b7Ssjelinek * so that is not necessary here. However, consider the following 7996bcc12b7Ssjelinek * example: 8006bcc12b7Ssjelinek * / - regular root fs 8016bcc12b7Ssjelinek * /foo - directory in root 8026bcc12b7Ssjelinek * /foo/bar - file in foo directory(in root fs) 8036bcc12b7Ssjelinek * /baz - directory in root 8046bcc12b7Ssjelinek * mount -F lofs -o ro /foo /baz - all still in root 8056bcc12b7Ssjelinek * directory 8066bcc12b7Ssjelinek * The fact that we mounted /foo on /baz read only should stop us 8076bcc12b7Ssjelinek * from renaming the file /foo/bar /bar, but it doesn't since 8086bcc12b7Ssjelinek * / is read/write. We are still renaming here since we are still 8096bcc12b7Ssjelinek * in the same filesystem, it is just that we do not check to see 8106bcc12b7Ssjelinek * if the filesystem we are coming from in this case is read only. 8116bcc12b7Ssjelinek */ 8126bcc12b7Ssjelinek if (odvp->v_vfsp->vfs_flag & VFS_RDONLY) 8136bcc12b7Ssjelinek return (EROFS); 8147c478bd9Sstevel@tonic-gate /* 8157c478bd9Sstevel@tonic-gate * We need to make sure we're not trying to remove a mount point for a 8167c478bd9Sstevel@tonic-gate * filesystem mounted on top of lofs, which only we know about. 8177c478bd9Sstevel@tonic-gate */ 8187c478bd9Sstevel@tonic-gate if (vn_matchops(ndvp, lo_vnodeops)) /* Not our problem. */ 8197c478bd9Sstevel@tonic-gate goto rename; 820da6c28aaSamw 821da6c28aaSamw /* 822da6c28aaSamw * XXXci - Once case-insensitive behavior is implemented, it should 823da6c28aaSamw * be added here. 824da6c28aaSamw */ 825da6c28aaSamw if (VOP_LOOKUP(ndvp, nnm, &tnvp, NULL, 0, NULL, cr, 826da6c28aaSamw ct, NULL, NULL) != 0) 8277c478bd9Sstevel@tonic-gate goto rename; 8287c478bd9Sstevel@tonic-gate if (tnvp->v_type != VDIR) { 8297c478bd9Sstevel@tonic-gate VN_RELE(tnvp); 8307c478bd9Sstevel@tonic-gate goto rename; 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate if (vn_mountedvfs(tnvp)) { 8337c478bd9Sstevel@tonic-gate VN_RELE(tnvp); 8347c478bd9Sstevel@tonic-gate return (EBUSY); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate VN_RELE(tnvp); 8377c478bd9Sstevel@tonic-gate rename: 8387c478bd9Sstevel@tonic-gate /* 8397c478bd9Sstevel@tonic-gate * Since the case we're dealing with above can happen at any layer in 8407c478bd9Sstevel@tonic-gate * the stack of lofs filesystems, we need to recurse down the stack, 8417c478bd9Sstevel@tonic-gate * checking to see if there are any instances of a filesystem mounted on 8427c478bd9Sstevel@tonic-gate * top of lofs. In order to keep on using the lofs version of 8437c478bd9Sstevel@tonic-gate * VOP_RENAME(), we make sure that while the target directory is of type 8447c478bd9Sstevel@tonic-gate * lofs, the source directory (the one used for getting the fs-specific 8457c478bd9Sstevel@tonic-gate * version of VOP_RENAME()) is also of type lofs. 8467c478bd9Sstevel@tonic-gate */ 8477c478bd9Sstevel@tonic-gate if (vn_matchops(ndvp, lo_vnodeops)) { 8487c478bd9Sstevel@tonic-gate ndvp = realvp(ndvp); /* Check the next layer */ 8497c478bd9Sstevel@tonic-gate } else { 8507c478bd9Sstevel@tonic-gate /* 8517c478bd9Sstevel@tonic-gate * We can go fast here 8527c478bd9Sstevel@tonic-gate */ 8537c478bd9Sstevel@tonic-gate while (vn_matchops(odvp, lo_vnodeops)) { 8547c478bd9Sstevel@tonic-gate odvp = realvp(odvp); 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate if (odvp->v_vfsp != ndvp->v_vfsp) 8577c478bd9Sstevel@tonic-gate return (EXDEV); 8587c478bd9Sstevel@tonic-gate } 859da6c28aaSamw return (VOP_RENAME(odvp, onm, ndvp, nnm, cr, ct, flags)); 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate static int 8637c478bd9Sstevel@tonic-gate lo_mkdir( 8647c478bd9Sstevel@tonic-gate vnode_t *dvp, 8657c478bd9Sstevel@tonic-gate char *nm, 8667c478bd9Sstevel@tonic-gate struct vattr *va, 8677c478bd9Sstevel@tonic-gate vnode_t **vpp, 868da6c28aaSamw struct cred *cr, 869da6c28aaSamw caller_context_t *ct, 870da6c28aaSamw int flags, 871da6c28aaSamw vsecattr_t *vsecp) 8727c478bd9Sstevel@tonic-gate { 8737c478bd9Sstevel@tonic-gate int error; 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate #ifdef LODEBUG 8767c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_mkdir vp %p realvp %p\n", dvp, realvp(dvp)); 8777c478bd9Sstevel@tonic-gate #endif 878da6c28aaSamw error = VOP_MKDIR(realvp(dvp), nm, va, vpp, cr, ct, flags, vsecp); 8797c478bd9Sstevel@tonic-gate if (!error) 880b431137cSowenr *vpp = makelonode(*vpp, vtoli(dvp->v_vfsp), 0); 8817c478bd9Sstevel@tonic-gate return (error); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate static int 885da6c28aaSamw lo_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct) 8867c478bd9Sstevel@tonic-gate { 8877c478bd9Sstevel@tonic-gate #ifdef LODEBUG 8887c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_realvp %p\n", vp); 8897c478bd9Sstevel@tonic-gate #endif 8907c478bd9Sstevel@tonic-gate while (vn_matchops(vp, lo_vnodeops)) 8917c478bd9Sstevel@tonic-gate vp = realvp(vp); 8927c478bd9Sstevel@tonic-gate 893da6c28aaSamw if (VOP_REALVP(vp, vpp, ct) != 0) 8947c478bd9Sstevel@tonic-gate *vpp = vp; 8957c478bd9Sstevel@tonic-gate return (0); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate static int 8997c478bd9Sstevel@tonic-gate lo_rmdir( 9007c478bd9Sstevel@tonic-gate vnode_t *dvp, 9017c478bd9Sstevel@tonic-gate char *nm, 9027c478bd9Sstevel@tonic-gate vnode_t *cdir, 903da6c28aaSamw struct cred *cr, 904da6c28aaSamw caller_context_t *ct, 905da6c28aaSamw int flags) 9067c478bd9Sstevel@tonic-gate { 9077c478bd9Sstevel@tonic-gate vnode_t *rvp = cdir; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate #ifdef LODEBUG 9107c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_rmdir vp %p realvp %p\n", dvp, realvp(dvp)); 9117c478bd9Sstevel@tonic-gate #endif 9127c478bd9Sstevel@tonic-gate /* if cdir is lofs vnode ptr get its real vnode ptr */ 9137c478bd9Sstevel@tonic-gate if (vn_matchops(dvp, vn_getops(rvp))) 914da6c28aaSamw (void) lo_realvp(cdir, &rvp, ct); 9157c478bd9Sstevel@tonic-gate dvp = realvp(dvp); 916da6c28aaSamw return (VOP_RMDIR(dvp, nm, rvp, cr, ct, flags)); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate static int 9207c478bd9Sstevel@tonic-gate lo_symlink( 9217c478bd9Sstevel@tonic-gate vnode_t *dvp, 9227c478bd9Sstevel@tonic-gate char *lnm, 9237c478bd9Sstevel@tonic-gate struct vattr *tva, 9247c478bd9Sstevel@tonic-gate char *tnm, 925da6c28aaSamw struct cred *cr, 926da6c28aaSamw caller_context_t *ct, 927da6c28aaSamw int flags) 9287c478bd9Sstevel@tonic-gate { 9297c478bd9Sstevel@tonic-gate #ifdef LODEBUG 9307c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_symlink vp %p realvp %p\n", dvp, realvp(dvp)); 9317c478bd9Sstevel@tonic-gate #endif 9327c478bd9Sstevel@tonic-gate dvp = realvp(dvp); 933da6c28aaSamw return (VOP_SYMLINK(dvp, lnm, tva, tnm, cr, ct, flags)); 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate static int 937da6c28aaSamw lo_readlink( 938da6c28aaSamw vnode_t *vp, 939da6c28aaSamw struct uio *uiop, 940da6c28aaSamw struct cred *cr, 941da6c28aaSamw caller_context_t *ct) 9427c478bd9Sstevel@tonic-gate { 9437c478bd9Sstevel@tonic-gate vp = realvp(vp); 944da6c28aaSamw return (VOP_READLINK(vp, uiop, cr, ct)); 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate static int 948da6c28aaSamw lo_readdir( 949da6c28aaSamw vnode_t *vp, 950da6c28aaSamw struct uio *uiop, 951da6c28aaSamw struct cred *cr, 952da6c28aaSamw int *eofp, 953da6c28aaSamw caller_context_t *ct, 954da6c28aaSamw int flags) 9557c478bd9Sstevel@tonic-gate { 9567c478bd9Sstevel@tonic-gate #ifdef LODEBUG 9577c478bd9Sstevel@tonic-gate lo_dprint(4, "lo_readdir vp %p realvp %p\n", vp, realvp(vp)); 9587c478bd9Sstevel@tonic-gate #endif 9597c478bd9Sstevel@tonic-gate vp = realvp(vp); 960da6c28aaSamw return (VOP_READDIR(vp, uiop, cr, eofp, ct, flags)); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate static int 9647c478bd9Sstevel@tonic-gate lo_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct) 9657c478bd9Sstevel@tonic-gate { 9667c478bd9Sstevel@tonic-gate vp = realvp(vp); 9677c478bd9Sstevel@tonic-gate return (VOP_RWLOCK(vp, write_lock, ct)); 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate static void 9717c478bd9Sstevel@tonic-gate lo_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct) 9727c478bd9Sstevel@tonic-gate { 9737c478bd9Sstevel@tonic-gate vp = realvp(vp); 9747c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, write_lock, ct); 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate static int 978da6c28aaSamw lo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) 9797c478bd9Sstevel@tonic-gate { 9807c478bd9Sstevel@tonic-gate vp = realvp(vp); 981da6c28aaSamw return (VOP_SEEK(vp, ooff, noffp, ct)); 9827c478bd9Sstevel@tonic-gate } 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate static int 985da6c28aaSamw lo_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct) 9867c478bd9Sstevel@tonic-gate { 9877c478bd9Sstevel@tonic-gate while (vn_matchops(vp1, lo_vnodeops)) 9887c478bd9Sstevel@tonic-gate vp1 = realvp(vp1); 9897c478bd9Sstevel@tonic-gate while (vn_matchops(vp2, lo_vnodeops)) 9907c478bd9Sstevel@tonic-gate vp2 = realvp(vp2); 991da6c28aaSamw return (VOP_CMP(vp1, vp2, ct)); 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate static int 9957c478bd9Sstevel@tonic-gate lo_frlock( 9967c478bd9Sstevel@tonic-gate vnode_t *vp, 9977c478bd9Sstevel@tonic-gate int cmd, 9987c478bd9Sstevel@tonic-gate struct flock64 *bfp, 9997c478bd9Sstevel@tonic-gate int flag, 10007c478bd9Sstevel@tonic-gate offset_t offset, 10017c478bd9Sstevel@tonic-gate struct flk_callback *flk_cbp, 1002da6c28aaSamw cred_t *cr, 1003da6c28aaSamw caller_context_t *ct) 10047c478bd9Sstevel@tonic-gate { 10057c478bd9Sstevel@tonic-gate vp = realvp(vp); 1006da6c28aaSamw return (VOP_FRLOCK(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct)); 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate static int 10107c478bd9Sstevel@tonic-gate lo_space( 10117c478bd9Sstevel@tonic-gate vnode_t *vp, 10127c478bd9Sstevel@tonic-gate int cmd, 10137c478bd9Sstevel@tonic-gate struct flock64 *bfp, 10147c478bd9Sstevel@tonic-gate int flag, 10157c478bd9Sstevel@tonic-gate offset_t offset, 10167c478bd9Sstevel@tonic-gate struct cred *cr, 10177c478bd9Sstevel@tonic-gate caller_context_t *ct) 10187c478bd9Sstevel@tonic-gate { 10197c478bd9Sstevel@tonic-gate vp = realvp(vp); 10207c478bd9Sstevel@tonic-gate return (VOP_SPACE(vp, cmd, bfp, flag, offset, cr, ct)); 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate static int 10247c478bd9Sstevel@tonic-gate lo_getpage( 10257c478bd9Sstevel@tonic-gate vnode_t *vp, 10267c478bd9Sstevel@tonic-gate offset_t off, 10277c478bd9Sstevel@tonic-gate size_t len, 10287c478bd9Sstevel@tonic-gate uint_t *prot, 10297c478bd9Sstevel@tonic-gate struct page *parr[], 10307c478bd9Sstevel@tonic-gate size_t psz, 10317c478bd9Sstevel@tonic-gate struct seg *seg, 10327c478bd9Sstevel@tonic-gate caddr_t addr, 10337c478bd9Sstevel@tonic-gate enum seg_rw rw, 1034da6c28aaSamw struct cred *cr, 1035da6c28aaSamw caller_context_t *ct) 10367c478bd9Sstevel@tonic-gate { 10377c478bd9Sstevel@tonic-gate vp = realvp(vp); 1038da6c28aaSamw return (VOP_GETPAGE(vp, off, len, prot, parr, psz, seg, addr, rw, cr, 1039*d7334e51Srm ct)); 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate static int 1043da6c28aaSamw lo_putpage( 1044da6c28aaSamw vnode_t *vp, 1045da6c28aaSamw offset_t off, 1046da6c28aaSamw size_t len, 1047da6c28aaSamw int flags, 1048da6c28aaSamw struct cred *cr, 1049da6c28aaSamw caller_context_t *ct) 10507c478bd9Sstevel@tonic-gate { 10517c478bd9Sstevel@tonic-gate vp = realvp(vp); 1052da6c28aaSamw return (VOP_PUTPAGE(vp, off, len, flags, cr, ct)); 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate static int 10567c478bd9Sstevel@tonic-gate lo_map( 10577c478bd9Sstevel@tonic-gate vnode_t *vp, 10587c478bd9Sstevel@tonic-gate offset_t off, 10597c478bd9Sstevel@tonic-gate struct as *as, 10607c478bd9Sstevel@tonic-gate caddr_t *addrp, 10617c478bd9Sstevel@tonic-gate size_t len, 10627c478bd9Sstevel@tonic-gate uchar_t prot, 10637c478bd9Sstevel@tonic-gate uchar_t maxprot, 10647c478bd9Sstevel@tonic-gate uint_t flags, 1065da6c28aaSamw struct cred *cr, 1066da6c28aaSamw caller_context_t *ct) 10677c478bd9Sstevel@tonic-gate { 10687c478bd9Sstevel@tonic-gate vp = realvp(vp); 1069da6c28aaSamw return (VOP_MAP(vp, off, as, addrp, len, prot, maxprot, flags, cr, ct)); 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate static int 10737c478bd9Sstevel@tonic-gate lo_addmap( 10747c478bd9Sstevel@tonic-gate vnode_t *vp, 10757c478bd9Sstevel@tonic-gate offset_t off, 10767c478bd9Sstevel@tonic-gate struct as *as, 10777c478bd9Sstevel@tonic-gate caddr_t addr, 10787c478bd9Sstevel@tonic-gate size_t len, 10797c478bd9Sstevel@tonic-gate uchar_t prot, 10807c478bd9Sstevel@tonic-gate uchar_t maxprot, 10817c478bd9Sstevel@tonic-gate uint_t flags, 1082da6c28aaSamw struct cred *cr, 1083da6c28aaSamw caller_context_t *ct) 10847c478bd9Sstevel@tonic-gate { 10857c478bd9Sstevel@tonic-gate vp = realvp(vp); 1086da6c28aaSamw return (VOP_ADDMAP(vp, off, as, addr, len, prot, maxprot, flags, cr, 1087*d7334e51Srm ct)); 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate static int 10917c478bd9Sstevel@tonic-gate lo_delmap( 10927c478bd9Sstevel@tonic-gate vnode_t *vp, 10937c478bd9Sstevel@tonic-gate offset_t off, 10947c478bd9Sstevel@tonic-gate struct as *as, 10957c478bd9Sstevel@tonic-gate caddr_t addr, 10967c478bd9Sstevel@tonic-gate size_t len, 10977c478bd9Sstevel@tonic-gate uint_t prot, 10987c478bd9Sstevel@tonic-gate uint_t maxprot, 10997c478bd9Sstevel@tonic-gate uint_t flags, 1100da6c28aaSamw struct cred *cr, 1101da6c28aaSamw caller_context_t *ct) 11027c478bd9Sstevel@tonic-gate { 11037c478bd9Sstevel@tonic-gate vp = realvp(vp); 1104da6c28aaSamw return (VOP_DELMAP(vp, off, as, addr, len, prot, maxprot, flags, cr, 1105*d7334e51Srm ct)); 11067c478bd9Sstevel@tonic-gate } 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate static int 11097c478bd9Sstevel@tonic-gate lo_poll( 11107c478bd9Sstevel@tonic-gate vnode_t *vp, 11117c478bd9Sstevel@tonic-gate short events, 11127c478bd9Sstevel@tonic-gate int anyyet, 11137c478bd9Sstevel@tonic-gate short *reventsp, 1114da6c28aaSamw struct pollhead **phpp, 1115da6c28aaSamw caller_context_t *ct) 11167c478bd9Sstevel@tonic-gate { 11177c478bd9Sstevel@tonic-gate vp = realvp(vp); 1118da6c28aaSamw return (VOP_POLL(vp, events, anyyet, reventsp, phpp, ct)); 11197c478bd9Sstevel@tonic-gate } 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate static int 1122*d7334e51Srm lo_dump(vnode_t *vp, caddr_t addr, offset_t bn, offset_t count, 1123*d7334e51Srm caller_context_t *ct) 11247c478bd9Sstevel@tonic-gate { 11257c478bd9Sstevel@tonic-gate vp = realvp(vp); 1126da6c28aaSamw return (VOP_DUMP(vp, addr, bn, count, ct)); 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate static int 1130da6c28aaSamw lo_pathconf( 1131da6c28aaSamw vnode_t *vp, 1132da6c28aaSamw int cmd, 1133da6c28aaSamw ulong_t *valp, 1134da6c28aaSamw struct cred *cr, 1135da6c28aaSamw caller_context_t *ct) 11367c478bd9Sstevel@tonic-gate { 11377c478bd9Sstevel@tonic-gate vp = realvp(vp); 1138da6c28aaSamw return (VOP_PATHCONF(vp, cmd, valp, cr, ct)); 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate static int 11427c478bd9Sstevel@tonic-gate lo_pageio( 11437c478bd9Sstevel@tonic-gate vnode_t *vp, 11447c478bd9Sstevel@tonic-gate struct page *pp, 11457c478bd9Sstevel@tonic-gate u_offset_t io_off, 11467c478bd9Sstevel@tonic-gate size_t io_len, 11477c478bd9Sstevel@tonic-gate int flags, 1148da6c28aaSamw cred_t *cr, 1149da6c28aaSamw caller_context_t *ct) 11507c478bd9Sstevel@tonic-gate { 11517c478bd9Sstevel@tonic-gate vp = realvp(vp); 1152da6c28aaSamw return (VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr, ct)); 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate static void 1156da6c28aaSamw lo_dispose( 1157da6c28aaSamw vnode_t *vp, 1158da6c28aaSamw page_t *pp, 1159da6c28aaSamw int fl, 1160da6c28aaSamw int dn, 1161da6c28aaSamw cred_t *cr, 1162da6c28aaSamw caller_context_t *ct) 11637c478bd9Sstevel@tonic-gate { 11647c478bd9Sstevel@tonic-gate vp = realvp(vp); 1165ad23a2dbSjohansen if (vp != NULL && !VN_ISKAS(vp)) 1166da6c28aaSamw VOP_DISPOSE(vp, pp, fl, dn, cr, ct); 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate static int 1170da6c28aaSamw lo_setsecattr( 1171da6c28aaSamw vnode_t *vp, 1172da6c28aaSamw vsecattr_t *secattr, 1173da6c28aaSamw int flags, 1174da6c28aaSamw struct cred *cr, 1175da6c28aaSamw caller_context_t *ct) 11767c478bd9Sstevel@tonic-gate { 11777c478bd9Sstevel@tonic-gate if (vn_is_readonly(vp)) 11787c478bd9Sstevel@tonic-gate return (EROFS); 11797c478bd9Sstevel@tonic-gate vp = realvp(vp); 1180da6c28aaSamw return (VOP_SETSECATTR(vp, secattr, flags, cr, ct)); 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate static int 1184da6c28aaSamw lo_getsecattr( 1185da6c28aaSamw vnode_t *vp, 1186da6c28aaSamw vsecattr_t *secattr, 1187da6c28aaSamw int flags, 1188da6c28aaSamw struct cred *cr, 1189da6c28aaSamw caller_context_t *ct) 11907c478bd9Sstevel@tonic-gate { 11917c478bd9Sstevel@tonic-gate vp = realvp(vp); 1192da6c28aaSamw return (VOP_GETSECATTR(vp, secattr, flags, cr, ct)); 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate static int 1196da6c28aaSamw lo_shrlock( 1197da6c28aaSamw vnode_t *vp, 1198da6c28aaSamw int cmd, 1199da6c28aaSamw struct shrlock *shr, 1200da6c28aaSamw int flag, 1201da6c28aaSamw cred_t *cr, 1202da6c28aaSamw caller_context_t *ct) 12037c478bd9Sstevel@tonic-gate { 12047c478bd9Sstevel@tonic-gate vp = realvp(vp); 1205da6c28aaSamw return (VOP_SHRLOCK(vp, cmd, shr, flag, cr, ct)); 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate /* 12097c478bd9Sstevel@tonic-gate * Loopback vnode operations vector. 12107c478bd9Sstevel@tonic-gate */ 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate struct vnodeops *lo_vnodeops; 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate const fs_operation_def_t lo_vnodeops_template[] = { 1215aa59c4cbSrsb VOPNAME_OPEN, { .vop_open = lo_open }, 1216aa59c4cbSrsb VOPNAME_CLOSE, { .vop_close = lo_close }, 1217aa59c4cbSrsb VOPNAME_READ, { .vop_read = lo_read }, 1218aa59c4cbSrsb VOPNAME_WRITE, { .vop_write = lo_write }, 1219aa59c4cbSrsb VOPNAME_IOCTL, { .vop_ioctl = lo_ioctl }, 1220aa59c4cbSrsb VOPNAME_SETFL, { .vop_setfl = lo_setfl }, 1221aa59c4cbSrsb VOPNAME_GETATTR, { .vop_getattr = lo_getattr }, 1222aa59c4cbSrsb VOPNAME_SETATTR, { .vop_setattr = lo_setattr }, 1223aa59c4cbSrsb VOPNAME_ACCESS, { .vop_access = lo_access }, 1224aa59c4cbSrsb VOPNAME_LOOKUP, { .vop_lookup = lo_lookup }, 1225aa59c4cbSrsb VOPNAME_CREATE, { .vop_create = lo_create }, 1226aa59c4cbSrsb VOPNAME_REMOVE, { .vop_remove = lo_remove }, 1227aa59c4cbSrsb VOPNAME_LINK, { .vop_link = lo_link }, 1228aa59c4cbSrsb VOPNAME_RENAME, { .vop_rename = lo_rename }, 1229aa59c4cbSrsb VOPNAME_MKDIR, { .vop_mkdir = lo_mkdir }, 1230aa59c4cbSrsb VOPNAME_RMDIR, { .vop_rmdir = lo_rmdir }, 1231aa59c4cbSrsb VOPNAME_READDIR, { .vop_readdir = lo_readdir }, 1232aa59c4cbSrsb VOPNAME_SYMLINK, { .vop_symlink = lo_symlink }, 1233aa59c4cbSrsb VOPNAME_READLINK, { .vop_readlink = lo_readlink }, 1234aa59c4cbSrsb VOPNAME_FSYNC, { .vop_fsync = lo_fsync }, 1235aa59c4cbSrsb VOPNAME_INACTIVE, { .vop_inactive = lo_inactive }, 1236aa59c4cbSrsb VOPNAME_FID, { .vop_fid = lo_fid }, 1237aa59c4cbSrsb VOPNAME_RWLOCK, { .vop_rwlock = lo_rwlock }, 1238aa59c4cbSrsb VOPNAME_RWUNLOCK, { .vop_rwunlock = lo_rwunlock }, 1239aa59c4cbSrsb VOPNAME_SEEK, { .vop_seek = lo_seek }, 1240aa59c4cbSrsb VOPNAME_CMP, { .vop_cmp = lo_cmp }, 1241aa59c4cbSrsb VOPNAME_FRLOCK, { .vop_frlock = lo_frlock }, 1242aa59c4cbSrsb VOPNAME_SPACE, { .vop_space = lo_space }, 1243aa59c4cbSrsb VOPNAME_REALVP, { .vop_realvp = lo_realvp }, 1244aa59c4cbSrsb VOPNAME_GETPAGE, { .vop_getpage = lo_getpage }, 1245aa59c4cbSrsb VOPNAME_PUTPAGE, { .vop_putpage = lo_putpage }, 1246aa59c4cbSrsb VOPNAME_MAP, { .vop_map = lo_map }, 1247aa59c4cbSrsb VOPNAME_ADDMAP, { .vop_addmap = lo_addmap }, 1248aa59c4cbSrsb VOPNAME_DELMAP, { .vop_delmap = lo_delmap }, 1249aa59c4cbSrsb VOPNAME_POLL, { .vop_poll = lo_poll }, 1250aa59c4cbSrsb VOPNAME_DUMP, { .vop_dump = lo_dump }, 1251aa59c4cbSrsb VOPNAME_DUMPCTL, { .error = fs_error }, /* XXX - why? */ 1252aa59c4cbSrsb VOPNAME_PATHCONF, { .vop_pathconf = lo_pathconf }, 1253aa59c4cbSrsb VOPNAME_PAGEIO, { .vop_pageio = lo_pageio }, 1254aa59c4cbSrsb VOPNAME_DISPOSE, { .vop_dispose = lo_dispose }, 1255aa59c4cbSrsb VOPNAME_SETSECATTR, { .vop_setsecattr = lo_setsecattr }, 1256aa59c4cbSrsb VOPNAME_GETSECATTR, { .vop_getsecattr = lo_getsecattr }, 1257aa59c4cbSrsb VOPNAME_SHRLOCK, { .vop_shrlock = lo_shrlock }, 1258aa59c4cbSrsb NULL, NULL 12597c478bd9Sstevel@tonic-gate }; 1260