1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/param.h> 30*0Sstevel@tonic-gate #include <sys/systm.h> 31*0Sstevel@tonic-gate #include <sys/errno.h> 32*0Sstevel@tonic-gate #include <sys/proc.h> 33*0Sstevel@tonic-gate #include <sys/vnode.h> 34*0Sstevel@tonic-gate #include <sys/vfs.h> 35*0Sstevel@tonic-gate #include <sys/uio.h> 36*0Sstevel@tonic-gate #include <sys/cred.h> 37*0Sstevel@tonic-gate #include <sys/pathname.h> 38*0Sstevel@tonic-gate #include <sys/dirent.h> 39*0Sstevel@tonic-gate #include <sys/debug.h> 40*0Sstevel@tonic-gate #include <sys/sysmacros.h> 41*0Sstevel@tonic-gate #include <sys/tiuser.h> 42*0Sstevel@tonic-gate #include <sys/cmn_err.h> 43*0Sstevel@tonic-gate #include <sys/stat.h> 44*0Sstevel@tonic-gate #include <sys/mode.h> 45*0Sstevel@tonic-gate #include <sys/policy.h> 46*0Sstevel@tonic-gate #include <rpc/types.h> 47*0Sstevel@tonic-gate #include <rpc/auth.h> 48*0Sstevel@tonic-gate #include <rpc/clnt.h> 49*0Sstevel@tonic-gate #include <sys/fs/autofs.h> 50*0Sstevel@tonic-gate #include <rpcsvc/autofs_prot.h> 51*0Sstevel@tonic-gate #include <fs/fs_subr.h> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate /* 54*0Sstevel@tonic-gate * Vnode ops for autofs 55*0Sstevel@tonic-gate */ 56*0Sstevel@tonic-gate static int auto_open(vnode_t **, int, cred_t *); 57*0Sstevel@tonic-gate static int auto_close(vnode_t *, int, int, offset_t, cred_t *); 58*0Sstevel@tonic-gate static int auto_getattr(vnode_t *, vattr_t *, int, cred_t *); 59*0Sstevel@tonic-gate static int auto_setattr(vnode_t *, vattr_t *, int, cred_t *, 60*0Sstevel@tonic-gate caller_context_t *); 61*0Sstevel@tonic-gate static int auto_access(vnode_t *, int, int, cred_t *); 62*0Sstevel@tonic-gate static int auto_lookup(vnode_t *, char *, vnode_t **, 63*0Sstevel@tonic-gate pathname_t *, int, vnode_t *, cred_t *); 64*0Sstevel@tonic-gate static int auto_create(vnode_t *, char *, vattr_t *, vcexcl_t, 65*0Sstevel@tonic-gate int, vnode_t **, cred_t *, int); 66*0Sstevel@tonic-gate static int auto_remove(vnode_t *, char *, cred_t *); 67*0Sstevel@tonic-gate static int auto_link(vnode_t *, vnode_t *, char *, cred_t *); 68*0Sstevel@tonic-gate static int auto_rename(vnode_t *, char *, vnode_t *, char *, cred_t *); 69*0Sstevel@tonic-gate static int auto_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *); 70*0Sstevel@tonic-gate static int auto_rmdir(vnode_t *, char *, vnode_t *, cred_t *); 71*0Sstevel@tonic-gate static int auto_readdir(vnode_t *, uio_t *, cred_t *, int *); 72*0Sstevel@tonic-gate static int auto_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *); 73*0Sstevel@tonic-gate static int auto_readlink(vnode_t *, struct uio *, cred_t *); 74*0Sstevel@tonic-gate static int auto_fsync(vnode_t *, int, cred_t *); 75*0Sstevel@tonic-gate static void auto_inactive(vnode_t *, cred_t *); 76*0Sstevel@tonic-gate static int auto_rwlock(vnode_t *, int, caller_context_t *); 77*0Sstevel@tonic-gate static void auto_rwunlock(vnode_t *vp, int, caller_context_t *); 78*0Sstevel@tonic-gate static int auto_seek(vnode_t *vp, offset_t, offset_t *); 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate static int auto_trigger_mount(vnode_t *, cred_t *, vnode_t **); 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate vnodeops_t *auto_vnodeops; 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate const fs_operation_def_t auto_vnodeops_template[] = { 85*0Sstevel@tonic-gate VOPNAME_OPEN, auto_open, 86*0Sstevel@tonic-gate VOPNAME_CLOSE, auto_close, 87*0Sstevel@tonic-gate VOPNAME_GETATTR, auto_getattr, 88*0Sstevel@tonic-gate VOPNAME_SETATTR, auto_setattr, 89*0Sstevel@tonic-gate VOPNAME_ACCESS, auto_access, 90*0Sstevel@tonic-gate VOPNAME_LOOKUP, auto_lookup, 91*0Sstevel@tonic-gate VOPNAME_CREATE, auto_create, 92*0Sstevel@tonic-gate VOPNAME_REMOVE, auto_remove, 93*0Sstevel@tonic-gate VOPNAME_LINK, auto_link, 94*0Sstevel@tonic-gate VOPNAME_RENAME, auto_rename, 95*0Sstevel@tonic-gate VOPNAME_MKDIR, auto_mkdir, 96*0Sstevel@tonic-gate VOPNAME_RMDIR, auto_rmdir, 97*0Sstevel@tonic-gate VOPNAME_READDIR, auto_readdir, 98*0Sstevel@tonic-gate VOPNAME_SYMLINK, auto_symlink, 99*0Sstevel@tonic-gate VOPNAME_READLINK, auto_readlink, 100*0Sstevel@tonic-gate VOPNAME_FSYNC, auto_fsync, 101*0Sstevel@tonic-gate VOPNAME_INACTIVE, (fs_generic_func_p) auto_inactive, 102*0Sstevel@tonic-gate VOPNAME_RWLOCK, auto_rwlock, 103*0Sstevel@tonic-gate VOPNAME_RWUNLOCK, (fs_generic_func_p) auto_rwunlock, 104*0Sstevel@tonic-gate VOPNAME_SEEK, auto_seek, 105*0Sstevel@tonic-gate VOPNAME_FRLOCK, fs_error, 106*0Sstevel@tonic-gate VOPNAME_DISPOSE, fs_error, 107*0Sstevel@tonic-gate VOPNAME_SHRLOCK, fs_error, 108*0Sstevel@tonic-gate NULL, NULL 109*0Sstevel@tonic-gate }; 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate /* ARGSUSED */ 112*0Sstevel@tonic-gate static int 113*0Sstevel@tonic-gate auto_open(vnode_t **vpp, int flag, cred_t *cred) 114*0Sstevel@tonic-gate { 115*0Sstevel@tonic-gate vnode_t *newvp; 116*0Sstevel@tonic-gate int error; 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_open: *vpp=%p\n", (void *)*vpp)); 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate error = auto_trigger_mount(*vpp, cred, &newvp); 121*0Sstevel@tonic-gate if (error) 122*0Sstevel@tonic-gate goto done; 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate if (newvp != NULL) { 125*0Sstevel@tonic-gate /* 126*0Sstevel@tonic-gate * Node is now mounted on. 127*0Sstevel@tonic-gate */ 128*0Sstevel@tonic-gate VN_RELE(*vpp); 129*0Sstevel@tonic-gate *vpp = newvp; 130*0Sstevel@tonic-gate error = VOP_ACCESS(*vpp, VREAD, 0, cred); 131*0Sstevel@tonic-gate if (!error) 132*0Sstevel@tonic-gate error = VOP_OPEN(vpp, flag, cred); 133*0Sstevel@tonic-gate } 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate done: 136*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_open: *vpp=%p error=%d\n", (void *)*vpp, 137*0Sstevel@tonic-gate error)); 138*0Sstevel@tonic-gate return (error); 139*0Sstevel@tonic-gate } 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate /* ARGSUSED */ 142*0Sstevel@tonic-gate static int 143*0Sstevel@tonic-gate auto_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cred) 144*0Sstevel@tonic-gate { 145*0Sstevel@tonic-gate return (0); 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate static int 149*0Sstevel@tonic-gate auto_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cred) 150*0Sstevel@tonic-gate { 151*0Sstevel@tonic-gate fnnode_t *fnp = vntofn(vp); 152*0Sstevel@tonic-gate vnode_t *newvp; 153*0Sstevel@tonic-gate vfs_t *vfsp; 154*0Sstevel@tonic-gate int error; 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_getattr vp %p\n", (void *)vp)); 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate if (error = vn_vfswlock_wait(vp)) 159*0Sstevel@tonic-gate return (error); 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate vfsp = vn_mountedvfs(vp); 162*0Sstevel@tonic-gate if (vfsp != NULL) { 163*0Sstevel@tonic-gate /* 164*0Sstevel@tonic-gate * Node is mounted on. 165*0Sstevel@tonic-gate */ 166*0Sstevel@tonic-gate vfs_lock_wait(vfsp); 167*0Sstevel@tonic-gate vn_vfsunlock(vp); 168*0Sstevel@tonic-gate error = VFS_ROOT(vfsp, &newvp); 169*0Sstevel@tonic-gate vfs_unlock(vfsp); 170*0Sstevel@tonic-gate if (error) 171*0Sstevel@tonic-gate return (error); 172*0Sstevel@tonic-gate mutex_enter(&fnp->fn_lock); 173*0Sstevel@tonic-gate if (fnp->fn_seen == newvp && fnp->fn_thread == curthread) { 174*0Sstevel@tonic-gate /* 175*0Sstevel@tonic-gate * Recursive auto_getattr(); just release newvp and drop 176*0Sstevel@tonic-gate * into the vfsp == NULL case. 177*0Sstevel@tonic-gate */ 178*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 179*0Sstevel@tonic-gate VN_RELE(newvp); 180*0Sstevel@tonic-gate } else { 181*0Sstevel@tonic-gate while (fnp->fn_thread && fnp->fn_thread != curthread) { 182*0Sstevel@tonic-gate fnp->fn_flags |= MF_ATTR_WAIT; 183*0Sstevel@tonic-gate cv_wait(&fnp->fn_cv_mount, &fnp->fn_lock); 184*0Sstevel@tonic-gate } 185*0Sstevel@tonic-gate fnp->fn_thread = curthread; 186*0Sstevel@tonic-gate fnp->fn_seen = newvp; 187*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 188*0Sstevel@tonic-gate error = VOP_GETATTR(newvp, vap, flags, cred); 189*0Sstevel@tonic-gate VN_RELE(newvp); 190*0Sstevel@tonic-gate mutex_enter(&fnp->fn_lock); 191*0Sstevel@tonic-gate fnp->fn_seen = 0; 192*0Sstevel@tonic-gate fnp->fn_thread = 0; 193*0Sstevel@tonic-gate if (fnp->fn_flags & MF_ATTR_WAIT) { 194*0Sstevel@tonic-gate fnp->fn_flags &= ~MF_ATTR_WAIT; 195*0Sstevel@tonic-gate cv_broadcast(&fnp->fn_cv_mount); 196*0Sstevel@tonic-gate } 197*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 198*0Sstevel@tonic-gate return (error); 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate } else { 201*0Sstevel@tonic-gate vn_vfsunlock(vp); 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate ASSERT(vp->v_type == VDIR || vp->v_type == VLNK); 205*0Sstevel@tonic-gate vap->va_uid = 0; 206*0Sstevel@tonic-gate vap->va_gid = 0; 207*0Sstevel@tonic-gate vap->va_nlink = fnp->fn_linkcnt; 208*0Sstevel@tonic-gate vap->va_nodeid = (u_longlong_t)fnp->fn_nodeid; 209*0Sstevel@tonic-gate vap->va_size = fnp->fn_size; 210*0Sstevel@tonic-gate vap->va_atime = fnp->fn_atime; 211*0Sstevel@tonic-gate vap->va_mtime = fnp->fn_mtime; 212*0Sstevel@tonic-gate vap->va_ctime = fnp->fn_ctime; 213*0Sstevel@tonic-gate vap->va_type = vp->v_type; 214*0Sstevel@tonic-gate vap->va_mode = fnp->fn_mode; 215*0Sstevel@tonic-gate vap->va_fsid = vp->v_vfsp->vfs_dev; 216*0Sstevel@tonic-gate vap->va_rdev = 0; 217*0Sstevel@tonic-gate vap->va_blksize = MAXBSIZE; 218*0Sstevel@tonic-gate vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size); 219*0Sstevel@tonic-gate vap->va_seq = 0; 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate return (0); 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /*ARGSUSED4*/ 225*0Sstevel@tonic-gate static int 226*0Sstevel@tonic-gate auto_setattr( 227*0Sstevel@tonic-gate vnode_t *vp, 228*0Sstevel@tonic-gate struct vattr *vap, 229*0Sstevel@tonic-gate int flags, 230*0Sstevel@tonic-gate cred_t *cred, 231*0Sstevel@tonic-gate caller_context_t *ct) 232*0Sstevel@tonic-gate { 233*0Sstevel@tonic-gate vnode_t *newvp; 234*0Sstevel@tonic-gate int error; 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp)); 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate if (error = auto_trigger_mount(vp, cred, &newvp)) 239*0Sstevel@tonic-gate goto done; 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate if (newvp != NULL) { 242*0Sstevel@tonic-gate /* 243*0Sstevel@tonic-gate * Node is mounted on. 244*0Sstevel@tonic-gate */ 245*0Sstevel@tonic-gate if (vn_is_readonly(newvp)) 246*0Sstevel@tonic-gate error = EROFS; 247*0Sstevel@tonic-gate else 248*0Sstevel@tonic-gate error = VOP_SETATTR(newvp, vap, flags, cred, NULL); 249*0Sstevel@tonic-gate VN_RELE(newvp); 250*0Sstevel@tonic-gate } else 251*0Sstevel@tonic-gate error = ENOSYS; 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate done: 254*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_setattr: error=%d\n", error)); 255*0Sstevel@tonic-gate return (error); 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate /* ARGSUSED */ 259*0Sstevel@tonic-gate static int 260*0Sstevel@tonic-gate auto_access(vnode_t *vp, int mode, int flags, cred_t *cred) 261*0Sstevel@tonic-gate { 262*0Sstevel@tonic-gate fnnode_t *fnp = vntofn(vp); 263*0Sstevel@tonic-gate vnode_t *newvp; 264*0Sstevel@tonic-gate int error; 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_access: vp=%p\n", (void *)vp)); 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate if (error = auto_trigger_mount(vp, cred, &newvp)) 269*0Sstevel@tonic-gate goto done; 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate if (newvp != NULL) { 272*0Sstevel@tonic-gate /* 273*0Sstevel@tonic-gate * Node is mounted on. 274*0Sstevel@tonic-gate */ 275*0Sstevel@tonic-gate error = VOP_ACCESS(newvp, mode, 0, cred); 276*0Sstevel@tonic-gate VN_RELE(newvp); 277*0Sstevel@tonic-gate } else { 278*0Sstevel@tonic-gate int shift = 0; 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate /* 281*0Sstevel@tonic-gate * really interested in the autofs node, check the 282*0Sstevel@tonic-gate * access on it 283*0Sstevel@tonic-gate */ 284*0Sstevel@tonic-gate ASSERT(error == 0); 285*0Sstevel@tonic-gate if (crgetuid(cred) != fnp->fn_uid) { 286*0Sstevel@tonic-gate shift += 3; 287*0Sstevel@tonic-gate if (groupmember(fnp->fn_gid, cred) == 0) 288*0Sstevel@tonic-gate shift += 3; 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate mode &= ~(fnp->fn_mode << shift); 291*0Sstevel@tonic-gate if (mode != 0) 292*0Sstevel@tonic-gate error = secpolicy_vnode_access(cred, vp, fnp->fn_uid, 293*0Sstevel@tonic-gate mode); 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate done: 297*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_access: error=%d\n", error)); 298*0Sstevel@tonic-gate return (error); 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate static int 303*0Sstevel@tonic-gate auto_lookup( 304*0Sstevel@tonic-gate vnode_t *dvp, 305*0Sstevel@tonic-gate char *nm, 306*0Sstevel@tonic-gate vnode_t **vpp, 307*0Sstevel@tonic-gate pathname_t *pnp, 308*0Sstevel@tonic-gate int flags, 309*0Sstevel@tonic-gate vnode_t *rdir, 310*0Sstevel@tonic-gate cred_t *cred) 311*0Sstevel@tonic-gate { 312*0Sstevel@tonic-gate int error = 0; 313*0Sstevel@tonic-gate vnode_t *newvp = NULL; 314*0Sstevel@tonic-gate vfs_t *vfsp; 315*0Sstevel@tonic-gate fninfo_t *dfnip; 316*0Sstevel@tonic-gate fnnode_t *dfnp = NULL; 317*0Sstevel@tonic-gate fnnode_t *fnp = NULL; 318*0Sstevel@tonic-gate char *searchnm; 319*0Sstevel@tonic-gate int operation; /* either AUTOFS_LOOKUP or AUTOFS_MOUNT */ 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate dfnip = vfstofni(dvp->v_vfsp); 322*0Sstevel@tonic-gate AUTOFS_DPRINT((3, "auto_lookup: dvp=%p (%s) name=%s\n", 323*0Sstevel@tonic-gate (void *)dvp, dfnip->fi_map, nm)); 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate if (nm[0] == 0) { 326*0Sstevel@tonic-gate VN_HOLD(dvp); 327*0Sstevel@tonic-gate *vpp = dvp; 328*0Sstevel@tonic-gate return (0); 329*0Sstevel@tonic-gate } 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate if (error = VOP_ACCESS(dvp, VEXEC, 0, cred)) 332*0Sstevel@tonic-gate return (error); 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate if (nm[0] == '.' && nm[1] == 0) { 335*0Sstevel@tonic-gate VN_HOLD(dvp); 336*0Sstevel@tonic-gate *vpp = dvp; 337*0Sstevel@tonic-gate return (0); 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate if (nm[0] == '.' && nm[1] == '.' && nm[2] == 0) { 341*0Sstevel@tonic-gate fnnode_t *pdfnp; 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate pdfnp = (vntofn(dvp))->fn_parent; 344*0Sstevel@tonic-gate ASSERT(pdfnp != NULL); 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate /* 347*0Sstevel@tonic-gate * Since it is legitimate to have the VROOT flag set for the 348*0Sstevel@tonic-gate * subdirectories of the indirect map in autofs filesystem, 349*0Sstevel@tonic-gate * rootfnnodep is checked against fnnode of dvp instead of 350*0Sstevel@tonic-gate * just checking whether VROOT flag is set in dvp 351*0Sstevel@tonic-gate */ 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate if (pdfnp == pdfnp->fn_globals->fng_rootfnnodep) { 354*0Sstevel@tonic-gate vnode_t *vp; 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate vfs_lock_wait(dvp->v_vfsp); 357*0Sstevel@tonic-gate if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) { 358*0Sstevel@tonic-gate vfs_unlock(dvp->v_vfsp); 359*0Sstevel@tonic-gate return (EIO); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate vp = dvp->v_vfsp->vfs_vnodecovered; 362*0Sstevel@tonic-gate VN_HOLD(vp); 363*0Sstevel@tonic-gate vfs_unlock(dvp->v_vfsp); 364*0Sstevel@tonic-gate error = VOP_LOOKUP(vp, nm, vpp, pnp, flags, rdir, cred); 365*0Sstevel@tonic-gate VN_RELE(vp); 366*0Sstevel@tonic-gate return (error); 367*0Sstevel@tonic-gate } else { 368*0Sstevel@tonic-gate *vpp = fntovn(pdfnp); 369*0Sstevel@tonic-gate VN_HOLD(*vpp); 370*0Sstevel@tonic-gate return (0); 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate } 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate top: 375*0Sstevel@tonic-gate dfnp = vntofn(dvp); 376*0Sstevel@tonic-gate searchnm = nm; 377*0Sstevel@tonic-gate operation = 0; 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate ASSERT(vn_matchops(dvp, auto_vnodeops)); 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate AUTOFS_DPRINT((3, "auto_lookup: dvp=%p dfnp=%p\n", (void *)dvp, 382*0Sstevel@tonic-gate (void *)dfnp)); 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate /* 385*0Sstevel@tonic-gate * If a lookup or mount of this node is in progress, wait for it 386*0Sstevel@tonic-gate * to finish, and return whatever result it got. 387*0Sstevel@tonic-gate */ 388*0Sstevel@tonic-gate mutex_enter(&dfnp->fn_lock); 389*0Sstevel@tonic-gate if (dfnp->fn_flags & (MF_LOOKUP | MF_INPROG)) { 390*0Sstevel@tonic-gate mutex_exit(&dfnp->fn_lock); 391*0Sstevel@tonic-gate error = auto_wait4mount(dfnp); 392*0Sstevel@tonic-gate if (error == AUTOFS_SHUTDOWN) 393*0Sstevel@tonic-gate error = ENOENT; 394*0Sstevel@tonic-gate if (error == EAGAIN) 395*0Sstevel@tonic-gate goto top; 396*0Sstevel@tonic-gate if (error) 397*0Sstevel@tonic-gate return (error); 398*0Sstevel@tonic-gate } else 399*0Sstevel@tonic-gate mutex_exit(&dfnp->fn_lock); 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate error = vn_vfswlock_wait(dvp); 403*0Sstevel@tonic-gate if (error) 404*0Sstevel@tonic-gate return (error); 405*0Sstevel@tonic-gate vfsp = vn_mountedvfs(dvp); 406*0Sstevel@tonic-gate if (vfsp != NULL) { 407*0Sstevel@tonic-gate vfs_lock_wait(vfsp); 408*0Sstevel@tonic-gate vn_vfsunlock(dvp); 409*0Sstevel@tonic-gate error = VFS_ROOT(vfsp, &newvp); 410*0Sstevel@tonic-gate vfs_unlock(vfsp); 411*0Sstevel@tonic-gate if (!error) { 412*0Sstevel@tonic-gate error = VOP_LOOKUP(newvp, nm, vpp, pnp, 413*0Sstevel@tonic-gate flags, rdir, cred); 414*0Sstevel@tonic-gate VN_RELE(newvp); 415*0Sstevel@tonic-gate } 416*0Sstevel@tonic-gate return (error); 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate vn_vfsunlock(dvp); 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate rw_enter(&dfnp->fn_rwlock, RW_READER); 421*0Sstevel@tonic-gate error = auto_search(dfnp, nm, &fnp, cred); 422*0Sstevel@tonic-gate if (error) { 423*0Sstevel@tonic-gate if (dfnip->fi_flags & MF_DIRECT) { 424*0Sstevel@tonic-gate /* 425*0Sstevel@tonic-gate * direct map. 426*0Sstevel@tonic-gate */ 427*0Sstevel@tonic-gate if (dfnp->fn_dirents) { 428*0Sstevel@tonic-gate /* 429*0Sstevel@tonic-gate * Mount previously triggered. 430*0Sstevel@tonic-gate * 'nm' not found 431*0Sstevel@tonic-gate */ 432*0Sstevel@tonic-gate error = ENOENT; 433*0Sstevel@tonic-gate } else { 434*0Sstevel@tonic-gate /* 435*0Sstevel@tonic-gate * I need to contact the daemon to trigger 436*0Sstevel@tonic-gate * the mount. 'dfnp' will be the mountpoint. 437*0Sstevel@tonic-gate */ 438*0Sstevel@tonic-gate operation = AUTOFS_MOUNT; 439*0Sstevel@tonic-gate VN_HOLD(fntovn(dfnp)); 440*0Sstevel@tonic-gate fnp = dfnp; 441*0Sstevel@tonic-gate error = 0; 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate } else if (dvp == dfnip->fi_rootvp) { 444*0Sstevel@tonic-gate /* 445*0Sstevel@tonic-gate * 'dfnp' is the root of the indirect AUTOFS. 446*0Sstevel@tonic-gate */ 447*0Sstevel@tonic-gate if (rw_tryupgrade(&dfnp->fn_rwlock) == 0) { 448*0Sstevel@tonic-gate /* 449*0Sstevel@tonic-gate * Could not acquire writer lock, release 450*0Sstevel@tonic-gate * reader, and wait until available. We 451*0Sstevel@tonic-gate * need to search for 'nm' again, since we 452*0Sstevel@tonic-gate * had to release the lock before reacquiring 453*0Sstevel@tonic-gate * it. 454*0Sstevel@tonic-gate */ 455*0Sstevel@tonic-gate rw_exit(&dfnp->fn_rwlock); 456*0Sstevel@tonic-gate rw_enter(&dfnp->fn_rwlock, RW_WRITER); 457*0Sstevel@tonic-gate error = auto_search(dfnp, nm, &fnp, cred); 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock)); 461*0Sstevel@tonic-gate if (error) { 462*0Sstevel@tonic-gate /* 463*0Sstevel@tonic-gate * create node being looked-up and request 464*0Sstevel@tonic-gate * mount on it. 465*0Sstevel@tonic-gate */ 466*0Sstevel@tonic-gate error = auto_enter(dfnp, nm, &fnp, kcred); 467*0Sstevel@tonic-gate if (!error) 468*0Sstevel@tonic-gate operation = AUTOFS_LOOKUP; 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate } else if ((dfnp->fn_dirents == NULL) && 471*0Sstevel@tonic-gate ((dvp->v_flag & VROOT) == 0) && 472*0Sstevel@tonic-gate ((fntovn(dfnp->fn_parent))->v_flag & VROOT)) { 473*0Sstevel@tonic-gate /* 474*0Sstevel@tonic-gate * dfnp is the actual 'mountpoint' of indirect map, 475*0Sstevel@tonic-gate * it is the equivalent of a direct mount, 476*0Sstevel@tonic-gate * ie, /home/'user1' 477*0Sstevel@tonic-gate */ 478*0Sstevel@tonic-gate operation = AUTOFS_MOUNT; 479*0Sstevel@tonic-gate VN_HOLD(fntovn(dfnp)); 480*0Sstevel@tonic-gate fnp = dfnp; 481*0Sstevel@tonic-gate error = 0; 482*0Sstevel@tonic-gate searchnm = dfnp->fn_name; 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate if (error == EAGAIN) { 487*0Sstevel@tonic-gate rw_exit(&dfnp->fn_rwlock); 488*0Sstevel@tonic-gate goto top; 489*0Sstevel@tonic-gate } 490*0Sstevel@tonic-gate if (error) { 491*0Sstevel@tonic-gate rw_exit(&dfnp->fn_rwlock); 492*0Sstevel@tonic-gate return (error); 493*0Sstevel@tonic-gate } 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate /* 496*0Sstevel@tonic-gate * We now have the actual fnnode we're interested in. 497*0Sstevel@tonic-gate * The 'MF_LOOKUP' indicates another thread is currently 498*0Sstevel@tonic-gate * performing a daemon lookup of this node, therefore we 499*0Sstevel@tonic-gate * wait for its completion. 500*0Sstevel@tonic-gate * The 'MF_INPROG' indicates another thread is currently 501*0Sstevel@tonic-gate * performing a daemon mount of this node, we wait for it 502*0Sstevel@tonic-gate * to be done if we are performing a MOUNT. We don't 503*0Sstevel@tonic-gate * wait for it if we are performing a LOOKUP. 504*0Sstevel@tonic-gate * We can release the reader/writer lock as soon as we acquire 505*0Sstevel@tonic-gate * the mutex, since the state of the lock can only change by 506*0Sstevel@tonic-gate * first acquiring the mutex. 507*0Sstevel@tonic-gate */ 508*0Sstevel@tonic-gate mutex_enter(&fnp->fn_lock); 509*0Sstevel@tonic-gate rw_exit(&dfnp->fn_rwlock); 510*0Sstevel@tonic-gate if ((fnp->fn_flags & MF_LOOKUP) || 511*0Sstevel@tonic-gate ((operation == AUTOFS_MOUNT) && (fnp->fn_flags & MF_INPROG))) { 512*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 513*0Sstevel@tonic-gate error = auto_wait4mount(fnp); 514*0Sstevel@tonic-gate VN_RELE(fntovn(fnp)); 515*0Sstevel@tonic-gate if (error == AUTOFS_SHUTDOWN) 516*0Sstevel@tonic-gate error = ENOENT; 517*0Sstevel@tonic-gate if (error && error != EAGAIN) 518*0Sstevel@tonic-gate return (error); 519*0Sstevel@tonic-gate goto top; 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate if (operation == 0) { 523*0Sstevel@tonic-gate /* 524*0Sstevel@tonic-gate * got the fnnode, check for any errors 525*0Sstevel@tonic-gate * on the previous operation on that node. 526*0Sstevel@tonic-gate */ 527*0Sstevel@tonic-gate error = fnp->fn_error; 528*0Sstevel@tonic-gate if ((error == EINTR) || (error == EAGAIN)) { 529*0Sstevel@tonic-gate /* 530*0Sstevel@tonic-gate * previous operation on this node was 531*0Sstevel@tonic-gate * not completed, do a lookup now. 532*0Sstevel@tonic-gate */ 533*0Sstevel@tonic-gate operation = AUTOFS_LOOKUP; 534*0Sstevel@tonic-gate } else { 535*0Sstevel@tonic-gate /* 536*0Sstevel@tonic-gate * previous operation completed. Return 537*0Sstevel@tonic-gate * a pointer to the node only if there was 538*0Sstevel@tonic-gate * no error. 539*0Sstevel@tonic-gate */ 540*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 541*0Sstevel@tonic-gate if (!error) 542*0Sstevel@tonic-gate *vpp = fntovn(fnp); 543*0Sstevel@tonic-gate else 544*0Sstevel@tonic-gate VN_RELE(fntovn(fnp)); 545*0Sstevel@tonic-gate return (error); 546*0Sstevel@tonic-gate } 547*0Sstevel@tonic-gate } 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate /* 550*0Sstevel@tonic-gate * Since I got to this point, it means I'm the one 551*0Sstevel@tonic-gate * responsible for triggering the mount/look-up of this node. 552*0Sstevel@tonic-gate */ 553*0Sstevel@tonic-gate switch (operation) { 554*0Sstevel@tonic-gate case AUTOFS_LOOKUP: 555*0Sstevel@tonic-gate AUTOFS_BLOCK_OTHERS(fnp, MF_LOOKUP); 556*0Sstevel@tonic-gate fnp->fn_error = 0; 557*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 558*0Sstevel@tonic-gate error = auto_lookup_aux(fnp, searchnm, cred); 559*0Sstevel@tonic-gate if (!error) { 560*0Sstevel@tonic-gate /* 561*0Sstevel@tonic-gate * Return this vnode 562*0Sstevel@tonic-gate */ 563*0Sstevel@tonic-gate *vpp = fntovn(fnp); 564*0Sstevel@tonic-gate } else { 565*0Sstevel@tonic-gate /* 566*0Sstevel@tonic-gate * release our reference to this vnode 567*0Sstevel@tonic-gate * and return error 568*0Sstevel@tonic-gate */ 569*0Sstevel@tonic-gate VN_RELE(fntovn(fnp)); 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate break; 572*0Sstevel@tonic-gate case AUTOFS_MOUNT: 573*0Sstevel@tonic-gate AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG); 574*0Sstevel@tonic-gate fnp->fn_error = 0; 575*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 576*0Sstevel@tonic-gate /* 577*0Sstevel@tonic-gate * auto_new_mount_thread fires up a new thread which 578*0Sstevel@tonic-gate * calls automountd finishing up the work 579*0Sstevel@tonic-gate */ 580*0Sstevel@tonic-gate auto_new_mount_thread(fnp, searchnm, cred); 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate /* 583*0Sstevel@tonic-gate * At this point, we are simply another thread 584*0Sstevel@tonic-gate * waiting for the mount to complete 585*0Sstevel@tonic-gate */ 586*0Sstevel@tonic-gate error = auto_wait4mount(fnp); 587*0Sstevel@tonic-gate if (error == AUTOFS_SHUTDOWN) 588*0Sstevel@tonic-gate error = ENOENT; 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate /* 591*0Sstevel@tonic-gate * now release our reference to this vnode 592*0Sstevel@tonic-gate */ 593*0Sstevel@tonic-gate VN_RELE(fntovn(fnp)); 594*0Sstevel@tonic-gate if (!error) 595*0Sstevel@tonic-gate goto top; 596*0Sstevel@tonic-gate break; 597*0Sstevel@tonic-gate default: 598*0Sstevel@tonic-gate auto_log(dfnp->fn_globals, CE_WARN, "auto_lookup: unknown " 599*0Sstevel@tonic-gate "operation %d", operation); 600*0Sstevel@tonic-gate } 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n", 603*0Sstevel@tonic-gate nm, (void *)*vpp, error)); 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate return (error); 606*0Sstevel@tonic-gate } 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate static int 609*0Sstevel@tonic-gate auto_create( 610*0Sstevel@tonic-gate vnode_t *dvp, 611*0Sstevel@tonic-gate char *nm, 612*0Sstevel@tonic-gate vattr_t *va, 613*0Sstevel@tonic-gate vcexcl_t excl, 614*0Sstevel@tonic-gate int mode, 615*0Sstevel@tonic-gate vnode_t **vpp, 616*0Sstevel@tonic-gate cred_t *cred, 617*0Sstevel@tonic-gate int flag) 618*0Sstevel@tonic-gate { 619*0Sstevel@tonic-gate vnode_t *newvp; 620*0Sstevel@tonic-gate int error; 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_create dvp %p nm %s\n", (void *)dvp, nm)); 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate if (error = auto_trigger_mount(dvp, cred, &newvp)) 625*0Sstevel@tonic-gate goto done; 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate if (newvp != NULL) { 628*0Sstevel@tonic-gate /* 629*0Sstevel@tonic-gate * Node is now mounted on. 630*0Sstevel@tonic-gate */ 631*0Sstevel@tonic-gate if (vn_is_readonly(newvp)) 632*0Sstevel@tonic-gate error = EROFS; 633*0Sstevel@tonic-gate else 634*0Sstevel@tonic-gate error = VOP_CREATE(newvp, nm, va, excl, 635*0Sstevel@tonic-gate mode, vpp, cred, flag); 636*0Sstevel@tonic-gate VN_RELE(newvp); 637*0Sstevel@tonic-gate } else 638*0Sstevel@tonic-gate error = ENOSYS; 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate done: 641*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_create: error=%d\n", error)); 642*0Sstevel@tonic-gate return (error); 643*0Sstevel@tonic-gate } 644*0Sstevel@tonic-gate 645*0Sstevel@tonic-gate static int 646*0Sstevel@tonic-gate auto_remove(vnode_t *dvp, char *nm, cred_t *cred) 647*0Sstevel@tonic-gate { 648*0Sstevel@tonic-gate vnode_t *newvp; 649*0Sstevel@tonic-gate int error; 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_remove dvp %p nm %s\n", (void *)dvp, nm)); 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate if (error = auto_trigger_mount(dvp, cred, &newvp)) 654*0Sstevel@tonic-gate goto done; 655*0Sstevel@tonic-gate 656*0Sstevel@tonic-gate if (newvp != NULL) { 657*0Sstevel@tonic-gate /* 658*0Sstevel@tonic-gate * Node is now mounted on. 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate if (vn_is_readonly(newvp)) 661*0Sstevel@tonic-gate error = EROFS; 662*0Sstevel@tonic-gate else 663*0Sstevel@tonic-gate error = VOP_REMOVE(newvp, nm, cred); 664*0Sstevel@tonic-gate VN_RELE(newvp); 665*0Sstevel@tonic-gate } else 666*0Sstevel@tonic-gate error = ENOSYS; 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate done: 669*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_remove: error=%d\n", error)); 670*0Sstevel@tonic-gate return (error); 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate static int 674*0Sstevel@tonic-gate auto_link(vnode_t *tdvp, vnode_t *svp, char *nm, cred_t *cred) 675*0Sstevel@tonic-gate { 676*0Sstevel@tonic-gate vnode_t *newvp; 677*0Sstevel@tonic-gate int error; 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_link tdvp %p svp %p nm %s\n", (void *)tdvp, 680*0Sstevel@tonic-gate (void *)svp, nm)); 681*0Sstevel@tonic-gate 682*0Sstevel@tonic-gate if (error = auto_trigger_mount(tdvp, cred, &newvp)) 683*0Sstevel@tonic-gate goto done; 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate if (newvp == NULL) { 686*0Sstevel@tonic-gate /* 687*0Sstevel@tonic-gate * an autonode can not be a link to another node 688*0Sstevel@tonic-gate */ 689*0Sstevel@tonic-gate error = ENOSYS; 690*0Sstevel@tonic-gate goto done; 691*0Sstevel@tonic-gate } 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate if (vn_is_readonly(newvp)) { 694*0Sstevel@tonic-gate error = EROFS; 695*0Sstevel@tonic-gate VN_RELE(newvp); 696*0Sstevel@tonic-gate goto done; 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate if (vn_matchops(svp, auto_vnodeops)) { 700*0Sstevel@tonic-gate /* 701*0Sstevel@tonic-gate * source vp can't be an autonode 702*0Sstevel@tonic-gate */ 703*0Sstevel@tonic-gate error = ENOSYS; 704*0Sstevel@tonic-gate VN_RELE(newvp); 705*0Sstevel@tonic-gate goto done; 706*0Sstevel@tonic-gate } 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate error = VOP_LINK(newvp, svp, nm, cred); 709*0Sstevel@tonic-gate VN_RELE(newvp); 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate done: 712*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_link error=%d\n", error)); 713*0Sstevel@tonic-gate return (error); 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate 716*0Sstevel@tonic-gate static int 717*0Sstevel@tonic-gate auto_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) 718*0Sstevel@tonic-gate { 719*0Sstevel@tonic-gate vnode_t *o_newvp, *n_newvp; 720*0Sstevel@tonic-gate int error; 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_rename odvp %p onm %s to ndvp %p nnm %s\n", 723*0Sstevel@tonic-gate (void *)odvp, onm, (void *)ndvp, nnm)); 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate /* 726*0Sstevel@tonic-gate * we know odvp is an autonode, otherwise this function 727*0Sstevel@tonic-gate * could not have ever been called. 728*0Sstevel@tonic-gate */ 729*0Sstevel@tonic-gate ASSERT(vn_matchops(odvp, auto_vnodeops)); 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate if (error = auto_trigger_mount(odvp, cr, &o_newvp)) 732*0Sstevel@tonic-gate goto done; 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate if (o_newvp == NULL) { 735*0Sstevel@tonic-gate /* 736*0Sstevel@tonic-gate * can't rename an autonode 737*0Sstevel@tonic-gate */ 738*0Sstevel@tonic-gate error = ENOSYS; 739*0Sstevel@tonic-gate goto done; 740*0Sstevel@tonic-gate } 741*0Sstevel@tonic-gate 742*0Sstevel@tonic-gate if (vn_matchops(ndvp, auto_vnodeops)) { 743*0Sstevel@tonic-gate /* 744*0Sstevel@tonic-gate * directory is AUTOFS, need to trigger the 745*0Sstevel@tonic-gate * mount of the real filesystem. 746*0Sstevel@tonic-gate */ 747*0Sstevel@tonic-gate if (error = auto_trigger_mount(ndvp, cr, &n_newvp)) { 748*0Sstevel@tonic-gate VN_RELE(o_newvp); 749*0Sstevel@tonic-gate goto done; 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate if (n_newvp == NULL) { 753*0Sstevel@tonic-gate /* 754*0Sstevel@tonic-gate * target can't be an autonode 755*0Sstevel@tonic-gate */ 756*0Sstevel@tonic-gate error = ENOSYS; 757*0Sstevel@tonic-gate VN_RELE(o_newvp); 758*0Sstevel@tonic-gate goto done; 759*0Sstevel@tonic-gate } 760*0Sstevel@tonic-gate } else { 761*0Sstevel@tonic-gate /* 762*0Sstevel@tonic-gate * destination directory mount had been 763*0Sstevel@tonic-gate * triggered prior to the call to this function. 764*0Sstevel@tonic-gate */ 765*0Sstevel@tonic-gate n_newvp = ndvp; 766*0Sstevel@tonic-gate } 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate ASSERT(!vn_matchops(n_newvp, auto_vnodeops)); 769*0Sstevel@tonic-gate 770*0Sstevel@tonic-gate if (vn_is_readonly(n_newvp)) { 771*0Sstevel@tonic-gate error = EROFS; 772*0Sstevel@tonic-gate VN_RELE(o_newvp); 773*0Sstevel@tonic-gate if (n_newvp != ndvp) 774*0Sstevel@tonic-gate VN_RELE(n_newvp); 775*0Sstevel@tonic-gate goto done; 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate error = VOP_RENAME(o_newvp, onm, n_newvp, nnm, cr); 779*0Sstevel@tonic-gate VN_RELE(o_newvp); 780*0Sstevel@tonic-gate if (n_newvp != ndvp) 781*0Sstevel@tonic-gate VN_RELE(n_newvp); 782*0Sstevel@tonic-gate 783*0Sstevel@tonic-gate done: 784*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_rename error=%d\n", error)); 785*0Sstevel@tonic-gate return (error); 786*0Sstevel@tonic-gate } 787*0Sstevel@tonic-gate 788*0Sstevel@tonic-gate static int 789*0Sstevel@tonic-gate auto_mkdir(vnode_t *dvp, char *nm, vattr_t *va, vnode_t **vpp, cred_t *cred) 790*0Sstevel@tonic-gate { 791*0Sstevel@tonic-gate vnode_t *newvp; 792*0Sstevel@tonic-gate int error; 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_mkdir dvp %p nm %s\n", (void *)dvp, nm)); 795*0Sstevel@tonic-gate 796*0Sstevel@tonic-gate if (error = auto_trigger_mount(dvp, cred, &newvp)) 797*0Sstevel@tonic-gate goto done; 798*0Sstevel@tonic-gate 799*0Sstevel@tonic-gate if (newvp != NULL) { 800*0Sstevel@tonic-gate /* 801*0Sstevel@tonic-gate * Node is now mounted on. 802*0Sstevel@tonic-gate */ 803*0Sstevel@tonic-gate if (vn_is_readonly(newvp)) 804*0Sstevel@tonic-gate error = EROFS; 805*0Sstevel@tonic-gate else 806*0Sstevel@tonic-gate error = VOP_MKDIR(newvp, nm, va, vpp, cred); 807*0Sstevel@tonic-gate VN_RELE(newvp); 808*0Sstevel@tonic-gate } else 809*0Sstevel@tonic-gate error = ENOSYS; 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate done: 812*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_mkdir: error=%d\n", error)); 813*0Sstevel@tonic-gate return (error); 814*0Sstevel@tonic-gate } 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate static int 817*0Sstevel@tonic-gate auto_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cred) 818*0Sstevel@tonic-gate { 819*0Sstevel@tonic-gate vnode_t *newvp; 820*0Sstevel@tonic-gate int error; 821*0Sstevel@tonic-gate 822*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_rmdir: vp=%p nm=%s\n", (void *)dvp, nm)); 823*0Sstevel@tonic-gate 824*0Sstevel@tonic-gate if (error = auto_trigger_mount(dvp, cred, &newvp)) 825*0Sstevel@tonic-gate goto done; 826*0Sstevel@tonic-gate 827*0Sstevel@tonic-gate if (newvp != NULL) { 828*0Sstevel@tonic-gate /* 829*0Sstevel@tonic-gate * Node is now mounted on. 830*0Sstevel@tonic-gate */ 831*0Sstevel@tonic-gate if (vn_is_readonly(newvp)) 832*0Sstevel@tonic-gate error = EROFS; 833*0Sstevel@tonic-gate else 834*0Sstevel@tonic-gate error = VOP_RMDIR(newvp, nm, cdir, cred); 835*0Sstevel@tonic-gate VN_RELE(newvp); 836*0Sstevel@tonic-gate } else 837*0Sstevel@tonic-gate error = ENOSYS; 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate done: 840*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_rmdir: error=%d\n", error)); 841*0Sstevel@tonic-gate return (error); 842*0Sstevel@tonic-gate } 843*0Sstevel@tonic-gate 844*0Sstevel@tonic-gate static int autofs_nobrowse = 0; 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate #ifdef nextdp 847*0Sstevel@tonic-gate #undef nextdp 848*0Sstevel@tonic-gate #endif 849*0Sstevel@tonic-gate #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate static int 852*0Sstevel@tonic-gate auto_readdir(vnode_t *vp, uio_t *uiop, cred_t *cred, int *eofp) 853*0Sstevel@tonic-gate { 854*0Sstevel@tonic-gate struct autofs_rddirargs rda; 855*0Sstevel@tonic-gate struct autofs_rddirres rd; 856*0Sstevel@tonic-gate fnnode_t *fnp = vntofn(vp); 857*0Sstevel@tonic-gate fnnode_t *cfnp, *nfnp; 858*0Sstevel@tonic-gate dirent64_t *dp; 859*0Sstevel@tonic-gate ulong_t offset; 860*0Sstevel@tonic-gate ulong_t outcount = 0, count = 0; 861*0Sstevel@tonic-gate size_t namelen; 862*0Sstevel@tonic-gate ulong_t alloc_count; 863*0Sstevel@tonic-gate void *outbuf; 864*0Sstevel@tonic-gate fninfo_t *fnip = vfstofni(vp->v_vfsp); 865*0Sstevel@tonic-gate struct iovec *iovp; 866*0Sstevel@tonic-gate int error = 0; 867*0Sstevel@tonic-gate int reached_max = 0; 868*0Sstevel@tonic-gate int myeof = 0; 869*0Sstevel@tonic-gate int this_reclen; 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n", 872*0Sstevel@tonic-gate (void *)vp, uiop->uio_loffset)); 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate if (eofp != NULL) 875*0Sstevel@tonic-gate *eofp = 0; 876*0Sstevel@tonic-gate 877*0Sstevel@tonic-gate iovp = uiop->uio_iov; 878*0Sstevel@tonic-gate alloc_count = iovp->iov_len; 879*0Sstevel@tonic-gate 880*0Sstevel@tonic-gate if (uiop->uio_iovcnt != 1) 881*0Sstevel@tonic-gate return (EINVAL); 882*0Sstevel@tonic-gate 883*0Sstevel@tonic-gate gethrestime(&fnp->fn_atime); 884*0Sstevel@tonic-gate fnp->fn_ref_time = fnp->fn_atime.tv_sec; 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate dp = outbuf = kmem_alloc(alloc_count, KM_SLEEP); 887*0Sstevel@tonic-gate 888*0Sstevel@tonic-gate /* 889*0Sstevel@tonic-gate * Held when getdents calls VOP_RWLOCK.... 890*0Sstevel@tonic-gate */ 891*0Sstevel@tonic-gate ASSERT(RW_READ_HELD(&fnp->fn_rwlock)); 892*0Sstevel@tonic-gate if (uiop->uio_offset >= AUTOFS_DAEMONCOOKIE) { 893*0Sstevel@tonic-gate again: 894*0Sstevel@tonic-gate /* 895*0Sstevel@tonic-gate * Do readdir of daemon contents only 896*0Sstevel@tonic-gate * Drop readers lock and reacquire after reply. 897*0Sstevel@tonic-gate */ 898*0Sstevel@tonic-gate rw_exit(&fnp->fn_rwlock); 899*0Sstevel@tonic-gate 900*0Sstevel@tonic-gate count = 0; 901*0Sstevel@tonic-gate rda.rda_map = fnip->fi_map; 902*0Sstevel@tonic-gate rda.rda_offset = (uint_t)uiop->uio_offset; 903*0Sstevel@tonic-gate rd.rd_rddir.rddir_entries = dp; 904*0Sstevel@tonic-gate rda.rda_count = rd.rd_rddir.rddir_size = (uint_t)alloc_count; 905*0Sstevel@tonic-gate error = auto_calldaemon(fnip, AUTOFS_READDIR, 906*0Sstevel@tonic-gate xdr_autofs_rddirargs, &rda, 907*0Sstevel@tonic-gate xdr_autofs_rddirres, &rd, 908*0Sstevel@tonic-gate cred, TRUE); 909*0Sstevel@tonic-gate /* 910*0Sstevel@tonic-gate * reacquire previously dropped lock 911*0Sstevel@tonic-gate */ 912*0Sstevel@tonic-gate rw_enter(&fnp->fn_rwlock, RW_READER); 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate if (!error) 915*0Sstevel@tonic-gate error = rd.rd_status; 916*0Sstevel@tonic-gate if (error) { 917*0Sstevel@tonic-gate if (error == AUTOFS_SHUTDOWN) { 918*0Sstevel@tonic-gate /* 919*0Sstevel@tonic-gate * treat as empty directory 920*0Sstevel@tonic-gate */ 921*0Sstevel@tonic-gate error = 0; 922*0Sstevel@tonic-gate myeof = 1; 923*0Sstevel@tonic-gate if (eofp) 924*0Sstevel@tonic-gate *eofp = 1; 925*0Sstevel@tonic-gate } 926*0Sstevel@tonic-gate goto done; 927*0Sstevel@tonic-gate } 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate if (rd.rd_rddir.rddir_size) { 930*0Sstevel@tonic-gate dirent64_t *odp = dp; /* next in output buffer */ 931*0Sstevel@tonic-gate dirent64_t *cdp = dp; /* current examined entry */ 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate /* 934*0Sstevel@tonic-gate * Check for duplicates here 935*0Sstevel@tonic-gate */ 936*0Sstevel@tonic-gate do { 937*0Sstevel@tonic-gate this_reclen = cdp->d_reclen; 938*0Sstevel@tonic-gate if (auto_search(fnp, cdp->d_name, NULL, cred)) { 939*0Sstevel@tonic-gate /* 940*0Sstevel@tonic-gate * entry not found in kernel list, 941*0Sstevel@tonic-gate * include it in readdir output. 942*0Sstevel@tonic-gate * 943*0Sstevel@tonic-gate * If we are skipping entries. then 944*0Sstevel@tonic-gate * we need to copy this entry to the 945*0Sstevel@tonic-gate * correct position in the buffer 946*0Sstevel@tonic-gate * to be copied out. 947*0Sstevel@tonic-gate */ 948*0Sstevel@tonic-gate if (cdp != odp) 949*0Sstevel@tonic-gate bcopy(cdp, odp, 950*0Sstevel@tonic-gate (size_t)this_reclen); 951*0Sstevel@tonic-gate odp = nextdp(odp); 952*0Sstevel@tonic-gate outcount += this_reclen; 953*0Sstevel@tonic-gate } else { 954*0Sstevel@tonic-gate /* 955*0Sstevel@tonic-gate * Entry was found in the kernel 956*0Sstevel@tonic-gate * list. If it is the first entry 957*0Sstevel@tonic-gate * in this buffer, then just skip it 958*0Sstevel@tonic-gate */ 959*0Sstevel@tonic-gate if (odp == dp) { 960*0Sstevel@tonic-gate dp = nextdp(dp); 961*0Sstevel@tonic-gate odp = dp; 962*0Sstevel@tonic-gate } 963*0Sstevel@tonic-gate } 964*0Sstevel@tonic-gate count += this_reclen; 965*0Sstevel@tonic-gate cdp = (struct dirent64 *) 966*0Sstevel@tonic-gate ((char *)cdp + this_reclen); 967*0Sstevel@tonic-gate } while (count < rd.rd_rddir.rddir_size); 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate if (outcount) 970*0Sstevel@tonic-gate error = uiomove(dp, outcount, UIO_READ, uiop); 971*0Sstevel@tonic-gate uiop->uio_offset = rd.rd_rddir.rddir_offset; 972*0Sstevel@tonic-gate } else { 973*0Sstevel@tonic-gate if (rd.rd_rddir.rddir_eof == 0) { 974*0Sstevel@tonic-gate /* 975*0Sstevel@tonic-gate * alloc_count not large enough for one 976*0Sstevel@tonic-gate * directory entry 977*0Sstevel@tonic-gate */ 978*0Sstevel@tonic-gate error = EINVAL; 979*0Sstevel@tonic-gate } 980*0Sstevel@tonic-gate } 981*0Sstevel@tonic-gate if (rd.rd_rddir.rddir_eof && !error) { 982*0Sstevel@tonic-gate myeof = 1; 983*0Sstevel@tonic-gate if (eofp) 984*0Sstevel@tonic-gate *eofp = 1; 985*0Sstevel@tonic-gate } 986*0Sstevel@tonic-gate if (!error && !myeof && outcount == 0) { 987*0Sstevel@tonic-gate /* 988*0Sstevel@tonic-gate * call daemon with new cookie, all previous 989*0Sstevel@tonic-gate * elements happened to be duplicates 990*0Sstevel@tonic-gate */ 991*0Sstevel@tonic-gate dp = outbuf; 992*0Sstevel@tonic-gate goto again; 993*0Sstevel@tonic-gate } 994*0Sstevel@tonic-gate goto done; 995*0Sstevel@tonic-gate } 996*0Sstevel@tonic-gate 997*0Sstevel@tonic-gate if (uiop->uio_offset == 0) { 998*0Sstevel@tonic-gate /* 999*0Sstevel@tonic-gate * first time: so fudge the . and .. 1000*0Sstevel@tonic-gate */ 1001*0Sstevel@tonic-gate this_reclen = DIRENT64_RECLEN(1); 1002*0Sstevel@tonic-gate if (alloc_count < this_reclen) { 1003*0Sstevel@tonic-gate error = EINVAL; 1004*0Sstevel@tonic-gate goto done; 1005*0Sstevel@tonic-gate } 1006*0Sstevel@tonic-gate dp->d_ino = (ino64_t)fnp->fn_nodeid; 1007*0Sstevel@tonic-gate dp->d_off = (off64_t)1; 1008*0Sstevel@tonic-gate dp->d_reclen = (ushort_t)this_reclen; 1009*0Sstevel@tonic-gate 1010*0Sstevel@tonic-gate /* use strncpy(9f) to zero out uninitialized bytes */ 1011*0Sstevel@tonic-gate 1012*0Sstevel@tonic-gate (void) strncpy(dp->d_name, ".", 1013*0Sstevel@tonic-gate DIRENT64_NAMELEN(this_reclen)); 1014*0Sstevel@tonic-gate outcount += dp->d_reclen; 1015*0Sstevel@tonic-gate dp = nextdp(dp); 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate this_reclen = DIRENT64_RECLEN(2); 1018*0Sstevel@tonic-gate if (alloc_count < outcount + this_reclen) { 1019*0Sstevel@tonic-gate error = EINVAL; 1020*0Sstevel@tonic-gate goto done; 1021*0Sstevel@tonic-gate } 1022*0Sstevel@tonic-gate dp->d_reclen = (ushort_t)this_reclen; 1023*0Sstevel@tonic-gate dp->d_ino = (ino64_t)fnp->fn_parent->fn_nodeid; 1024*0Sstevel@tonic-gate dp->d_off = (off64_t)2; 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate /* use strncpy(9f) to zero out uninitialized bytes */ 1027*0Sstevel@tonic-gate 1028*0Sstevel@tonic-gate (void) strncpy(dp->d_name, "..", 1029*0Sstevel@tonic-gate DIRENT64_NAMELEN(this_reclen)); 1030*0Sstevel@tonic-gate outcount += dp->d_reclen; 1031*0Sstevel@tonic-gate dp = nextdp(dp); 1032*0Sstevel@tonic-gate } 1033*0Sstevel@tonic-gate 1034*0Sstevel@tonic-gate offset = 2; 1035*0Sstevel@tonic-gate cfnp = fnp->fn_dirents; 1036*0Sstevel@tonic-gate while (cfnp != NULL) { 1037*0Sstevel@tonic-gate nfnp = cfnp->fn_next; 1038*0Sstevel@tonic-gate offset = cfnp->fn_offset; 1039*0Sstevel@tonic-gate if ((offset >= uiop->uio_offset) && 1040*0Sstevel@tonic-gate (!(cfnp->fn_flags & MF_LOOKUP))) { 1041*0Sstevel@tonic-gate int reclen; 1042*0Sstevel@tonic-gate 1043*0Sstevel@tonic-gate /* 1044*0Sstevel@tonic-gate * include node only if its offset is greater or 1045*0Sstevel@tonic-gate * equal to the one required and it is not in 1046*0Sstevel@tonic-gate * transient state (not being looked-up) 1047*0Sstevel@tonic-gate */ 1048*0Sstevel@tonic-gate namelen = strlen(cfnp->fn_name); 1049*0Sstevel@tonic-gate reclen = (int)DIRENT64_RECLEN(namelen); 1050*0Sstevel@tonic-gate if (outcount + reclen > alloc_count) { 1051*0Sstevel@tonic-gate reached_max = 1; 1052*0Sstevel@tonic-gate break; 1053*0Sstevel@tonic-gate } 1054*0Sstevel@tonic-gate dp->d_reclen = (ushort_t)reclen; 1055*0Sstevel@tonic-gate dp->d_ino = (ino64_t)cfnp->fn_nodeid; 1056*0Sstevel@tonic-gate if (nfnp != NULL) { 1057*0Sstevel@tonic-gate /* 1058*0Sstevel@tonic-gate * get the offset of the next element 1059*0Sstevel@tonic-gate */ 1060*0Sstevel@tonic-gate dp->d_off = (off64_t)nfnp->fn_offset; 1061*0Sstevel@tonic-gate } else { 1062*0Sstevel@tonic-gate /* 1063*0Sstevel@tonic-gate * This is the last element, make 1064*0Sstevel@tonic-gate * offset one plus the current 1065*0Sstevel@tonic-gate */ 1066*0Sstevel@tonic-gate dp->d_off = (off64_t)cfnp->fn_offset + 1; 1067*0Sstevel@tonic-gate } 1068*0Sstevel@tonic-gate 1069*0Sstevel@tonic-gate /* use strncpy(9f) to zero out uninitialized bytes */ 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate (void) strncpy(dp->d_name, cfnp->fn_name, 1072*0Sstevel@tonic-gate DIRENT64_NAMELEN(reclen)); 1073*0Sstevel@tonic-gate outcount += dp->d_reclen; 1074*0Sstevel@tonic-gate dp = nextdp(dp); 1075*0Sstevel@tonic-gate } 1076*0Sstevel@tonic-gate cfnp = nfnp; 1077*0Sstevel@tonic-gate } 1078*0Sstevel@tonic-gate 1079*0Sstevel@tonic-gate if (outcount) 1080*0Sstevel@tonic-gate error = uiomove(outbuf, outcount, UIO_READ, uiop); 1081*0Sstevel@tonic-gate if (!error) { 1082*0Sstevel@tonic-gate if (reached_max) { 1083*0Sstevel@tonic-gate /* 1084*0Sstevel@tonic-gate * This entry did not get added to the buffer on this, 1085*0Sstevel@tonic-gate * call. We need to add it on the next call therefore 1086*0Sstevel@tonic-gate * set uio_offset to this entry's offset. If there 1087*0Sstevel@tonic-gate * wasn't enough space for one dirent, return EINVAL. 1088*0Sstevel@tonic-gate */ 1089*0Sstevel@tonic-gate uiop->uio_offset = offset; 1090*0Sstevel@tonic-gate if (outcount == 0) 1091*0Sstevel@tonic-gate error = EINVAL; 1092*0Sstevel@tonic-gate } else if (autofs_nobrowse || 1093*0Sstevel@tonic-gate auto_nobrowse_option(fnip->fi_opts) || 1094*0Sstevel@tonic-gate (fnip->fi_flags & MF_DIRECT) || (fnp->fn_trigger != NULL) || 1095*0Sstevel@tonic-gate (((vp->v_flag & VROOT) == 0) && 1096*0Sstevel@tonic-gate ((fntovn(fnp->fn_parent))->v_flag & VROOT) && 1097*0Sstevel@tonic-gate (fnp->fn_dirents == NULL))) { 1098*0Sstevel@tonic-gate /* 1099*0Sstevel@tonic-gate * done reading directory entries 1100*0Sstevel@tonic-gate */ 1101*0Sstevel@tonic-gate uiop->uio_offset = offset + 1; 1102*0Sstevel@tonic-gate if (eofp) 1103*0Sstevel@tonic-gate *eofp = 1; 1104*0Sstevel@tonic-gate } else { 1105*0Sstevel@tonic-gate /* 1106*0Sstevel@tonic-gate * Need to get the rest of the entries from the daemon. 1107*0Sstevel@tonic-gate */ 1108*0Sstevel@tonic-gate uiop->uio_offset = AUTOFS_DAEMONCOOKIE; 1109*0Sstevel@tonic-gate } 1110*0Sstevel@tonic-gate } 1111*0Sstevel@tonic-gate 1112*0Sstevel@tonic-gate done: 1113*0Sstevel@tonic-gate kmem_free(outbuf, alloc_count); 1114*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n", 1115*0Sstevel@tonic-gate (void *)vp, uiop->uio_loffset, myeof)); 1116*0Sstevel@tonic-gate return (error); 1117*0Sstevel@tonic-gate } 1118*0Sstevel@tonic-gate 1119*0Sstevel@tonic-gate static int 1120*0Sstevel@tonic-gate auto_symlink( 1121*0Sstevel@tonic-gate vnode_t *dvp, 1122*0Sstevel@tonic-gate char *lnknm, /* new entry */ 1123*0Sstevel@tonic-gate vattr_t *tva, 1124*0Sstevel@tonic-gate char *tnm, /* existing entry */ 1125*0Sstevel@tonic-gate cred_t *cred) 1126*0Sstevel@tonic-gate { 1127*0Sstevel@tonic-gate vnode_t *newvp; 1128*0Sstevel@tonic-gate int error; 1129*0Sstevel@tonic-gate 1130*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_symlink: dvp=%p lnknm=%s tnm=%s\n", 1131*0Sstevel@tonic-gate (void *)dvp, lnknm, tnm)); 1132*0Sstevel@tonic-gate 1133*0Sstevel@tonic-gate if (error = auto_trigger_mount(dvp, cred, &newvp)) 1134*0Sstevel@tonic-gate goto done; 1135*0Sstevel@tonic-gate 1136*0Sstevel@tonic-gate if (newvp != NULL) { 1137*0Sstevel@tonic-gate /* 1138*0Sstevel@tonic-gate * Node is mounted on. 1139*0Sstevel@tonic-gate */ 1140*0Sstevel@tonic-gate if (vn_is_readonly(newvp)) 1141*0Sstevel@tonic-gate error = EROFS; 1142*0Sstevel@tonic-gate else 1143*0Sstevel@tonic-gate error = VOP_SYMLINK(newvp, lnknm, tva, tnm, cred); 1144*0Sstevel@tonic-gate VN_RELE(newvp); 1145*0Sstevel@tonic-gate } else 1146*0Sstevel@tonic-gate error = ENOSYS; 1147*0Sstevel@tonic-gate 1148*0Sstevel@tonic-gate done: 1149*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_symlink: error=%d\n", error)); 1150*0Sstevel@tonic-gate return (error); 1151*0Sstevel@tonic-gate } 1152*0Sstevel@tonic-gate 1153*0Sstevel@tonic-gate /* ARGSUSED */ 1154*0Sstevel@tonic-gate static int 1155*0Sstevel@tonic-gate auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr) 1156*0Sstevel@tonic-gate { 1157*0Sstevel@tonic-gate fnnode_t *fnp = vntofn(vp); 1158*0Sstevel@tonic-gate int error; 1159*0Sstevel@tonic-gate timestruc_t now; 1160*0Sstevel@tonic-gate 1161*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp)); 1162*0Sstevel@tonic-gate 1163*0Sstevel@tonic-gate gethrestime(&now); 1164*0Sstevel@tonic-gate fnp->fn_ref_time = now.tv_sec; 1165*0Sstevel@tonic-gate 1166*0Sstevel@tonic-gate if (vp->v_type != VLNK) 1167*0Sstevel@tonic-gate error = EINVAL; 1168*0Sstevel@tonic-gate else { 1169*0Sstevel@tonic-gate ASSERT(!(fnp->fn_flags & (MF_INPROG | MF_LOOKUP))); 1170*0Sstevel@tonic-gate fnp->fn_atime = now; 1171*0Sstevel@tonic-gate error = uiomove(fnp->fn_symlink, MIN(fnp->fn_symlinklen, 1172*0Sstevel@tonic-gate uiop->uio_resid), UIO_READ, uiop); 1173*0Sstevel@tonic-gate } 1174*0Sstevel@tonic-gate 1175*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error)); 1176*0Sstevel@tonic-gate return (error); 1177*0Sstevel@tonic-gate } 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate /* ARGSUSED */ 1180*0Sstevel@tonic-gate static int 1181*0Sstevel@tonic-gate auto_fsync(vnode_t *cp, int syncflag, cred_t *cred) 1182*0Sstevel@tonic-gate { 1183*0Sstevel@tonic-gate return (0); 1184*0Sstevel@tonic-gate } 1185*0Sstevel@tonic-gate 1186*0Sstevel@tonic-gate /* ARGSUSED */ 1187*0Sstevel@tonic-gate static void 1188*0Sstevel@tonic-gate auto_inactive(vnode_t *vp, cred_t *cred) 1189*0Sstevel@tonic-gate { 1190*0Sstevel@tonic-gate fnnode_t *fnp = vntofn(vp); 1191*0Sstevel@tonic-gate fnnode_t *dfnp = fnp->fn_parent; 1192*0Sstevel@tonic-gate int count; 1193*0Sstevel@tonic-gate 1194*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_inactive: vp=%p v_count=%u fn_link=%d\n", 1195*0Sstevel@tonic-gate (void *)vp, vp->v_count, fnp->fn_linkcnt)); 1196*0Sstevel@tonic-gate 1197*0Sstevel@tonic-gate /* 1198*0Sstevel@tonic-gate * The rwlock should not be already held by this thread. 1199*0Sstevel@tonic-gate * The assert relies on the fact that the owner field is cleared 1200*0Sstevel@tonic-gate * when the lock is released. 1201*0Sstevel@tonic-gate */ 1202*0Sstevel@tonic-gate ASSERT(dfnp != NULL); 1203*0Sstevel@tonic-gate ASSERT(rw_owner(&dfnp->fn_rwlock) != curthread); 1204*0Sstevel@tonic-gate rw_enter(&dfnp->fn_rwlock, RW_WRITER); 1205*0Sstevel@tonic-gate mutex_enter(&vp->v_lock); 1206*0Sstevel@tonic-gate ASSERT(vp->v_count > 0); 1207*0Sstevel@tonic-gate count = --vp->v_count; 1208*0Sstevel@tonic-gate mutex_exit(&vp->v_lock); 1209*0Sstevel@tonic-gate if (count == 0) { 1210*0Sstevel@tonic-gate /* 1211*0Sstevel@tonic-gate * Free only if node has no subdirectories. 1212*0Sstevel@tonic-gate */ 1213*0Sstevel@tonic-gate if (fnp->fn_linkcnt == 1) { 1214*0Sstevel@tonic-gate auto_disconnect(dfnp, fnp); 1215*0Sstevel@tonic-gate rw_exit(&dfnp->fn_rwlock); 1216*0Sstevel@tonic-gate auto_freefnnode(fnp); 1217*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p freed\n", 1218*0Sstevel@tonic-gate (void *)vp)); 1219*0Sstevel@tonic-gate return; 1220*0Sstevel@tonic-gate } 1221*0Sstevel@tonic-gate } 1222*0Sstevel@tonic-gate rw_exit(&dfnp->fn_rwlock); 1223*0Sstevel@tonic-gate 1224*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p v_count=%u fn_link=%d\n", 1225*0Sstevel@tonic-gate (void *)vp, vp->v_count, fnp->fn_linkcnt)); 1226*0Sstevel@tonic-gate } 1227*0Sstevel@tonic-gate 1228*0Sstevel@tonic-gate /* ARGSUSED2 */ 1229*0Sstevel@tonic-gate static int 1230*0Sstevel@tonic-gate auto_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct) 1231*0Sstevel@tonic-gate { 1232*0Sstevel@tonic-gate fnnode_t *fnp = vntofn(vp); 1233*0Sstevel@tonic-gate if (write_lock) 1234*0Sstevel@tonic-gate rw_enter(&fnp->fn_rwlock, RW_WRITER); 1235*0Sstevel@tonic-gate else 1236*0Sstevel@tonic-gate rw_enter(&fnp->fn_rwlock, RW_READER); 1237*0Sstevel@tonic-gate return (write_lock); 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate /* ARGSUSED */ 1241*0Sstevel@tonic-gate static void 1242*0Sstevel@tonic-gate auto_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct) 1243*0Sstevel@tonic-gate { 1244*0Sstevel@tonic-gate fnnode_t *fnp = vntofn(vp); 1245*0Sstevel@tonic-gate rw_exit(&fnp->fn_rwlock); 1246*0Sstevel@tonic-gate } 1247*0Sstevel@tonic-gate 1248*0Sstevel@tonic-gate 1249*0Sstevel@tonic-gate /* ARGSUSED */ 1250*0Sstevel@tonic-gate static int 1251*0Sstevel@tonic-gate auto_seek(struct vnode *vp, offset_t ooff, offset_t *noffp) 1252*0Sstevel@tonic-gate { 1253*0Sstevel@tonic-gate /* 1254*0Sstevel@tonic-gate * Return 0 unconditionally, since we expect 1255*0Sstevel@tonic-gate * a VDIR all the time 1256*0Sstevel@tonic-gate */ 1257*0Sstevel@tonic-gate return (0); 1258*0Sstevel@tonic-gate } 1259*0Sstevel@tonic-gate 1260*0Sstevel@tonic-gate /* 1261*0Sstevel@tonic-gate * Triggers the mount if needed. If the mount has been triggered by 1262*0Sstevel@tonic-gate * another thread, it will wait for its return status, and return it. 1263*0Sstevel@tonic-gate * Whether the mount is triggered by this thread, another thread, or 1264*0Sstevel@tonic-gate * if the vnode was already covered, '*newvp' is a 1265*0Sstevel@tonic-gate * VN_HELD vnode pointing to the root of the filesystem covering 'vp'. 1266*0Sstevel@tonic-gate * If the node is not mounted on, and should not be mounted on, '*newvp' 1267*0Sstevel@tonic-gate * will be NULL. 1268*0Sstevel@tonic-gate * The calling routine may use '*newvp' to do the filesystem jump. 1269*0Sstevel@tonic-gate */ 1270*0Sstevel@tonic-gate static int 1271*0Sstevel@tonic-gate auto_trigger_mount(vnode_t *vp, cred_t *cred, vnode_t **newvp) 1272*0Sstevel@tonic-gate { 1273*0Sstevel@tonic-gate fnnode_t *fnp = vntofn(vp); 1274*0Sstevel@tonic-gate fninfo_t *fnip = vfstofni(vp->v_vfsp); 1275*0Sstevel@tonic-gate vnode_t *dvp; 1276*0Sstevel@tonic-gate vfs_t *vfsp; 1277*0Sstevel@tonic-gate int delayed_ind; 1278*0Sstevel@tonic-gate char name[AUTOFS_MAXPATHLEN]; 1279*0Sstevel@tonic-gate int error; 1280*0Sstevel@tonic-gate 1281*0Sstevel@tonic-gate AUTOFS_DPRINT((4, "auto_trigger_mount: vp=%p\n", (void *)vp)); 1282*0Sstevel@tonic-gate 1283*0Sstevel@tonic-gate *newvp = NULL; 1284*0Sstevel@tonic-gate 1285*0Sstevel@tonic-gate /* 1286*0Sstevel@tonic-gate * Cross-zone mount triggering is disallowed. 1287*0Sstevel@tonic-gate */ 1288*0Sstevel@tonic-gate if (fnip->fi_zoneid != getzoneid()) 1289*0Sstevel@tonic-gate return (EPERM); /* Not owner of mount */ 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate retry: 1292*0Sstevel@tonic-gate error = 0; 1293*0Sstevel@tonic-gate delayed_ind = 0; 1294*0Sstevel@tonic-gate mutex_enter(&fnp->fn_lock); 1295*0Sstevel@tonic-gate while (fnp->fn_flags & (MF_LOOKUP | MF_INPROG)) { 1296*0Sstevel@tonic-gate /* 1297*0Sstevel@tonic-gate * Mount or lookup in progress, 1298*0Sstevel@tonic-gate * wait for it before proceeding. 1299*0Sstevel@tonic-gate */ 1300*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 1301*0Sstevel@tonic-gate error = auto_wait4mount(fnp); 1302*0Sstevel@tonic-gate if (error == AUTOFS_SHUTDOWN) { 1303*0Sstevel@tonic-gate error = 0; 1304*0Sstevel@tonic-gate goto done; 1305*0Sstevel@tonic-gate } 1306*0Sstevel@tonic-gate if (error && error != EAGAIN) 1307*0Sstevel@tonic-gate goto done; 1308*0Sstevel@tonic-gate error = 0; 1309*0Sstevel@tonic-gate mutex_enter(&fnp->fn_lock); 1310*0Sstevel@tonic-gate } 1311*0Sstevel@tonic-gate 1312*0Sstevel@tonic-gate /* 1313*0Sstevel@tonic-gate * If the vfslock can't be acquired for the first time. 1314*0Sstevel@tonic-gate * drop the fn_lock and retry next time in blocking mode. 1315*0Sstevel@tonic-gate */ 1316*0Sstevel@tonic-gate if (vn_vfswlock(vp)) { 1317*0Sstevel@tonic-gate /* 1318*0Sstevel@tonic-gate * Lock held by another thread. 1319*0Sstevel@tonic-gate * Perform blocking by dropping the 1320*0Sstevel@tonic-gate * fn_lock. 1321*0Sstevel@tonic-gate */ 1322*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 1323*0Sstevel@tonic-gate error = vn_vfswlock_wait(vp); 1324*0Sstevel@tonic-gate if (error) 1325*0Sstevel@tonic-gate goto done; 1326*0Sstevel@tonic-gate /* 1327*0Sstevel@tonic-gate * Because fn_lock wasn't held, the state 1328*0Sstevel@tonic-gate * of the trigger node might have changed. 1329*0Sstevel@tonic-gate * Need to run through the checks on trigger 1330*0Sstevel@tonic-gate * node again. 1331*0Sstevel@tonic-gate */ 1332*0Sstevel@tonic-gate vn_vfsunlock(vp); 1333*0Sstevel@tonic-gate goto retry; 1334*0Sstevel@tonic-gate } 1335*0Sstevel@tonic-gate 1336*0Sstevel@tonic-gate vfsp = vn_mountedvfs(vp); 1337*0Sstevel@tonic-gate if (vfsp != NULL) { 1338*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 1339*0Sstevel@tonic-gate vfs_lock_wait(vfsp); 1340*0Sstevel@tonic-gate vn_vfsunlock(vp); 1341*0Sstevel@tonic-gate error = VFS_ROOT(vfsp, newvp); 1342*0Sstevel@tonic-gate vfs_unlock(vfsp); 1343*0Sstevel@tonic-gate goto done; 1344*0Sstevel@tonic-gate } else { 1345*0Sstevel@tonic-gate vn_vfsunlock(vp); 1346*0Sstevel@tonic-gate if ((fnp->fn_flags & MF_MOUNTPOINT) && 1347*0Sstevel@tonic-gate fnp->fn_trigger != NULL) { 1348*0Sstevel@tonic-gate ASSERT(fnp->fn_dirents == NULL); 1349*0Sstevel@tonic-gate /* 1350*0Sstevel@tonic-gate * The filesystem that used to sit here has been 1351*0Sstevel@tonic-gate * forcibly unmounted. 1352*0Sstevel@tonic-gate */ 1353*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 1354*0Sstevel@tonic-gate error = EIO; 1355*0Sstevel@tonic-gate goto done; 1356*0Sstevel@tonic-gate } 1357*0Sstevel@tonic-gate } 1358*0Sstevel@tonic-gate 1359*0Sstevel@tonic-gate ASSERT(vp->v_type == VDIR); 1360*0Sstevel@tonic-gate dvp = fntovn(fnp->fn_parent); 1361*0Sstevel@tonic-gate 1362*0Sstevel@tonic-gate if ((fnp->fn_dirents == NULL) && 1363*0Sstevel@tonic-gate ((fnip->fi_flags & MF_DIRECT) == 0) && 1364*0Sstevel@tonic-gate ((vp->v_flag & VROOT) == 0) && 1365*0Sstevel@tonic-gate (dvp->v_flag & VROOT)) { 1366*0Sstevel@tonic-gate /* 1367*0Sstevel@tonic-gate * If the parent of this node is the root of an indirect 1368*0Sstevel@tonic-gate * AUTOFS filesystem, this node is remountable. 1369*0Sstevel@tonic-gate */ 1370*0Sstevel@tonic-gate delayed_ind = 1; 1371*0Sstevel@tonic-gate } 1372*0Sstevel@tonic-gate 1373*0Sstevel@tonic-gate if (delayed_ind || 1374*0Sstevel@tonic-gate ((fnip->fi_flags & MF_DIRECT) && (fnp->fn_dirents == NULL))) { 1375*0Sstevel@tonic-gate /* 1376*0Sstevel@tonic-gate * Trigger mount since: 1377*0Sstevel@tonic-gate * direct mountpoint with no subdirs or 1378*0Sstevel@tonic-gate * delayed indirect. 1379*0Sstevel@tonic-gate */ 1380*0Sstevel@tonic-gate AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG); 1381*0Sstevel@tonic-gate fnp->fn_error = 0; 1382*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 1383*0Sstevel@tonic-gate if (delayed_ind) 1384*0Sstevel@tonic-gate (void) strcpy(name, fnp->fn_name); 1385*0Sstevel@tonic-gate else 1386*0Sstevel@tonic-gate (void) strcpy(name, "."); 1387*0Sstevel@tonic-gate fnp->fn_ref_time = gethrestime_sec(); 1388*0Sstevel@tonic-gate auto_new_mount_thread(fnp, name, cred); 1389*0Sstevel@tonic-gate /* 1390*0Sstevel@tonic-gate * At this point we're simply another thread waiting 1391*0Sstevel@tonic-gate * for the mount to finish. 1392*0Sstevel@tonic-gate */ 1393*0Sstevel@tonic-gate error = auto_wait4mount(fnp); 1394*0Sstevel@tonic-gate if (error == EAGAIN) 1395*0Sstevel@tonic-gate goto retry; 1396*0Sstevel@tonic-gate if (error == AUTOFS_SHUTDOWN) { 1397*0Sstevel@tonic-gate error = 0; 1398*0Sstevel@tonic-gate goto done; 1399*0Sstevel@tonic-gate } 1400*0Sstevel@tonic-gate if (error == 0) { 1401*0Sstevel@tonic-gate if (error = vn_vfswlock_wait(vp)) 1402*0Sstevel@tonic-gate goto done; 1403*0Sstevel@tonic-gate /* Reacquire after dropping locks */ 1404*0Sstevel@tonic-gate vfsp = vn_mountedvfs(vp); 1405*0Sstevel@tonic-gate if (vfsp != NULL) { 1406*0Sstevel@tonic-gate vfs_lock_wait(vfsp); 1407*0Sstevel@tonic-gate vn_vfsunlock(vp); 1408*0Sstevel@tonic-gate error = VFS_ROOT(vfsp, newvp); 1409*0Sstevel@tonic-gate vfs_unlock(vfsp); 1410*0Sstevel@tonic-gate } else { 1411*0Sstevel@tonic-gate vn_vfsunlock(vp); 1412*0Sstevel@tonic-gate goto retry; 1413*0Sstevel@tonic-gate } 1414*0Sstevel@tonic-gate } 1415*0Sstevel@tonic-gate } else 1416*0Sstevel@tonic-gate mutex_exit(&fnp->fn_lock); 1417*0Sstevel@tonic-gate 1418*0Sstevel@tonic-gate done: 1419*0Sstevel@tonic-gate AUTOFS_DPRINT((5, "auto_trigger_mount: error=%d\n", error)); 1420*0Sstevel@tonic-gate return (error); 1421*0Sstevel@tonic-gate } 1422