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