1e2950f41STomohiro Kusumi /*- 2d53d00abSTomohiro Kusumi * Copyright (c) 2016 Tomohiro Kusumi <kusumi.tomohiro@gmail.com> 3e2950f41STomohiro Kusumi * Copyright (c) 2016 The DragonFly Project 4e2950f41STomohiro Kusumi * Copyright (c) 2014 The FreeBSD Foundation 5e2950f41STomohiro Kusumi * All rights reserved. 6e2950f41STomohiro Kusumi * 7e2950f41STomohiro Kusumi * This software was developed by Edward Tomasz Napierala under sponsorship 8e2950f41STomohiro Kusumi * from the FreeBSD Foundation. 9e2950f41STomohiro Kusumi * 10e2950f41STomohiro Kusumi * Redistribution and use in source and binary forms, with or without 11e2950f41STomohiro Kusumi * modification, are permitted provided that the following conditions 12e2950f41STomohiro Kusumi * are met: 13e2950f41STomohiro Kusumi * 1. Redistributions of source code must retain the above copyright 14e2950f41STomohiro Kusumi * notice, this list of conditions and the following disclaimer. 15e2950f41STomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright 16e2950f41STomohiro Kusumi * notice, this list of conditions and the following disclaimer in the 17e2950f41STomohiro Kusumi * documentation and/or other materials provided with the distribution. 18e2950f41STomohiro Kusumi * 19e2950f41STomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20e2950f41STomohiro Kusumi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21e2950f41STomohiro Kusumi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22e2950f41STomohiro Kusumi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23e2950f41STomohiro Kusumi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24e2950f41STomohiro Kusumi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25e2950f41STomohiro Kusumi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26e2950f41STomohiro Kusumi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27e2950f41STomohiro Kusumi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28e2950f41STomohiro Kusumi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29e2950f41STomohiro Kusumi * SUCH DAMAGE. 30e2950f41STomohiro Kusumi * 31e2950f41STomohiro Kusumi */ 32e2950f41STomohiro Kusumi 33e2950f41STomohiro Kusumi #include <sys/kernel.h> 34e2950f41STomohiro Kusumi #include <sys/module.h> 35e2950f41STomohiro Kusumi #include <sys/stat.h> 36e2950f41STomohiro Kusumi #include <sys/dirent.h> 37e2950f41STomohiro Kusumi #include <sys/namei.h> 38e2950f41STomohiro Kusumi #include <sys/nlookup.h> 39e2950f41STomohiro Kusumi #include <sys/mountctl.h> 40e2950f41STomohiro Kusumi 41e2950f41STomohiro Kusumi #include "autofs.h" 42e2950f41STomohiro Kusumi 43f568b8a3STomohiro Kusumi static bool 44e2950f41STomohiro Kusumi test_fs_root(struct vnode *vp) 45e2950f41STomohiro Kusumi { 46e2950f41STomohiro Kusumi int error; 47e2950f41STomohiro Kusumi 48e2950f41STomohiro Kusumi if ((error = vget(vp, LK_SHARED)) != 0) { 49e2950f41STomohiro Kusumi AUTOFS_WARN("vget failed with error %d", error); 50f568b8a3STomohiro Kusumi return (false); 51e2950f41STomohiro Kusumi } 52e2950f41STomohiro Kusumi 53e2950f41STomohiro Kusumi if (((vp->v_flag & VROOT) == 0) || (vp->v_tag == VT_AUTOFS)) { 54e2950f41STomohiro Kusumi vput(vp); 55f568b8a3STomohiro Kusumi return (false); 56e2950f41STomohiro Kusumi } 57e2950f41STomohiro Kusumi 58f568b8a3STomohiro Kusumi return (true); 59e2950f41STomohiro Kusumi } 60e2950f41STomohiro Kusumi 61f568b8a3STomohiro Kusumi static bool 62e2950f41STomohiro Kusumi nlookup_fs_root(struct autofs_node *anp, struct vnode **vpp) 63e2950f41STomohiro Kusumi { 64e2950f41STomohiro Kusumi struct nlookupdata nd; 65e2950f41STomohiro Kusumi char *path; 66e2950f41STomohiro Kusumi int error; 67e2950f41STomohiro Kusumi 68e2950f41STomohiro Kusumi path = autofs_path(anp); 69e2950f41STomohiro Kusumi 70e2950f41STomohiro Kusumi error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); 71e2950f41STomohiro Kusumi if (error == 0) { 72e2950f41STomohiro Kusumi error = nlookup(&nd); 73e2950f41STomohiro Kusumi if (error == 0) { 74662e8088STomohiro Kusumi struct vnode *vp = nd.nl_nch.ncp->nc_vp; 75f568b8a3STomohiro Kusumi if (test_fs_root(vp) == true) 76e2950f41STomohiro Kusumi *vpp = vp; 77f568b8a3STomohiro Kusumi else 78f568b8a3STomohiro Kusumi error = 1; 79e2950f41STomohiro Kusumi } 80e2950f41STomohiro Kusumi } 81e2950f41STomohiro Kusumi nlookup_done(&nd); 82e2950f41STomohiro Kusumi kfree(path, M_AUTOFS); 83e2950f41STomohiro Kusumi 84f568b8a3STomohiro Kusumi return (error ? false : true); 85e2950f41STomohiro Kusumi } 86e2950f41STomohiro Kusumi 87e2950f41STomohiro Kusumi static int 88e2950f41STomohiro Kusumi autofs_access(struct vop_access_args *ap) 89e2950f41STomohiro Kusumi { 90e2950f41STomohiro Kusumi /* 91e2950f41STomohiro Kusumi * Nothing to do here; the only kind of access control 92e2950f41STomohiro Kusumi * needed is in autofs_mkdir(). 93e2950f41STomohiro Kusumi */ 94e2950f41STomohiro Kusumi return (0); 95e2950f41STomohiro Kusumi } 96e2950f41STomohiro Kusumi 97e2950f41STomohiro Kusumi static int 98e2950f41STomohiro Kusumi autofs_getattr(struct vop_getattr_args *ap) 99e2950f41STomohiro Kusumi { 100e2950f41STomohiro Kusumi struct vnode *vp = ap->a_vp; 101e2950f41STomohiro Kusumi struct vattr *vap = ap->a_vap; 102e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(vp); 103e2950f41STomohiro Kusumi 104e2950f41STomohiro Kusumi KASSERT(vp->v_type == VDIR, ("!VDIR")); 105e2950f41STomohiro Kusumi 106e2950f41STomohiro Kusumi /* 107e2950f41STomohiro Kusumi * The reason we must do this is that some tree-walking software, 108e2950f41STomohiro Kusumi * namely fts(3), assumes that stat(".") results will not change 109e2950f41STomohiro Kusumi * between chdir("subdir") and chdir(".."), and fails with ENOENT 110e2950f41STomohiro Kusumi * otherwise. 111caaec4e3STomohiro Kusumi * 112e2950f41STomohiro Kusumi * XXX: Not supported on DragonFly. 113caaec4e3STomohiro Kusumi * With the current trigger mechanism on DragonFly, the process 114caaec4e3STomohiro Kusumi * will hang while in nlookup() in nlookup_fs_root(). 115e2950f41STomohiro Kusumi */ 116888acc39STomohiro Kusumi #if 0 117888acc39STomohiro Kusumi if (autofs_mount_on_stat && ...) { 118caaec4e3STomohiro Kusumi } 119888acc39STomohiro Kusumi #endif 120e2950f41STomohiro Kusumi vap->va_type = VDIR; 121e2950f41STomohiro Kusumi vap->va_nlink = 3; /* XXX: FreeBSD had it like this */ 1222f752b64STomohiro Kusumi vap->va_mode = 0755; 123e2950f41STomohiro Kusumi vap->va_uid = 0; 124e2950f41STomohiro Kusumi vap->va_gid = 0; 125e2950f41STomohiro Kusumi vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 126e2950f41STomohiro Kusumi vap->va_fileid = anp->an_ino; 127e2950f41STomohiro Kusumi vap->va_size = S_BLKSIZE; 128e2950f41STomohiro Kusumi vap->va_blocksize = S_BLKSIZE; 129e2950f41STomohiro Kusumi vap->va_atime = anp->an_ctime; 1302f752b64STomohiro Kusumi vap->va_mtime = anp->an_ctime; 131e2950f41STomohiro Kusumi vap->va_ctime = anp->an_ctime; 132e2950f41STomohiro Kusumi vap->va_gen = 0; 133e2950f41STomohiro Kusumi vap->va_flags = 0; 134e2950f41STomohiro Kusumi vap->va_rmajor = 0; 135e2950f41STomohiro Kusumi vap->va_rminor = 0; 136e2950f41STomohiro Kusumi vap->va_bytes = S_BLKSIZE; 137e2950f41STomohiro Kusumi vap->va_filerev = 0; 1382f752b64STomohiro Kusumi vap->va_vaflags = 0; 139e2950f41STomohiro Kusumi vap->va_spare = 0; 140e2950f41STomohiro Kusumi 141e2950f41STomohiro Kusumi return (0); 142e2950f41STomohiro Kusumi } 143e2950f41STomohiro Kusumi 144e2950f41STomohiro Kusumi static int 145e2950f41STomohiro Kusumi autofs_trigger_vn(struct vnode *vp, const char *path, int pathlen, 146e2950f41STomohiro Kusumi struct vnode **newvp) 147e2950f41STomohiro Kusumi { 148e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(vp); 149e2950f41STomohiro Kusumi struct vnode *nvp = NULL; 150e2950f41STomohiro Kusumi int error; 151e2950f41STomohiro Kusumi 152e2950f41STomohiro Kusumi KKASSERT(!vn_islocked(vp)); 153e2950f41STomohiro Kusumi 154f568b8a3STomohiro Kusumi if (test_fs_root(vp) == true) 155e2950f41STomohiro Kusumi goto mounted; 156e2950f41STomohiro Kusumi 157e2950f41STomohiro Kusumi /* 15874565ee0STomohiro Kusumi * Don't remove this lookup. Without this, the process 15974565ee0STomohiro Kusumi * may trigger automountd(8) to mount the filesystem for the 16074565ee0STomohiro Kusumi * second time after successful mount, and the second attempt 16174565ee0STomohiro Kusumi * will fail. 162e2950f41STomohiro Kusumi */ 163f568b8a3STomohiro Kusumi if (nlookup_fs_root(anp, &nvp) == true) 164e2950f41STomohiro Kusumi goto mounted; 165e2950f41STomohiro Kusumi 1662137724aSTomohiro Kusumi mtx_lock_ex_quick(&autofs_softc->sc_lock); 167e2950f41STomohiro Kusumi error = autofs_trigger(anp, path, pathlen); 1682137724aSTomohiro Kusumi mtx_unlock_ex(&autofs_softc->sc_lock); 169e2950f41STomohiro Kusumi 170e2950f41STomohiro Kusumi if (error) 171e2950f41STomohiro Kusumi return (error); 172e2950f41STomohiro Kusumi 173f568b8a3STomohiro Kusumi if (nlookup_fs_root(anp, &nvp) == false) 174e2950f41STomohiro Kusumi return (0); 175e2950f41STomohiro Kusumi 176e2950f41STomohiro Kusumi /* 177e2950f41STomohiro Kusumi * If the operation that succeeded was mount, then mark 178e2950f41STomohiro Kusumi * the node as non-cached. Otherwise, if someone unmounts 179e2950f41STomohiro Kusumi * the filesystem before the cache times out, we will fail 180e2950f41STomohiro Kusumi * to trigger. 181e2950f41STomohiro Kusumi */ 182e2950f41STomohiro Kusumi autofs_node_uncache(anp); 183e2950f41STomohiro Kusumi mounted: 184e2950f41STomohiro Kusumi *newvp = nvp; 185e2950f41STomohiro Kusumi KKASSERT(vn_islocked(*newvp)); 186e2950f41STomohiro Kusumi 187e2950f41STomohiro Kusumi return (0); 188e2950f41STomohiro Kusumi } 189e2950f41STomohiro Kusumi 190e2950f41STomohiro Kusumi static int 191e2950f41STomohiro Kusumi autofs_nresolve(struct vop_nresolve_args *ap) 192e2950f41STomohiro Kusumi { 193e2950f41STomohiro Kusumi struct vnode *vp = NULL; 194e2950f41STomohiro Kusumi struct vnode *dvp = ap->a_dvp; 195e2950f41STomohiro Kusumi struct nchandle *nch = ap->a_nch; 196e2950f41STomohiro Kusumi struct namecache *ncp = nch->ncp; 197e2950f41STomohiro Kusumi struct autofs_mount *amp = VFSTOAUTOFS(dvp->v_mount); 198e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(dvp); 199e2950f41STomohiro Kusumi struct autofs_node *child = NULL; 200e2950f41STomohiro Kusumi int error; 201e2950f41STomohiro Kusumi 202e2950f41STomohiro Kusumi if (autofs_cached(anp, ncp->nc_name, ncp->nc_nlen) == false && 203e2950f41STomohiro Kusumi autofs_ignore_thread() == false) { 204e2950f41STomohiro Kusumi struct vnode *newvp = NULL; 205e2950f41STomohiro Kusumi 206e2950f41STomohiro Kusumi cache_hold(nch); 207e2950f41STomohiro Kusumi cache_unlock(nch); 20874565ee0STomohiro Kusumi error = autofs_trigger_vn(dvp, ncp->nc_name, ncp->nc_nlen, 20974565ee0STomohiro Kusumi &newvp); 210e2950f41STomohiro Kusumi cache_lock(nch); 211e2950f41STomohiro Kusumi cache_drop(nch); 212e2950f41STomohiro Kusumi if (error) 213e2950f41STomohiro Kusumi return (error); 214e2950f41STomohiro Kusumi if (newvp != NULL) { 215e2950f41STomohiro Kusumi KKASSERT(newvp->v_tag != VT_AUTOFS); 216e2950f41STomohiro Kusumi vput(newvp); 217e2950f41STomohiro Kusumi return (ESTALE); 218e2950f41STomohiro Kusumi } 219e2950f41STomohiro Kusumi return (0); 220e2950f41STomohiro Kusumi } 221e2950f41STomohiro Kusumi 222bc6139d4STomohiro Kusumi mtx_lock_sh_quick(&->am_lock); 223e2950f41STomohiro Kusumi error = autofs_node_find(anp, ncp->nc_name, ncp->nc_nlen, &child); 224bc6139d4STomohiro Kusumi mtx_unlock_sh(&->am_lock); 225e2950f41STomohiro Kusumi 226e2950f41STomohiro Kusumi if (error) { 227e2950f41STomohiro Kusumi cache_setvp(nch, NULL); 228e2950f41STomohiro Kusumi return (0); 229e2950f41STomohiro Kusumi } 230e2950f41STomohiro Kusumi 231e2950f41STomohiro Kusumi error = autofs_node_vn(child, dvp->v_mount, LK_EXCLUSIVE, &vp); 232e2950f41STomohiro Kusumi if (error == 0) { 233e2950f41STomohiro Kusumi KKASSERT(vn_islocked(vp)); 234e2950f41STomohiro Kusumi vn_unlock(vp); 235e2950f41STomohiro Kusumi cache_setvp(nch, vp); 236e2950f41STomohiro Kusumi vrele(vp); 237e2950f41STomohiro Kusumi return (0); 238e2950f41STomohiro Kusumi } 239e2950f41STomohiro Kusumi 240e2950f41STomohiro Kusumi return (error); 241e2950f41STomohiro Kusumi } 242e2950f41STomohiro Kusumi 243e2950f41STomohiro Kusumi static int 244e2950f41STomohiro Kusumi autofs_nmkdir(struct vop_nmkdir_args *ap) 245e2950f41STomohiro Kusumi { 246e2950f41STomohiro Kusumi struct vnode *vp = NULL; 247e2950f41STomohiro Kusumi struct vnode *dvp = ap->a_dvp; 248e2950f41STomohiro Kusumi struct nchandle *nch = ap->a_nch; 249e2950f41STomohiro Kusumi struct namecache *ncp = nch->ncp; 250e2950f41STomohiro Kusumi struct autofs_mount *amp = VFSTOAUTOFS(dvp->v_mount); 251e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(dvp); 252e2950f41STomohiro Kusumi struct autofs_node *child = NULL; 253e2950f41STomohiro Kusumi int error; 254e2950f41STomohiro Kusumi 255e2950f41STomohiro Kusumi /* 256e2950f41STomohiro Kusumi * Do not allow mkdir() if the calling thread is not 257e2950f41STomohiro Kusumi * automountd(8) descendant. 258e2950f41STomohiro Kusumi */ 259e2950f41STomohiro Kusumi if (autofs_ignore_thread() == false) 260e2950f41STomohiro Kusumi return (EPERM); 261e2950f41STomohiro Kusumi 262bc6139d4STomohiro Kusumi mtx_lock_ex_quick(&->am_lock); 263e2950f41STomohiro Kusumi error = autofs_node_new(anp, amp, ncp->nc_name, ncp->nc_nlen, &child); 264bc6139d4STomohiro Kusumi mtx_unlock_ex(&->am_lock); 265e2950f41STomohiro Kusumi KKASSERT(error == 0); 266e2950f41STomohiro Kusumi 267e2950f41STomohiro Kusumi error = autofs_node_vn(child, dvp->v_mount, LK_EXCLUSIVE, &vp); 268e2950f41STomohiro Kusumi if (error == 0) { 269e2950f41STomohiro Kusumi KKASSERT(vn_islocked(vp)); 270e2950f41STomohiro Kusumi cache_setunresolved(nch); 271e2950f41STomohiro Kusumi cache_setvp(nch, vp); 272e2950f41STomohiro Kusumi *(ap->a_vpp) = vp; 273e2950f41STomohiro Kusumi return (0); 274e2950f41STomohiro Kusumi } 275e2950f41STomohiro Kusumi 276e2950f41STomohiro Kusumi return (error); 277e2950f41STomohiro Kusumi } 278e2950f41STomohiro Kusumi 27974565ee0STomohiro Kusumi static __inline size_t 28074565ee0STomohiro Kusumi autofs_dirent_reclen(const char *name) 28174565ee0STomohiro Kusumi { 28274565ee0STomohiro Kusumi return (_DIRENT_RECLEN(strlen(name))); 28374565ee0STomohiro Kusumi } 28474565ee0STomohiro Kusumi 285e2950f41STomohiro Kusumi static int 286*05b68237STomohiro Kusumi autofs_readdir_one(struct uio *uio, const char *name, ino_t ino) 287e2950f41STomohiro Kusumi { 288e2950f41STomohiro Kusumi int error = 0; 289e2950f41STomohiro Kusumi 290e2950f41STomohiro Kusumi if (vop_write_dirent(&error, uio, ino, DT_DIR, strlen(name), name)) 291e2950f41STomohiro Kusumi return (EINVAL); 292e2950f41STomohiro Kusumi 293e2950f41STomohiro Kusumi return (error); 294e2950f41STomohiro Kusumi } 295e2950f41STomohiro Kusumi 296e2950f41STomohiro Kusumi static int 297e2950f41STomohiro Kusumi autofs_readdir(struct vop_readdir_args *ap) 298e2950f41STomohiro Kusumi { 299e2950f41STomohiro Kusumi struct vnode *vp = ap->a_vp; 300e2950f41STomohiro Kusumi struct autofs_mount *amp = VFSTOAUTOFS(vp->v_mount); 301e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(vp); 302e2950f41STomohiro Kusumi struct autofs_node *child; 303e2950f41STomohiro Kusumi struct uio *uio = ap->a_uio; 304e2950f41STomohiro Kusumi ssize_t initial_resid = ap->a_uio->uio_resid; 305*05b68237STomohiro Kusumi size_t reclens = 0; 306e2950f41STomohiro Kusumi int error; 307e2950f41STomohiro Kusumi 308e2950f41STomohiro Kusumi KASSERT(vp->v_type == VDIR, ("!VDIR")); 309e2950f41STomohiro Kusumi 310e2950f41STomohiro Kusumi if (autofs_cached(anp, NULL, 0) == false && 311e2950f41STomohiro Kusumi autofs_ignore_thread() == false) { 312e2950f41STomohiro Kusumi struct vnode *newvp = NULL; 313caaec4e3STomohiro Kusumi error = autofs_trigger_vn(vp, "", 0, &newvp); 314e2950f41STomohiro Kusumi if (error) 315e2950f41STomohiro Kusumi return (error); 316e2950f41STomohiro Kusumi if (newvp != NULL) { 317e2950f41STomohiro Kusumi KKASSERT(newvp->v_tag != VT_AUTOFS); 318e2950f41STomohiro Kusumi vn_unlock(newvp); 319e2950f41STomohiro Kusumi error = VOP_READDIR(newvp, ap->a_uio, ap->a_cred, 320e2950f41STomohiro Kusumi ap->a_eofflag, ap->a_ncookies, ap->a_cookies); 321e2950f41STomohiro Kusumi vrele(newvp); 322e2950f41STomohiro Kusumi return (error); 323e2950f41STomohiro Kusumi } 324e2950f41STomohiro Kusumi } 325e2950f41STomohiro Kusumi 326e2950f41STomohiro Kusumi if (uio->uio_offset < 0) 327e2950f41STomohiro Kusumi return (EINVAL); 328e2950f41STomohiro Kusumi 329e2950f41STomohiro Kusumi if (ap->a_eofflag != NULL) 330e2950f41STomohiro Kusumi *ap->a_eofflag = FALSE; 331e2950f41STomohiro Kusumi 332e2950f41STomohiro Kusumi /* 333e2950f41STomohiro Kusumi * Write out the directory entry for ".". 334e2950f41STomohiro Kusumi */ 335e2950f41STomohiro Kusumi if (uio->uio_offset == 0) { 336*05b68237STomohiro Kusumi error = autofs_readdir_one(uio, ".", anp->an_ino); 337e2950f41STomohiro Kusumi if (error) 338e2950f41STomohiro Kusumi goto out; 339e2950f41STomohiro Kusumi } 340e2950f41STomohiro Kusumi reclens = autofs_dirent_reclen("."); 341e2950f41STomohiro Kusumi 342e2950f41STomohiro Kusumi /* 343e2950f41STomohiro Kusumi * Write out the directory entry for "..". 344e2950f41STomohiro Kusumi */ 345e2950f41STomohiro Kusumi if (uio->uio_offset <= reclens) { 346e2950f41STomohiro Kusumi if (uio->uio_offset != reclens) 347e2950f41STomohiro Kusumi return (EINVAL); 348e2950f41STomohiro Kusumi error = autofs_readdir_one(uio, "..", 349*05b68237STomohiro Kusumi (anp->an_parent ? anp->an_parent->an_ino : anp->an_ino)); 350e2950f41STomohiro Kusumi if (error) 351e2950f41STomohiro Kusumi goto out; 352e2950f41STomohiro Kusumi } 353e2950f41STomohiro Kusumi reclens += autofs_dirent_reclen(".."); 354e2950f41STomohiro Kusumi 355e2950f41STomohiro Kusumi /* 356e2950f41STomohiro Kusumi * Write out the directory entries for subdirectories. 357e2950f41STomohiro Kusumi */ 358bc6139d4STomohiro Kusumi mtx_lock_sh_quick(&->am_lock); 359e2950f41STomohiro Kusumi RB_FOREACH(child, autofs_node_tree, &anp->an_children) { 360e2950f41STomohiro Kusumi /* 361e2950f41STomohiro Kusumi * Check the offset to skip entries returned by previous 362e2950f41STomohiro Kusumi * calls to getdents(). 363e2950f41STomohiro Kusumi */ 364e2950f41STomohiro Kusumi if (uio->uio_offset > reclens) { 365e2950f41STomohiro Kusumi reclens += autofs_dirent_reclen(child->an_name); 366e2950f41STomohiro Kusumi continue; 367e2950f41STomohiro Kusumi } 368e2950f41STomohiro Kusumi 369e2950f41STomohiro Kusumi /* 370e2950f41STomohiro Kusumi * Prevent seeking into the middle of dirent. 371e2950f41STomohiro Kusumi */ 372e2950f41STomohiro Kusumi if (uio->uio_offset != reclens) { 373bc6139d4STomohiro Kusumi mtx_unlock_sh(&->am_lock); 374e2950f41STomohiro Kusumi return (EINVAL); 375e2950f41STomohiro Kusumi } 376e2950f41STomohiro Kusumi 377*05b68237STomohiro Kusumi error = autofs_readdir_one(uio, child->an_name, child->an_ino); 378*05b68237STomohiro Kusumi reclens += autofs_dirent_reclen(child->an_name); 379e2950f41STomohiro Kusumi if (error) { 380bc6139d4STomohiro Kusumi mtx_unlock_sh(&->am_lock); 381e2950f41STomohiro Kusumi goto out; 382e2950f41STomohiro Kusumi } 383e2950f41STomohiro Kusumi } 384bc6139d4STomohiro Kusumi mtx_unlock_sh(&->am_lock); 385e2950f41STomohiro Kusumi 386e2950f41STomohiro Kusumi if (ap->a_eofflag != NULL) 387e2950f41STomohiro Kusumi *ap->a_eofflag = TRUE; 388e2950f41STomohiro Kusumi 389e2950f41STomohiro Kusumi return (0); 390e2950f41STomohiro Kusumi out: 391e2950f41STomohiro Kusumi /* 392e2950f41STomohiro Kusumi * Return error if the initial buffer was too small to do anything. 393e2950f41STomohiro Kusumi */ 394e2950f41STomohiro Kusumi if (uio->uio_resid == initial_resid) 395e2950f41STomohiro Kusumi return (error); 396e2950f41STomohiro Kusumi 397e2950f41STomohiro Kusumi /* 398e2950f41STomohiro Kusumi * Don't return an error if we managed to copy out some entries. 399e2950f41STomohiro Kusumi */ 400*05b68237STomohiro Kusumi if (uio->uio_resid < initial_resid) 401e2950f41STomohiro Kusumi return (0); 402e2950f41STomohiro Kusumi 403e2950f41STomohiro Kusumi return (error); 404e2950f41STomohiro Kusumi } 405e2950f41STomohiro Kusumi 406e2950f41STomohiro Kusumi static int 407e2950f41STomohiro Kusumi autofs_reclaim(struct vop_reclaim_args *ap) 408e2950f41STomohiro Kusumi { 409e2950f41STomohiro Kusumi struct vnode *vp = ap->a_vp; 410e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(vp); 411e2950f41STomohiro Kusumi 412e2950f41STomohiro Kusumi /* 413e2950f41STomohiro Kusumi * We do not free autofs_node here; instead we are 414e2950f41STomohiro Kusumi * destroying them in autofs_node_delete(). 415e2950f41STomohiro Kusumi */ 416bfccbb76STomohiro Kusumi mtx_lock_ex_quick(&anp->an_vnode_lock); 417e2950f41STomohiro Kusumi anp->an_vnode = NULL; 418e2950f41STomohiro Kusumi vp->v_data = NULL; 419bfccbb76STomohiro Kusumi mtx_unlock_ex(&anp->an_vnode_lock); 420e2950f41STomohiro Kusumi 421e2950f41STomohiro Kusumi return (0); 422e2950f41STomohiro Kusumi } 423e2950f41STomohiro Kusumi 424e2950f41STomohiro Kusumi static int 425e2950f41STomohiro Kusumi autofs_mountctl(struct vop_mountctl_args *ap) 426e2950f41STomohiro Kusumi { 427e2950f41STomohiro Kusumi struct mount *mp; 428662e8088STomohiro Kusumi int res = 0; 429e2950f41STomohiro Kusumi 430e2950f41STomohiro Kusumi mp = ap->a_head.a_ops->head.vv_mount; 431e2950f41STomohiro Kusumi lwkt_gettoken(&mp->mnt_token); 432e2950f41STomohiro Kusumi 433e2950f41STomohiro Kusumi switch (ap->a_op) { 4345e4f9d10STomohiro Kusumi //case ...: 4355e4f9d10STomohiro Kusumi // break; 436e2950f41STomohiro Kusumi default: 437e2950f41STomohiro Kusumi res = vop_stdmountctl(ap); 438e2950f41STomohiro Kusumi break; 439e2950f41STomohiro Kusumi } 440e2950f41STomohiro Kusumi 441e2950f41STomohiro Kusumi lwkt_reltoken(&mp->mnt_token); 442e2950f41STomohiro Kusumi return (res); 443e2950f41STomohiro Kusumi } 444e2950f41STomohiro Kusumi 445e2950f41STomohiro Kusumi static int 446e2950f41STomohiro Kusumi autofs_print(struct vop_print_args *ap) 447e2950f41STomohiro Kusumi { 448e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(ap->a_vp); 449e2950f41STomohiro Kusumi 4507d470fedSTomohiro Kusumi kprintf("tag VT_AUTOFS, node %p, ino %jd, name %s, cached %d, retries %d, wildcards %d\n", 451b112b669STomohiro Kusumi anp, (intmax_t)anp->an_ino, anp->an_name, anp->an_cached, 452b112b669STomohiro Kusumi anp->an_retries, anp->an_wildcards); 453e2950f41STomohiro Kusumi 454e2950f41STomohiro Kusumi return (0); 455e2950f41STomohiro Kusumi } 456e2950f41STomohiro Kusumi 457e2950f41STomohiro Kusumi struct vop_ops autofs_vnode_vops = { 458e2950f41STomohiro Kusumi .vop_default = vop_defaultop, 459e2950f41STomohiro Kusumi .vop_getpages = vop_stdgetpages, 460e2950f41STomohiro Kusumi .vop_putpages = vop_stdputpages, 461e2950f41STomohiro Kusumi .vop_access = autofs_access, 462e2950f41STomohiro Kusumi .vop_getattr = autofs_getattr, 463e2950f41STomohiro Kusumi .vop_nresolve = autofs_nresolve, 464e2950f41STomohiro Kusumi .vop_nmkdir = autofs_nmkdir, 465e2950f41STomohiro Kusumi .vop_readdir = autofs_readdir, 466e2950f41STomohiro Kusumi .vop_reclaim = autofs_reclaim, 467e2950f41STomohiro Kusumi .vop_mountctl = autofs_mountctl, 468e2950f41STomohiro Kusumi .vop_print = autofs_print, 469e2950f41STomohiro Kusumi }; 470e2950f41STomohiro Kusumi 471e2950f41STomohiro Kusumi int 472e2950f41STomohiro Kusumi autofs_node_new(struct autofs_node *parent, struct autofs_mount *amp, 473e2950f41STomohiro Kusumi const char *name, int namelen, struct autofs_node **anpp) 474e2950f41STomohiro Kusumi { 475e2950f41STomohiro Kusumi struct autofs_node *anp; 476e2950f41STomohiro Kusumi 4776be174c1STomohiro Kusumi KKASSERT(mtx_islocked_ex(&->am_lock)); 478e2950f41STomohiro Kusumi 479e2950f41STomohiro Kusumi if (parent != NULL) { 4806be174c1STomohiro Kusumi KKASSERT(mtx_islocked_ex(&parent->an_mount->am_lock)); 481e2950f41STomohiro Kusumi KASSERT(autofs_node_find(parent, name, namelen, NULL) == ENOENT, 482e2950f41STomohiro Kusumi ("node \"%s\" already exists", name)); 483e2950f41STomohiro Kusumi } 484e2950f41STomohiro Kusumi 485a5dfdd2bSTomohiro Kusumi /* 486a5dfdd2bSTomohiro Kusumi * All struct fields must be initialized. 487a5dfdd2bSTomohiro Kusumi */ 488e2950f41STomohiro Kusumi anp = objcache_get(autofs_node_objcache, M_WAITOK); 489e2950f41STomohiro Kusumi if (namelen >= 0) 490e2950f41STomohiro Kusumi anp->an_name = kstrndup(name, namelen, M_AUTOFS); 491e2950f41STomohiro Kusumi else 492e2950f41STomohiro Kusumi anp->an_name = kstrdup(name, M_AUTOFS); 493e2950f41STomohiro Kusumi anp->an_ino = amp->am_last_ino++; 494e2950f41STomohiro Kusumi callout_init(&anp->an_callout); 495bfccbb76STomohiro Kusumi mtx_init(&anp->an_vnode_lock, "autofsvnlk"); 496e2950f41STomohiro Kusumi getnanotime(&anp->an_ctime); 497e2950f41STomohiro Kusumi anp->an_parent = parent; 498e2950f41STomohiro Kusumi anp->an_mount = amp; 499e2950f41STomohiro Kusumi anp->an_vnode = NULL; 500e2950f41STomohiro Kusumi anp->an_cached = false; 501e2950f41STomohiro Kusumi anp->an_wildcards = false; 502e2950f41STomohiro Kusumi anp->an_retries = 0; 503e2950f41STomohiro Kusumi if (parent != NULL) 504e2950f41STomohiro Kusumi RB_INSERT(autofs_node_tree, &parent->an_children, anp); 505e2950f41STomohiro Kusumi RB_INIT(&anp->an_children); 506e2950f41STomohiro Kusumi 507e2950f41STomohiro Kusumi *anpp = anp; 508e2950f41STomohiro Kusumi 509e2950f41STomohiro Kusumi return (0); 510e2950f41STomohiro Kusumi } 511e2950f41STomohiro Kusumi 512e2950f41STomohiro Kusumi int 51374565ee0STomohiro Kusumi autofs_node_find(struct autofs_node *parent, const char *name, int namelen, 51474565ee0STomohiro Kusumi struct autofs_node **anpp) 515e2950f41STomohiro Kusumi { 516e2950f41STomohiro Kusumi struct autofs_node *anp, find; 517e2950f41STomohiro Kusumi int error; 518e2950f41STomohiro Kusumi 5196be174c1STomohiro Kusumi KKASSERT(mtx_islocked(&parent->an_mount->am_lock)); 520e2950f41STomohiro Kusumi 521e2950f41STomohiro Kusumi if (namelen >= 0) 522e2950f41STomohiro Kusumi find.an_name = kstrndup(name, namelen, M_AUTOFS); 523e2950f41STomohiro Kusumi else 524e2950f41STomohiro Kusumi find.an_name = kstrdup(name, M_AUTOFS); 525e2950f41STomohiro Kusumi 526e2950f41STomohiro Kusumi anp = RB_FIND(autofs_node_tree, &parent->an_children, &find); 527e2950f41STomohiro Kusumi if (anp != NULL) { 528e2950f41STomohiro Kusumi error = 0; 529e2950f41STomohiro Kusumi if (anpp != NULL) 530e2950f41STomohiro Kusumi *anpp = anp; 531e2950f41STomohiro Kusumi } else { 532e2950f41STomohiro Kusumi error = ENOENT; 533e2950f41STomohiro Kusumi } 534e2950f41STomohiro Kusumi 535e2950f41STomohiro Kusumi kfree(find.an_name, M_AUTOFS); 536e2950f41STomohiro Kusumi 537e2950f41STomohiro Kusumi return (error); 538e2950f41STomohiro Kusumi } 539e2950f41STomohiro Kusumi 540e2950f41STomohiro Kusumi void 541e2950f41STomohiro Kusumi autofs_node_delete(struct autofs_node *anp) 542e2950f41STomohiro Kusumi { 5436be174c1STomohiro Kusumi KKASSERT(mtx_islocked_ex(&anp->an_mount->am_lock)); 544e2950f41STomohiro Kusumi KASSERT(RB_EMPTY(&anp->an_children), ("have children")); 545e2950f41STomohiro Kusumi 546e2950f41STomohiro Kusumi callout_drain(&anp->an_callout); 547e2950f41STomohiro Kusumi 548e2950f41STomohiro Kusumi if (anp->an_parent != NULL) 549e2950f41STomohiro Kusumi RB_REMOVE(autofs_node_tree, &anp->an_parent->an_children, anp); 550e2950f41STomohiro Kusumi 551bfccbb76STomohiro Kusumi mtx_uninit(&anp->an_vnode_lock); 552e2950f41STomohiro Kusumi kfree(anp->an_name, M_AUTOFS); 553e2950f41STomohiro Kusumi objcache_put(autofs_node_objcache, anp); 554e2950f41STomohiro Kusumi } 555e2950f41STomohiro Kusumi 556e2950f41STomohiro Kusumi int 557e2950f41STomohiro Kusumi autofs_node_vn(struct autofs_node *anp, struct mount *mp, int flags, 558e2950f41STomohiro Kusumi struct vnode **vpp) 559e2950f41STomohiro Kusumi { 560e2950f41STomohiro Kusumi struct vnode *vp = NULL; 561e2950f41STomohiro Kusumi int error; 562e2950f41STomohiro Kusumi retry: 5636be174c1STomohiro Kusumi KKASSERT(mtx_notlocked(&anp->an_mount->am_lock)); 564bfccbb76STomohiro Kusumi mtx_lock_ex_quick(&anp->an_vnode_lock); 565e2950f41STomohiro Kusumi 566e2950f41STomohiro Kusumi vp = anp->an_vnode; 567e2950f41STomohiro Kusumi if (vp != NULL) { 568e2950f41STomohiro Kusumi vhold(vp); 569bfccbb76STomohiro Kusumi mtx_unlock_ex(&anp->an_vnode_lock); 570e2950f41STomohiro Kusumi 571e2950f41STomohiro Kusumi error = vget(vp, flags | LK_RETRY); 572e2950f41STomohiro Kusumi if (error) { 573e2950f41STomohiro Kusumi AUTOFS_WARN("vget failed with error %d", error); 574e2950f41STomohiro Kusumi vdrop(vp); 575e2950f41STomohiro Kusumi goto retry; 576e2950f41STomohiro Kusumi } 577e2950f41STomohiro Kusumi vdrop(vp); 578e2950f41STomohiro Kusumi *vpp = vp; 579e2950f41STomohiro Kusumi return (0); 580e2950f41STomohiro Kusumi } 581e2950f41STomohiro Kusumi 582bfccbb76STomohiro Kusumi mtx_unlock_ex(&anp->an_vnode_lock); 583e2950f41STomohiro Kusumi 584e2950f41STomohiro Kusumi error = getnewvnode(VT_AUTOFS, mp, &vp, VLKTIMEOUT, LK_CANRECURSE); 585e2950f41STomohiro Kusumi if (error) 586e2950f41STomohiro Kusumi return (error); 587e2950f41STomohiro Kusumi vp->v_type = VDIR; 588e2950f41STomohiro Kusumi vp->v_data = anp; 589e2950f41STomohiro Kusumi 590e2950f41STomohiro Kusumi KASSERT(anp->an_vnode == NULL, ("lost race")); 591e2950f41STomohiro Kusumi anp->an_vnode = vp; 592e2950f41STomohiro Kusumi *vpp = vp; 593e2950f41STomohiro Kusumi 594e2950f41STomohiro Kusumi return (0); 595e2950f41STomohiro Kusumi } 596