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 43e2950f41STomohiro Kusumi static int 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); 50e2950f41STomohiro Kusumi return (1); 51e2950f41STomohiro Kusumi } 52e2950f41STomohiro Kusumi 53e2950f41STomohiro Kusumi if (((vp->v_flag & VROOT) == 0) || (vp->v_tag == VT_AUTOFS)) { 54e2950f41STomohiro Kusumi vput(vp); 55e2950f41STomohiro Kusumi return (1); 56e2950f41STomohiro Kusumi } 57e2950f41STomohiro Kusumi 58e2950f41STomohiro Kusumi return (0); 59e2950f41STomohiro Kusumi } 60e2950f41STomohiro Kusumi 61e2950f41STomohiro Kusumi static int 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; 75e2950f41STomohiro Kusumi error = test_fs_root(vp); 76e2950f41STomohiro Kusumi if (error == 0) 77e2950f41STomohiro Kusumi *vpp = vp; 78e2950f41STomohiro Kusumi } 79e2950f41STomohiro Kusumi } 80e2950f41STomohiro Kusumi nlookup_done(&nd); 81e2950f41STomohiro Kusumi kfree(path, M_AUTOFS); 82e2950f41STomohiro Kusumi 83e2950f41STomohiro Kusumi return (error); 84e2950f41STomohiro Kusumi } 85e2950f41STomohiro Kusumi 86e2950f41STomohiro Kusumi static int 87e2950f41STomohiro Kusumi autofs_access(struct vop_access_args *ap) 88e2950f41STomohiro Kusumi { 89e2950f41STomohiro Kusumi /* 90e2950f41STomohiro Kusumi * Nothing to do here; the only kind of access control 91e2950f41STomohiro Kusumi * needed is in autofs_mkdir(). 92e2950f41STomohiro Kusumi */ 93e2950f41STomohiro Kusumi return (0); 94e2950f41STomohiro Kusumi } 95e2950f41STomohiro Kusumi 96e2950f41STomohiro Kusumi static int 97e2950f41STomohiro Kusumi autofs_getattr(struct vop_getattr_args *ap) 98e2950f41STomohiro Kusumi { 99e2950f41STomohiro Kusumi struct vnode *vp = ap->a_vp; 100e2950f41STomohiro Kusumi struct vattr *vap = ap->a_vap; 101e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(vp); 102e2950f41STomohiro Kusumi 103e2950f41STomohiro Kusumi KASSERT(vp->v_type == VDIR, ("!VDIR")); 104e2950f41STomohiro Kusumi 105e2950f41STomohiro Kusumi /* 106e2950f41STomohiro Kusumi * The reason we must do this is that some tree-walking software, 107e2950f41STomohiro Kusumi * namely fts(3), assumes that stat(".") results will not change 108e2950f41STomohiro Kusumi * between chdir("subdir") and chdir(".."), and fails with ENOENT 109e2950f41STomohiro Kusumi * otherwise. 110caaec4e3STomohiro Kusumi * 111e2950f41STomohiro Kusumi * XXX: Not supported on DragonFly. 112caaec4e3STomohiro Kusumi * With the current trigger mechanism on DragonFly, the process 113caaec4e3STomohiro Kusumi * will hang while in nlookup() in nlookup_fs_root(). 114e2950f41STomohiro Kusumi */ 115888acc39STomohiro Kusumi #if 0 116888acc39STomohiro Kusumi if (autofs_mount_on_stat && ...) { 117caaec4e3STomohiro Kusumi } 118888acc39STomohiro Kusumi #endif 119e2950f41STomohiro Kusumi vap->va_type = VDIR; 120e2950f41STomohiro Kusumi vap->va_nlink = 3; /* XXX: FreeBSD had it like this */ 121*2f752b64STomohiro Kusumi vap->va_mode = 0755; 122e2950f41STomohiro Kusumi vap->va_uid = 0; 123e2950f41STomohiro Kusumi vap->va_gid = 0; 124e2950f41STomohiro Kusumi vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 125e2950f41STomohiro Kusumi vap->va_fileid = anp->an_ino; 126e2950f41STomohiro Kusumi vap->va_size = S_BLKSIZE; 127e2950f41STomohiro Kusumi vap->va_blocksize = S_BLKSIZE; 128e2950f41STomohiro Kusumi vap->va_atime = anp->an_ctime; 129*2f752b64STomohiro Kusumi vap->va_mtime = anp->an_ctime; 130e2950f41STomohiro Kusumi vap->va_ctime = anp->an_ctime; 131e2950f41STomohiro Kusumi vap->va_gen = 0; 132e2950f41STomohiro Kusumi vap->va_flags = 0; 133e2950f41STomohiro Kusumi vap->va_rmajor = 0; 134e2950f41STomohiro Kusumi vap->va_rminor = 0; 135e2950f41STomohiro Kusumi vap->va_bytes = S_BLKSIZE; 136e2950f41STomohiro Kusumi vap->va_filerev = 0; 137*2f752b64STomohiro Kusumi vap->va_vaflags = 0; 138e2950f41STomohiro Kusumi vap->va_spare = 0; 139e2950f41STomohiro Kusumi 140e2950f41STomohiro Kusumi return (0); 141e2950f41STomohiro Kusumi } 142e2950f41STomohiro Kusumi 143e2950f41STomohiro Kusumi static int 144e2950f41STomohiro Kusumi autofs_trigger_vn(struct vnode *vp, const char *path, int pathlen, 145e2950f41STomohiro Kusumi struct vnode **newvp) 146e2950f41STomohiro Kusumi { 147e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(vp); 148e2950f41STomohiro Kusumi struct vnode *nvp = NULL; 149e2950f41STomohiro Kusumi int error; 150e2950f41STomohiro Kusumi 151e2950f41STomohiro Kusumi KKASSERT(!vn_islocked(vp)); 152e2950f41STomohiro Kusumi 153e2950f41STomohiro Kusumi if (test_fs_root(vp) == 0) 154e2950f41STomohiro Kusumi goto mounted; 155e2950f41STomohiro Kusumi 156e2950f41STomohiro Kusumi /* 15774565ee0STomohiro Kusumi * Don't remove this lookup. Without this, the process 15874565ee0STomohiro Kusumi * may trigger automountd(8) to mount the filesystem for the 15974565ee0STomohiro Kusumi * second time after successful mount, and the second attempt 16074565ee0STomohiro Kusumi * will fail. 161e2950f41STomohiro Kusumi */ 162e2950f41STomohiro Kusumi if (nlookup_fs_root(anp, &nvp) == 0) 163e2950f41STomohiro Kusumi goto mounted; 164e2950f41STomohiro Kusumi 1652137724aSTomohiro Kusumi mtx_lock_ex_quick(&autofs_softc->sc_lock); 166e2950f41STomohiro Kusumi error = autofs_trigger(anp, path, pathlen); 1672137724aSTomohiro Kusumi mtx_unlock_ex(&autofs_softc->sc_lock); 168e2950f41STomohiro Kusumi 169e2950f41STomohiro Kusumi if (error) 170e2950f41STomohiro Kusumi return (error); 171e2950f41STomohiro Kusumi 172e2950f41STomohiro Kusumi if (nlookup_fs_root(anp, &nvp)) 173e2950f41STomohiro Kusumi return (0); 174e2950f41STomohiro Kusumi 175e2950f41STomohiro Kusumi /* 176e2950f41STomohiro Kusumi * If the operation that succeeded was mount, then mark 177e2950f41STomohiro Kusumi * the node as non-cached. Otherwise, if someone unmounts 178e2950f41STomohiro Kusumi * the filesystem before the cache times out, we will fail 179e2950f41STomohiro Kusumi * to trigger. 180e2950f41STomohiro Kusumi */ 181e2950f41STomohiro Kusumi autofs_node_uncache(anp); 182e2950f41STomohiro Kusumi mounted: 183e2950f41STomohiro Kusumi *newvp = nvp; 184e2950f41STomohiro Kusumi KKASSERT(vn_islocked(*newvp)); 185e2950f41STomohiro Kusumi 186e2950f41STomohiro Kusumi return (0); 187e2950f41STomohiro Kusumi } 188e2950f41STomohiro Kusumi 189e2950f41STomohiro Kusumi static int 190e2950f41STomohiro Kusumi autofs_nresolve(struct vop_nresolve_args *ap) 191e2950f41STomohiro Kusumi { 192e2950f41STomohiro Kusumi struct vnode *vp = NULL; 193e2950f41STomohiro Kusumi struct vnode *dvp = ap->a_dvp; 194e2950f41STomohiro Kusumi struct nchandle *nch = ap->a_nch; 195e2950f41STomohiro Kusumi struct namecache *ncp = nch->ncp; 196e2950f41STomohiro Kusumi struct autofs_mount *amp = VFSTOAUTOFS(dvp->v_mount); 197e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(dvp); 198e2950f41STomohiro Kusumi struct autofs_node *child = NULL; 199e2950f41STomohiro Kusumi int error; 200e2950f41STomohiro Kusumi 201e2950f41STomohiro Kusumi if (autofs_cached(anp, ncp->nc_name, ncp->nc_nlen) == false && 202e2950f41STomohiro Kusumi autofs_ignore_thread() == false) { 203e2950f41STomohiro Kusumi struct vnode *newvp = NULL; 204e2950f41STomohiro Kusumi 205e2950f41STomohiro Kusumi cache_hold(nch); 206e2950f41STomohiro Kusumi cache_unlock(nch); 20774565ee0STomohiro Kusumi error = autofs_trigger_vn(dvp, ncp->nc_name, ncp->nc_nlen, 20874565ee0STomohiro Kusumi &newvp); 209e2950f41STomohiro Kusumi cache_lock(nch); 210e2950f41STomohiro Kusumi cache_drop(nch); 211e2950f41STomohiro Kusumi if (error) 212e2950f41STomohiro Kusumi return (error); 213e2950f41STomohiro Kusumi if (newvp != NULL) { 214e2950f41STomohiro Kusumi KKASSERT(newvp->v_tag != VT_AUTOFS); 215e2950f41STomohiro Kusumi vput(newvp); 216e2950f41STomohiro Kusumi return (ESTALE); 217e2950f41STomohiro Kusumi } 218e2950f41STomohiro Kusumi return (0); 219e2950f41STomohiro Kusumi } 220e2950f41STomohiro Kusumi 221bc6139d4STomohiro Kusumi mtx_lock_sh_quick(&->am_lock); 222e2950f41STomohiro Kusumi error = autofs_node_find(anp, ncp->nc_name, ncp->nc_nlen, &child); 223bc6139d4STomohiro Kusumi mtx_unlock_sh(&->am_lock); 224e2950f41STomohiro Kusumi 225e2950f41STomohiro Kusumi if (error) { 226e2950f41STomohiro Kusumi cache_setvp(nch, NULL); 227e2950f41STomohiro Kusumi return (0); 228e2950f41STomohiro Kusumi } 229e2950f41STomohiro Kusumi 230e2950f41STomohiro Kusumi error = autofs_node_vn(child, dvp->v_mount, LK_EXCLUSIVE, &vp); 231e2950f41STomohiro Kusumi if (error == 0) { 232e2950f41STomohiro Kusumi KKASSERT(vn_islocked(vp)); 233e2950f41STomohiro Kusumi vn_unlock(vp); 234e2950f41STomohiro Kusumi cache_setvp(nch, vp); 235e2950f41STomohiro Kusumi vrele(vp); 236e2950f41STomohiro Kusumi return (0); 237e2950f41STomohiro Kusumi } 238e2950f41STomohiro Kusumi 239e2950f41STomohiro Kusumi return (error); 240e2950f41STomohiro Kusumi } 241e2950f41STomohiro Kusumi 242e2950f41STomohiro Kusumi static int 243e2950f41STomohiro Kusumi autofs_nmkdir(struct vop_nmkdir_args *ap) 244e2950f41STomohiro Kusumi { 245e2950f41STomohiro Kusumi struct vnode *vp = NULL; 246e2950f41STomohiro Kusumi struct vnode *dvp = ap->a_dvp; 247e2950f41STomohiro Kusumi struct nchandle *nch = ap->a_nch; 248e2950f41STomohiro Kusumi struct namecache *ncp = nch->ncp; 249e2950f41STomohiro Kusumi struct autofs_mount *amp = VFSTOAUTOFS(dvp->v_mount); 250e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(dvp); 251e2950f41STomohiro Kusumi struct autofs_node *child = NULL; 252e2950f41STomohiro Kusumi int error; 253e2950f41STomohiro Kusumi 254e2950f41STomohiro Kusumi /* 255e2950f41STomohiro Kusumi * Do not allow mkdir() if the calling thread is not 256e2950f41STomohiro Kusumi * automountd(8) descendant. 257e2950f41STomohiro Kusumi */ 258e2950f41STomohiro Kusumi if (autofs_ignore_thread() == false) 259e2950f41STomohiro Kusumi return (EPERM); 260e2950f41STomohiro Kusumi 261bc6139d4STomohiro Kusumi mtx_lock_ex_quick(&->am_lock); 262e2950f41STomohiro Kusumi error = autofs_node_new(anp, amp, ncp->nc_name, ncp->nc_nlen, &child); 263bc6139d4STomohiro Kusumi mtx_unlock_ex(&->am_lock); 264e2950f41STomohiro Kusumi KKASSERT(error == 0); 265e2950f41STomohiro Kusumi 266e2950f41STomohiro Kusumi error = autofs_node_vn(child, dvp->v_mount, LK_EXCLUSIVE, &vp); 267e2950f41STomohiro Kusumi if (error == 0) { 268e2950f41STomohiro Kusumi KKASSERT(vn_islocked(vp)); 269e2950f41STomohiro Kusumi cache_setunresolved(nch); 270e2950f41STomohiro Kusumi cache_setvp(nch, vp); 271e2950f41STomohiro Kusumi *(ap->a_vpp) = vp; 272e2950f41STomohiro Kusumi return (0); 273e2950f41STomohiro Kusumi } 274e2950f41STomohiro Kusumi 275e2950f41STomohiro Kusumi return (error); 276e2950f41STomohiro Kusumi } 277e2950f41STomohiro Kusumi 27874565ee0STomohiro Kusumi static __inline size_t 27974565ee0STomohiro Kusumi autofs_dirent_reclen(const char *name) 28074565ee0STomohiro Kusumi { 28174565ee0STomohiro Kusumi return (_DIRENT_RECLEN(strlen(name))); 28274565ee0STomohiro Kusumi } 28374565ee0STomohiro Kusumi 284e2950f41STomohiro Kusumi static int 285e2950f41STomohiro Kusumi autofs_readdir_one(struct uio *uio, const char *name, ino_t ino, 286e2950f41STomohiro Kusumi size_t *reclenp) 287e2950f41STomohiro Kusumi { 288e2950f41STomohiro Kusumi int error = 0; 289e2950f41STomohiro Kusumi 290e2950f41STomohiro Kusumi if (reclenp != NULL) 291e2950f41STomohiro Kusumi *reclenp = autofs_dirent_reclen(name); 292e2950f41STomohiro Kusumi 293e2950f41STomohiro Kusumi if (vop_write_dirent(&error, uio, ino, DT_DIR, strlen(name), name)) 294e2950f41STomohiro Kusumi return (EINVAL); 295e2950f41STomohiro Kusumi 296e2950f41STomohiro Kusumi return (error); 297e2950f41STomohiro Kusumi } 298e2950f41STomohiro Kusumi 299e2950f41STomohiro Kusumi static int 300e2950f41STomohiro Kusumi autofs_readdir(struct vop_readdir_args *ap) 301e2950f41STomohiro Kusumi { 302e2950f41STomohiro Kusumi struct vnode *vp = ap->a_vp; 303e2950f41STomohiro Kusumi struct autofs_mount *amp = VFSTOAUTOFS(vp->v_mount); 304e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(vp); 305e2950f41STomohiro Kusumi struct autofs_node *child; 306e2950f41STomohiro Kusumi struct uio *uio = ap->a_uio; 307e2950f41STomohiro Kusumi ssize_t initial_resid = ap->a_uio->uio_resid; 308e2950f41STomohiro Kusumi size_t reclen, reclens; 309e2950f41STomohiro Kusumi int error; 310e2950f41STomohiro Kusumi 311e2950f41STomohiro Kusumi KASSERT(vp->v_type == VDIR, ("!VDIR")); 312e2950f41STomohiro Kusumi 313e2950f41STomohiro Kusumi if (autofs_cached(anp, NULL, 0) == false && 314e2950f41STomohiro Kusumi autofs_ignore_thread() == false) { 315e2950f41STomohiro Kusumi struct vnode *newvp = NULL; 316caaec4e3STomohiro Kusumi error = autofs_trigger_vn(vp, "", 0, &newvp); 317e2950f41STomohiro Kusumi if (error) 318e2950f41STomohiro Kusumi return (error); 319e2950f41STomohiro Kusumi if (newvp != NULL) { 320e2950f41STomohiro Kusumi KKASSERT(newvp->v_tag != VT_AUTOFS); 321e2950f41STomohiro Kusumi vn_unlock(newvp); 322e2950f41STomohiro Kusumi error = VOP_READDIR(newvp, ap->a_uio, ap->a_cred, 323e2950f41STomohiro Kusumi ap->a_eofflag, ap->a_ncookies, ap->a_cookies); 324e2950f41STomohiro Kusumi vrele(newvp); 325e2950f41STomohiro Kusumi return (error); 326e2950f41STomohiro Kusumi } 327e2950f41STomohiro Kusumi } 328e2950f41STomohiro Kusumi 329e2950f41STomohiro Kusumi if (uio->uio_offset < 0) 330e2950f41STomohiro Kusumi return (EINVAL); 331e2950f41STomohiro Kusumi 332e2950f41STomohiro Kusumi if (ap->a_eofflag != NULL) 333e2950f41STomohiro Kusumi *ap->a_eofflag = FALSE; 334e2950f41STomohiro Kusumi 335e2950f41STomohiro Kusumi /* 336e2950f41STomohiro Kusumi * Write out the directory entry for ".". 337e2950f41STomohiro Kusumi */ 338e2950f41STomohiro Kusumi if (uio->uio_offset == 0) { 339e2950f41STomohiro Kusumi error = autofs_readdir_one(uio, ".", anp->an_ino, &reclen); 340e2950f41STomohiro Kusumi if (error) 341e2950f41STomohiro Kusumi goto out; 342e2950f41STomohiro Kusumi } 343e2950f41STomohiro Kusumi reclens = autofs_dirent_reclen("."); 344e2950f41STomohiro Kusumi 345e2950f41STomohiro Kusumi /* 346e2950f41STomohiro Kusumi * Write out the directory entry for "..". 347e2950f41STomohiro Kusumi */ 348e2950f41STomohiro Kusumi if (uio->uio_offset <= reclens) { 349e2950f41STomohiro Kusumi if (uio->uio_offset != reclens) 350e2950f41STomohiro Kusumi return (EINVAL); 351e2950f41STomohiro Kusumi error = autofs_readdir_one(uio, "..", 352e2950f41STomohiro Kusumi (anp->an_parent ? anp->an_parent->an_ino : anp->an_ino), 353e2950f41STomohiro Kusumi &reclen); 354e2950f41STomohiro Kusumi if (error) 355e2950f41STomohiro Kusumi goto out; 356e2950f41STomohiro Kusumi } 357e2950f41STomohiro Kusumi reclens += autofs_dirent_reclen(".."); 358e2950f41STomohiro Kusumi 359e2950f41STomohiro Kusumi /* 360e2950f41STomohiro Kusumi * Write out the directory entries for subdirectories. 361e2950f41STomohiro Kusumi */ 362bc6139d4STomohiro Kusumi mtx_lock_sh_quick(&->am_lock); 363e2950f41STomohiro Kusumi RB_FOREACH(child, autofs_node_tree, &anp->an_children) { 364e2950f41STomohiro Kusumi /* 365e2950f41STomohiro Kusumi * Check the offset to skip entries returned by previous 366e2950f41STomohiro Kusumi * calls to getdents(). 367e2950f41STomohiro Kusumi */ 368e2950f41STomohiro Kusumi if (uio->uio_offset > reclens) { 369e2950f41STomohiro Kusumi reclens += autofs_dirent_reclen(child->an_name); 370e2950f41STomohiro Kusumi continue; 371e2950f41STomohiro Kusumi } 372e2950f41STomohiro Kusumi 373e2950f41STomohiro Kusumi /* 374e2950f41STomohiro Kusumi * Prevent seeking into the middle of dirent. 375e2950f41STomohiro Kusumi */ 376e2950f41STomohiro Kusumi if (uio->uio_offset != reclens) { 377bc6139d4STomohiro Kusumi mtx_unlock_sh(&->am_lock); 378e2950f41STomohiro Kusumi return (EINVAL); 379e2950f41STomohiro Kusumi } 380e2950f41STomohiro Kusumi 38174565ee0STomohiro Kusumi error = autofs_readdir_one(uio, child->an_name, child->an_ino, 38274565ee0STomohiro Kusumi &reclen); 383e2950f41STomohiro Kusumi reclens += reclen; 384e2950f41STomohiro Kusumi if (error) { 385bc6139d4STomohiro Kusumi mtx_unlock_sh(&->am_lock); 386e2950f41STomohiro Kusumi goto out; 387e2950f41STomohiro Kusumi } 388e2950f41STomohiro Kusumi } 389bc6139d4STomohiro Kusumi mtx_unlock_sh(&->am_lock); 390e2950f41STomohiro Kusumi 391e2950f41STomohiro Kusumi if (ap->a_eofflag != NULL) 392e2950f41STomohiro Kusumi *ap->a_eofflag = TRUE; 393e2950f41STomohiro Kusumi 394e2950f41STomohiro Kusumi return (0); 395e2950f41STomohiro Kusumi out: 396e2950f41STomohiro Kusumi /* 397e2950f41STomohiro Kusumi * Return error if the initial buffer was too small to do anything. 398e2950f41STomohiro Kusumi */ 399e2950f41STomohiro Kusumi if (uio->uio_resid == initial_resid) 400e2950f41STomohiro Kusumi return (error); 401e2950f41STomohiro Kusumi 402e2950f41STomohiro Kusumi /* 403e2950f41STomohiro Kusumi * Don't return an error if we managed to copy out some entries. 404e2950f41STomohiro Kusumi */ 405e2950f41STomohiro Kusumi if (uio->uio_resid < reclen) 406e2950f41STomohiro Kusumi return (0); 407e2950f41STomohiro Kusumi 408e2950f41STomohiro Kusumi return (error); 409e2950f41STomohiro Kusumi } 410e2950f41STomohiro Kusumi 411e2950f41STomohiro Kusumi static int 412e2950f41STomohiro Kusumi autofs_reclaim(struct vop_reclaim_args *ap) 413e2950f41STomohiro Kusumi { 414e2950f41STomohiro Kusumi struct vnode *vp = ap->a_vp; 415e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(vp); 416e2950f41STomohiro Kusumi 417e2950f41STomohiro Kusumi /* 418e2950f41STomohiro Kusumi * We do not free autofs_node here; instead we are 419e2950f41STomohiro Kusumi * destroying them in autofs_node_delete(). 420e2950f41STomohiro Kusumi */ 421bfccbb76STomohiro Kusumi mtx_lock_ex_quick(&anp->an_vnode_lock); 422e2950f41STomohiro Kusumi anp->an_vnode = NULL; 423e2950f41STomohiro Kusumi vp->v_data = NULL; 424bfccbb76STomohiro Kusumi mtx_unlock_ex(&anp->an_vnode_lock); 425e2950f41STomohiro Kusumi 426e2950f41STomohiro Kusumi return (0); 427e2950f41STomohiro Kusumi } 428e2950f41STomohiro Kusumi 429e2950f41STomohiro Kusumi static int 430e2950f41STomohiro Kusumi autofs_mountctl(struct vop_mountctl_args *ap) 431e2950f41STomohiro Kusumi { 432e2950f41STomohiro Kusumi struct mount *mp; 433662e8088STomohiro Kusumi int res = 0; 434e2950f41STomohiro Kusumi 435e2950f41STomohiro Kusumi mp = ap->a_head.a_ops->head.vv_mount; 436e2950f41STomohiro Kusumi lwkt_gettoken(&mp->mnt_token); 437e2950f41STomohiro Kusumi 438e2950f41STomohiro Kusumi switch (ap->a_op) { 4395e4f9d10STomohiro Kusumi //case ...: 4405e4f9d10STomohiro Kusumi // break; 441e2950f41STomohiro Kusumi default: 442e2950f41STomohiro Kusumi res = vop_stdmountctl(ap); 443e2950f41STomohiro Kusumi break; 444e2950f41STomohiro Kusumi } 445e2950f41STomohiro Kusumi 446e2950f41STomohiro Kusumi lwkt_reltoken(&mp->mnt_token); 447e2950f41STomohiro Kusumi return (res); 448e2950f41STomohiro Kusumi } 449e2950f41STomohiro Kusumi 450e2950f41STomohiro Kusumi static int 451e2950f41STomohiro Kusumi autofs_print(struct vop_print_args *ap) 452e2950f41STomohiro Kusumi { 453e2950f41STomohiro Kusumi struct autofs_node *anp = VTOI(ap->a_vp); 454e2950f41STomohiro Kusumi 4557d470fedSTomohiro Kusumi kprintf("tag VT_AUTOFS, node %p, ino %jd, name %s, cached %d, retries %d, wildcards %d\n", 456b112b669STomohiro Kusumi anp, (intmax_t)anp->an_ino, anp->an_name, anp->an_cached, 457b112b669STomohiro Kusumi anp->an_retries, anp->an_wildcards); 458e2950f41STomohiro Kusumi 459e2950f41STomohiro Kusumi return (0); 460e2950f41STomohiro Kusumi } 461e2950f41STomohiro Kusumi 462e2950f41STomohiro Kusumi struct vop_ops autofs_vnode_vops = { 463e2950f41STomohiro Kusumi .vop_default = vop_defaultop, 464e2950f41STomohiro Kusumi .vop_getpages = vop_stdgetpages, 465e2950f41STomohiro Kusumi .vop_putpages = vop_stdputpages, 466e2950f41STomohiro Kusumi .vop_access = autofs_access, 467e2950f41STomohiro Kusumi .vop_getattr = autofs_getattr, 468e2950f41STomohiro Kusumi .vop_nresolve = autofs_nresolve, 469e2950f41STomohiro Kusumi .vop_nmkdir = autofs_nmkdir, 470e2950f41STomohiro Kusumi .vop_readdir = autofs_readdir, 471e2950f41STomohiro Kusumi .vop_reclaim = autofs_reclaim, 472e2950f41STomohiro Kusumi .vop_mountctl = autofs_mountctl, 473e2950f41STomohiro Kusumi .vop_print = autofs_print, 474e2950f41STomohiro Kusumi }; 475e2950f41STomohiro Kusumi 476e2950f41STomohiro Kusumi int 477e2950f41STomohiro Kusumi autofs_node_new(struct autofs_node *parent, struct autofs_mount *amp, 478e2950f41STomohiro Kusumi const char *name, int namelen, struct autofs_node **anpp) 479e2950f41STomohiro Kusumi { 480e2950f41STomohiro Kusumi struct autofs_node *anp; 481e2950f41STomohiro Kusumi 4826be174c1STomohiro Kusumi KKASSERT(mtx_islocked_ex(&->am_lock)); 483e2950f41STomohiro Kusumi 484e2950f41STomohiro Kusumi if (parent != NULL) { 4856be174c1STomohiro Kusumi KKASSERT(mtx_islocked_ex(&parent->an_mount->am_lock)); 486e2950f41STomohiro Kusumi KASSERT(autofs_node_find(parent, name, namelen, NULL) == ENOENT, 487e2950f41STomohiro Kusumi ("node \"%s\" already exists", name)); 488e2950f41STomohiro Kusumi } 489e2950f41STomohiro Kusumi 490a5dfdd2bSTomohiro Kusumi /* 491a5dfdd2bSTomohiro Kusumi * All struct fields must be initialized. 492a5dfdd2bSTomohiro Kusumi */ 493e2950f41STomohiro Kusumi anp = objcache_get(autofs_node_objcache, M_WAITOK); 494e2950f41STomohiro Kusumi if (namelen >= 0) 495e2950f41STomohiro Kusumi anp->an_name = kstrndup(name, namelen, M_AUTOFS); 496e2950f41STomohiro Kusumi else 497e2950f41STomohiro Kusumi anp->an_name = kstrdup(name, M_AUTOFS); 498e2950f41STomohiro Kusumi anp->an_ino = amp->am_last_ino++; 499e2950f41STomohiro Kusumi callout_init(&anp->an_callout); 500bfccbb76STomohiro Kusumi mtx_init(&anp->an_vnode_lock, "autofsvnlk"); 501e2950f41STomohiro Kusumi getnanotime(&anp->an_ctime); 502e2950f41STomohiro Kusumi anp->an_parent = parent; 503e2950f41STomohiro Kusumi anp->an_mount = amp; 504e2950f41STomohiro Kusumi anp->an_vnode = NULL; 505e2950f41STomohiro Kusumi anp->an_cached = false; 506e2950f41STomohiro Kusumi anp->an_wildcards = false; 507e2950f41STomohiro Kusumi anp->an_retries = 0; 508e2950f41STomohiro Kusumi if (parent != NULL) 509e2950f41STomohiro Kusumi RB_INSERT(autofs_node_tree, &parent->an_children, anp); 510e2950f41STomohiro Kusumi RB_INIT(&anp->an_children); 511e2950f41STomohiro Kusumi 512e2950f41STomohiro Kusumi *anpp = anp; 513e2950f41STomohiro Kusumi 514e2950f41STomohiro Kusumi return (0); 515e2950f41STomohiro Kusumi } 516e2950f41STomohiro Kusumi 517e2950f41STomohiro Kusumi int 51874565ee0STomohiro Kusumi autofs_node_find(struct autofs_node *parent, const char *name, int namelen, 51974565ee0STomohiro Kusumi struct autofs_node **anpp) 520e2950f41STomohiro Kusumi { 521e2950f41STomohiro Kusumi struct autofs_node *anp, find; 522e2950f41STomohiro Kusumi int error; 523e2950f41STomohiro Kusumi 5246be174c1STomohiro Kusumi KKASSERT(mtx_islocked(&parent->an_mount->am_lock)); 525e2950f41STomohiro Kusumi 526e2950f41STomohiro Kusumi if (namelen >= 0) 527e2950f41STomohiro Kusumi find.an_name = kstrndup(name, namelen, M_AUTOFS); 528e2950f41STomohiro Kusumi else 529e2950f41STomohiro Kusumi find.an_name = kstrdup(name, M_AUTOFS); 530e2950f41STomohiro Kusumi 531e2950f41STomohiro Kusumi anp = RB_FIND(autofs_node_tree, &parent->an_children, &find); 532e2950f41STomohiro Kusumi if (anp != NULL) { 533e2950f41STomohiro Kusumi error = 0; 534e2950f41STomohiro Kusumi if (anpp != NULL) 535e2950f41STomohiro Kusumi *anpp = anp; 536e2950f41STomohiro Kusumi } else { 537e2950f41STomohiro Kusumi error = ENOENT; 538e2950f41STomohiro Kusumi } 539e2950f41STomohiro Kusumi 540e2950f41STomohiro Kusumi kfree(find.an_name, M_AUTOFS); 541e2950f41STomohiro Kusumi 542e2950f41STomohiro Kusumi return (error); 543e2950f41STomohiro Kusumi } 544e2950f41STomohiro Kusumi 545e2950f41STomohiro Kusumi void 546e2950f41STomohiro Kusumi autofs_node_delete(struct autofs_node *anp) 547e2950f41STomohiro Kusumi { 5486be174c1STomohiro Kusumi KKASSERT(mtx_islocked_ex(&anp->an_mount->am_lock)); 549e2950f41STomohiro Kusumi KASSERT(RB_EMPTY(&anp->an_children), ("have children")); 550e2950f41STomohiro Kusumi 551e2950f41STomohiro Kusumi callout_drain(&anp->an_callout); 552e2950f41STomohiro Kusumi 553e2950f41STomohiro Kusumi if (anp->an_parent != NULL) 554e2950f41STomohiro Kusumi RB_REMOVE(autofs_node_tree, &anp->an_parent->an_children, anp); 555e2950f41STomohiro Kusumi 556bfccbb76STomohiro Kusumi mtx_uninit(&anp->an_vnode_lock); 557e2950f41STomohiro Kusumi kfree(anp->an_name, M_AUTOFS); 558e2950f41STomohiro Kusumi objcache_put(autofs_node_objcache, anp); 559e2950f41STomohiro Kusumi } 560e2950f41STomohiro Kusumi 561e2950f41STomohiro Kusumi int 562e2950f41STomohiro Kusumi autofs_node_vn(struct autofs_node *anp, struct mount *mp, int flags, 563e2950f41STomohiro Kusumi struct vnode **vpp) 564e2950f41STomohiro Kusumi { 565e2950f41STomohiro Kusumi struct vnode *vp = NULL; 566e2950f41STomohiro Kusumi int error; 567e2950f41STomohiro Kusumi retry: 5686be174c1STomohiro Kusumi KKASSERT(mtx_notlocked(&anp->an_mount->am_lock)); 569bfccbb76STomohiro Kusumi mtx_lock_ex_quick(&anp->an_vnode_lock); 570e2950f41STomohiro Kusumi 571e2950f41STomohiro Kusumi vp = anp->an_vnode; 572e2950f41STomohiro Kusumi if (vp != NULL) { 573e2950f41STomohiro Kusumi vhold(vp); 574bfccbb76STomohiro Kusumi mtx_unlock_ex(&anp->an_vnode_lock); 575e2950f41STomohiro Kusumi 576e2950f41STomohiro Kusumi error = vget(vp, flags | LK_RETRY); 577e2950f41STomohiro Kusumi if (error) { 578e2950f41STomohiro Kusumi AUTOFS_WARN("vget failed with error %d", error); 579e2950f41STomohiro Kusumi vdrop(vp); 580e2950f41STomohiro Kusumi goto retry; 581e2950f41STomohiro Kusumi } 582e2950f41STomohiro Kusumi vdrop(vp); 583e2950f41STomohiro Kusumi *vpp = vp; 584e2950f41STomohiro Kusumi return (0); 585e2950f41STomohiro Kusumi } 586e2950f41STomohiro Kusumi 587bfccbb76STomohiro Kusumi mtx_unlock_ex(&anp->an_vnode_lock); 588e2950f41STomohiro Kusumi 589e2950f41STomohiro Kusumi error = getnewvnode(VT_AUTOFS, mp, &vp, VLKTIMEOUT, LK_CANRECURSE); 590e2950f41STomohiro Kusumi if (error) 591e2950f41STomohiro Kusumi return (error); 592e2950f41STomohiro Kusumi vp->v_type = VDIR; 593e2950f41STomohiro Kusumi vp->v_data = anp; 594e2950f41STomohiro Kusumi 595e2950f41STomohiro Kusumi KASSERT(anp->an_vnode == NULL, ("lost race")); 596e2950f41STomohiro Kusumi anp->an_vnode = vp; 597e2950f41STomohiro Kusumi *vpp = vp; 598e2950f41STomohiro Kusumi 599e2950f41STomohiro Kusumi return (0); 600e2950f41STomohiro Kusumi } 601