13914ddf8SEdward Tomasz Napierala /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
318dffafaSEdward Tomasz Napierala *
43914ddf8SEdward Tomasz Napierala * Copyright (c) 2014 The FreeBSD Foundation
53914ddf8SEdward Tomasz Napierala *
63914ddf8SEdward Tomasz Napierala * This software was developed by Edward Tomasz Napierala under sponsorship
73914ddf8SEdward Tomasz Napierala * from the FreeBSD Foundation.
83914ddf8SEdward Tomasz Napierala *
93914ddf8SEdward Tomasz Napierala * Redistribution and use in source and binary forms, with or without
103914ddf8SEdward Tomasz Napierala * modification, are permitted provided that the following conditions
113914ddf8SEdward Tomasz Napierala * are met:
123914ddf8SEdward Tomasz Napierala * 1. Redistributions of source code must retain the above copyright
133914ddf8SEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer.
143914ddf8SEdward Tomasz Napierala * 2. Redistributions in binary form must reproduce the above copyright
153914ddf8SEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer in the
163914ddf8SEdward Tomasz Napierala * documentation and/or other materials provided with the distribution.
173914ddf8SEdward Tomasz Napierala *
183914ddf8SEdward Tomasz Napierala * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
193914ddf8SEdward Tomasz Napierala * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
203914ddf8SEdward Tomasz Napierala * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
213914ddf8SEdward Tomasz Napierala * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
223914ddf8SEdward Tomasz Napierala * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
233914ddf8SEdward Tomasz Napierala * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
243914ddf8SEdward Tomasz Napierala * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
253914ddf8SEdward Tomasz Napierala * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
263914ddf8SEdward Tomasz Napierala * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
273914ddf8SEdward Tomasz Napierala * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
283914ddf8SEdward Tomasz Napierala * SUCH DAMAGE.
293914ddf8SEdward Tomasz Napierala *
303914ddf8SEdward Tomasz Napierala */
313914ddf8SEdward Tomasz Napierala
323914ddf8SEdward Tomasz Napierala #include <sys/param.h>
336d2e2df7SMark Johnston #include <sys/systm.h>
343914ddf8SEdward Tomasz Napierala #include <sys/kernel.h>
353914ddf8SEdward Tomasz Napierala #include <sys/condvar.h>
363914ddf8SEdward Tomasz Napierala #include <sys/dirent.h>
373914ddf8SEdward Tomasz Napierala #include <sys/fcntl.h>
383914ddf8SEdward Tomasz Napierala #include <sys/lock.h>
393914ddf8SEdward Tomasz Napierala #include <sys/mount.h>
403914ddf8SEdward Tomasz Napierala #include <sys/mutex.h>
413914ddf8SEdward Tomasz Napierala #include <sys/namei.h>
423914ddf8SEdward Tomasz Napierala #include <sys/signalvar.h>
437571d313SEdward Tomasz Napierala #include <sys/stat.h>
44759489f9SEdward Tomasz Napierala #include <sys/taskqueue.h>
4542ed64e3SEdward Tomasz Napierala #include <sys/tree.h>
463914ddf8SEdward Tomasz Napierala #include <sys/vnode.h>
473914ddf8SEdward Tomasz Napierala #include <machine/atomic.h>
483914ddf8SEdward Tomasz Napierala #include <vm/uma.h>
493914ddf8SEdward Tomasz Napierala
50f5440d1aSEdward Tomasz Napierala #include <fs/autofs/autofs.h>
513914ddf8SEdward Tomasz Napierala
523914ddf8SEdward Tomasz Napierala static int autofs_trigger_vn(struct vnode *vp, const char *path,
533914ddf8SEdward Tomasz Napierala int pathlen, struct vnode **newvp);
543914ddf8SEdward Tomasz Napierala
55f81018caSEdward Tomasz Napierala extern struct autofs_softc *autofs_softc;
56f81018caSEdward Tomasz Napierala
573914ddf8SEdward Tomasz Napierala static int
autofs_access(struct vop_access_args * ap)583914ddf8SEdward Tomasz Napierala autofs_access(struct vop_access_args *ap)
593914ddf8SEdward Tomasz Napierala {
603914ddf8SEdward Tomasz Napierala
613914ddf8SEdward Tomasz Napierala /*
623914ddf8SEdward Tomasz Napierala * Nothing to do here; the only kind of access control
633914ddf8SEdward Tomasz Napierala * needed is in autofs_mkdir().
643914ddf8SEdward Tomasz Napierala */
653914ddf8SEdward Tomasz Napierala
663914ddf8SEdward Tomasz Napierala return (0);
673914ddf8SEdward Tomasz Napierala }
683914ddf8SEdward Tomasz Napierala
693914ddf8SEdward Tomasz Napierala static int
autofs_getattr(struct vop_getattr_args * ap)703914ddf8SEdward Tomasz Napierala autofs_getattr(struct vop_getattr_args *ap)
713914ddf8SEdward Tomasz Napierala {
723914ddf8SEdward Tomasz Napierala struct vnode *vp, *newvp;
733914ddf8SEdward Tomasz Napierala struct autofs_node *anp;
743914ddf8SEdward Tomasz Napierala struct mount *mp;
753914ddf8SEdward Tomasz Napierala struct vattr *vap;
763914ddf8SEdward Tomasz Napierala int error;
773914ddf8SEdward Tomasz Napierala
783914ddf8SEdward Tomasz Napierala vp = ap->a_vp;
793914ddf8SEdward Tomasz Napierala anp = vp->v_data;
803914ddf8SEdward Tomasz Napierala mp = vp->v_mount;
813914ddf8SEdward Tomasz Napierala vap = ap->a_vap;
823914ddf8SEdward Tomasz Napierala
833914ddf8SEdward Tomasz Napierala KASSERT(ap->a_vp->v_type == VDIR, ("!VDIR"));
843914ddf8SEdward Tomasz Napierala
853914ddf8SEdward Tomasz Napierala /*
863914ddf8SEdward Tomasz Napierala * The reason we must do this is that some tree-walking software,
873914ddf8SEdward Tomasz Napierala * namely fts(3), assumes that stat(".") results will not change
883914ddf8SEdward Tomasz Napierala * between chdir("subdir") and chdir(".."), and fails with ENOENT
893914ddf8SEdward Tomasz Napierala * otherwise.
903914ddf8SEdward Tomasz Napierala */
913914ddf8SEdward Tomasz Napierala if (autofs_mount_on_stat && autofs_cached(anp, NULL, 0) == false &&
923914ddf8SEdward Tomasz Napierala autofs_ignore_thread(curthread) == false) {
933914ddf8SEdward Tomasz Napierala error = autofs_trigger_vn(vp, "", 0, &newvp);
943914ddf8SEdward Tomasz Napierala if (error != 0)
953914ddf8SEdward Tomasz Napierala return (error);
963914ddf8SEdward Tomasz Napierala
973914ddf8SEdward Tomasz Napierala if (newvp != NULL) {
983914ddf8SEdward Tomasz Napierala error = VOP_GETATTR(newvp, ap->a_vap,
993914ddf8SEdward Tomasz Napierala ap->a_cred);
1003914ddf8SEdward Tomasz Napierala vput(newvp);
1013914ddf8SEdward Tomasz Napierala return (error);
1023914ddf8SEdward Tomasz Napierala }
1033914ddf8SEdward Tomasz Napierala }
1043914ddf8SEdward Tomasz Napierala
1053914ddf8SEdward Tomasz Napierala vap->va_type = VDIR;
1063914ddf8SEdward Tomasz Napierala vap->va_mode = 0755;
1073914ddf8SEdward Tomasz Napierala vap->va_nlink = 3; /* XXX */
1083914ddf8SEdward Tomasz Napierala vap->va_uid = 0;
1093914ddf8SEdward Tomasz Napierala vap->va_gid = 0;
1103914ddf8SEdward Tomasz Napierala vap->va_rdev = NODEV;
1113914ddf8SEdward Tomasz Napierala vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
1123914ddf8SEdward Tomasz Napierala vap->va_fileid = anp->an_fileno;
1137571d313SEdward Tomasz Napierala vap->va_size = S_BLKSIZE;
1147571d313SEdward Tomasz Napierala vap->va_blocksize = S_BLKSIZE;
1153914ddf8SEdward Tomasz Napierala vap->va_mtime = anp->an_ctime;
1163914ddf8SEdward Tomasz Napierala vap->va_atime = anp->an_ctime;
1173914ddf8SEdward Tomasz Napierala vap->va_ctime = anp->an_ctime;
1183914ddf8SEdward Tomasz Napierala vap->va_birthtime = anp->an_ctime;
1193914ddf8SEdward Tomasz Napierala vap->va_gen = 0;
1203914ddf8SEdward Tomasz Napierala vap->va_flags = 0;
1213914ddf8SEdward Tomasz Napierala vap->va_rdev = 0;
1227571d313SEdward Tomasz Napierala vap->va_bytes = S_BLKSIZE;
1233914ddf8SEdward Tomasz Napierala vap->va_filerev = 0;
1243914ddf8SEdward Tomasz Napierala vap->va_spare = 0;
1253914ddf8SEdward Tomasz Napierala
1263914ddf8SEdward Tomasz Napierala return (0);
1273914ddf8SEdward Tomasz Napierala }
1283914ddf8SEdward Tomasz Napierala
1293914ddf8SEdward Tomasz Napierala /*
1303914ddf8SEdward Tomasz Napierala * Unlock the vnode, request automountd(8) action, and then lock it back.
1313914ddf8SEdward Tomasz Napierala * If anything got mounted on top of the vnode, return the new filesystem's
1323914ddf8SEdward Tomasz Napierala * root vnode in 'newvp', locked.
1333914ddf8SEdward Tomasz Napierala */
1343914ddf8SEdward Tomasz Napierala static int
autofs_trigger_vn(struct vnode * vp,const char * path,int pathlen,struct vnode ** newvp)1353914ddf8SEdward Tomasz Napierala autofs_trigger_vn(struct vnode *vp, const char *path, int pathlen,
1363914ddf8SEdward Tomasz Napierala struct vnode **newvp)
1373914ddf8SEdward Tomasz Napierala {
1383914ddf8SEdward Tomasz Napierala struct autofs_node *anp;
1393914ddf8SEdward Tomasz Napierala int error, lock_flags;
1403914ddf8SEdward Tomasz Napierala
1413914ddf8SEdward Tomasz Napierala anp = vp->v_data;
1423914ddf8SEdward Tomasz Napierala
1433914ddf8SEdward Tomasz Napierala /*
1443914ddf8SEdward Tomasz Napierala * Release the vnode lock, so that other operations, in partcular
1453914ddf8SEdward Tomasz Napierala * mounting a filesystem on top of it, can proceed. Increase use
1463914ddf8SEdward Tomasz Napierala * count, to prevent the vnode from being deallocated and to prevent
1473914ddf8SEdward Tomasz Napierala * filesystem from being unmounted.
1483914ddf8SEdward Tomasz Napierala */
1493914ddf8SEdward Tomasz Napierala lock_flags = VOP_ISLOCKED(vp);
1503914ddf8SEdward Tomasz Napierala vref(vp);
151b249ce48SMateusz Guzik VOP_UNLOCK(vp);
1523914ddf8SEdward Tomasz Napierala
153f81018caSEdward Tomasz Napierala sx_xlock(&autofs_softc->sc_lock);
1543914ddf8SEdward Tomasz Napierala
1553914ddf8SEdward Tomasz Napierala /*
1563914ddf8SEdward Tomasz Napierala * XXX: Workaround for mounting the same thing multiple times; revisit.
1573914ddf8SEdward Tomasz Napierala */
1583914ddf8SEdward Tomasz Napierala if (vp->v_mountedhere != NULL) {
1593914ddf8SEdward Tomasz Napierala error = 0;
1603914ddf8SEdward Tomasz Napierala goto mounted;
1613914ddf8SEdward Tomasz Napierala }
1623914ddf8SEdward Tomasz Napierala
1633914ddf8SEdward Tomasz Napierala error = autofs_trigger(anp, path, pathlen);
1643914ddf8SEdward Tomasz Napierala mounted:
165f81018caSEdward Tomasz Napierala sx_xunlock(&autofs_softc->sc_lock);
1663914ddf8SEdward Tomasz Napierala vn_lock(vp, lock_flags | LK_RETRY);
1673914ddf8SEdward Tomasz Napierala vunref(vp);
168abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vp)) {
169abd80ddbSMateusz Guzik AUTOFS_DEBUG("VIRF_DOOMED");
1703914ddf8SEdward Tomasz Napierala return (ENOENT);
1713914ddf8SEdward Tomasz Napierala }
1723914ddf8SEdward Tomasz Napierala
1733914ddf8SEdward Tomasz Napierala if (error != 0)
1743914ddf8SEdward Tomasz Napierala return (error);
1753914ddf8SEdward Tomasz Napierala
1763914ddf8SEdward Tomasz Napierala if (vp->v_mountedhere == NULL) {
1773914ddf8SEdward Tomasz Napierala *newvp = NULL;
1783914ddf8SEdward Tomasz Napierala return (0);
1793914ddf8SEdward Tomasz Napierala } else {
1803914ddf8SEdward Tomasz Napierala /*
1813914ddf8SEdward Tomasz Napierala * If the operation that succeeded was mount, then mark
1823914ddf8SEdward Tomasz Napierala * the node as non-cached. Otherwise, if someone unmounts
1833914ddf8SEdward Tomasz Napierala * the filesystem before the cache times out, we will fail
1843914ddf8SEdward Tomasz Napierala * to trigger.
1853914ddf8SEdward Tomasz Napierala */
1863914ddf8SEdward Tomasz Napierala anp->an_cached = false;
1873914ddf8SEdward Tomasz Napierala }
1883914ddf8SEdward Tomasz Napierala
1893914ddf8SEdward Tomasz Napierala error = VFS_ROOT(vp->v_mountedhere, lock_flags, newvp);
1903914ddf8SEdward Tomasz Napierala if (error != 0) {
1913914ddf8SEdward Tomasz Napierala AUTOFS_WARN("VFS_ROOT() failed with error %d", error);
1923914ddf8SEdward Tomasz Napierala return (error);
1933914ddf8SEdward Tomasz Napierala }
1943914ddf8SEdward Tomasz Napierala
1953914ddf8SEdward Tomasz Napierala return (0);
1963914ddf8SEdward Tomasz Napierala }
1973914ddf8SEdward Tomasz Napierala
1983914ddf8SEdward Tomasz Napierala static int
autofs_vget_callback(struct mount * mp,void * arg,int flags,struct vnode ** vpp)199d19c297eSEdward Tomasz Napierala autofs_vget_callback(struct mount *mp, void *arg, int flags,
2002f438a99SEdward Tomasz Napierala struct vnode **vpp)
2012f438a99SEdward Tomasz Napierala {
2022f438a99SEdward Tomasz Napierala
203d19c297eSEdward Tomasz Napierala return (autofs_node_vn(arg, mp, flags, vpp));
2042f438a99SEdward Tomasz Napierala }
2052f438a99SEdward Tomasz Napierala
2062f438a99SEdward Tomasz Napierala static int
autofs_lookup(struct vop_lookup_args * ap)2073914ddf8SEdward Tomasz Napierala autofs_lookup(struct vop_lookup_args *ap)
2083914ddf8SEdward Tomasz Napierala {
2093914ddf8SEdward Tomasz Napierala struct vnode *dvp, *newvp, **vpp;
2103914ddf8SEdward Tomasz Napierala struct mount *mp;
2113914ddf8SEdward Tomasz Napierala struct autofs_mount *amp;
2123914ddf8SEdward Tomasz Napierala struct autofs_node *anp, *child;
2133914ddf8SEdward Tomasz Napierala struct componentname *cnp;
214213ed838SEdward Tomasz Napierala int error;
2153914ddf8SEdward Tomasz Napierala
2163914ddf8SEdward Tomasz Napierala dvp = ap->a_dvp;
2173914ddf8SEdward Tomasz Napierala vpp = ap->a_vpp;
2183914ddf8SEdward Tomasz Napierala mp = dvp->v_mount;
2193914ddf8SEdward Tomasz Napierala amp = VFSTOAUTOFS(mp);
2203914ddf8SEdward Tomasz Napierala anp = dvp->v_data;
2213914ddf8SEdward Tomasz Napierala cnp = ap->a_cnp;
2223914ddf8SEdward Tomasz Napierala
2233914ddf8SEdward Tomasz Napierala if (cnp->cn_flags & ISDOTDOT) {
2243914ddf8SEdward Tomasz Napierala KASSERT(anp->an_parent != NULL, ("NULL parent"));
2253914ddf8SEdward Tomasz Napierala /*
2262f438a99SEdward Tomasz Napierala * Note that in this case, dvp is the child vnode, and we
2272f438a99SEdward Tomasz Napierala * are looking up the parent vnode - exactly reverse from
2282f438a99SEdward Tomasz Napierala * normal operation. Unlocking dvp requires some rather
2292f438a99SEdward Tomasz Napierala * tricky unlock/relock dance to prevent mp from being freed;
2302f438a99SEdward Tomasz Napierala * use vn_vget_ino_gen() which takes care of all that.
2313914ddf8SEdward Tomasz Napierala */
2322f438a99SEdward Tomasz Napierala error = vn_vget_ino_gen(dvp, autofs_vget_callback,
233d19c297eSEdward Tomasz Napierala anp->an_parent, cnp->cn_lkflags, vpp);
2343914ddf8SEdward Tomasz Napierala if (error != 0) {
2352f438a99SEdward Tomasz Napierala AUTOFS_WARN("vn_vget_ino_gen() failed with error %d",
2363914ddf8SEdward Tomasz Napierala error);
2372f438a99SEdward Tomasz Napierala return (error);
2383914ddf8SEdward Tomasz Napierala }
2393914ddf8SEdward Tomasz Napierala return (error);
2403914ddf8SEdward Tomasz Napierala }
2413914ddf8SEdward Tomasz Napierala
2423914ddf8SEdward Tomasz Napierala if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
2433914ddf8SEdward Tomasz Napierala vref(dvp);
2443914ddf8SEdward Tomasz Napierala *vpp = dvp;
2453914ddf8SEdward Tomasz Napierala
2463914ddf8SEdward Tomasz Napierala return (0);
2473914ddf8SEdward Tomasz Napierala }
2483914ddf8SEdward Tomasz Napierala
2493914ddf8SEdward Tomasz Napierala if (autofs_cached(anp, cnp->cn_nameptr, cnp->cn_namelen) == false &&
250b4a58fbfSMateusz Guzik autofs_ignore_thread(curthread) == false) {
2513914ddf8SEdward Tomasz Napierala error = autofs_trigger_vn(dvp,
2523914ddf8SEdward Tomasz Napierala cnp->cn_nameptr, cnp->cn_namelen, &newvp);
2533914ddf8SEdward Tomasz Napierala if (error != 0)
2543914ddf8SEdward Tomasz Napierala return (error);
2553914ddf8SEdward Tomasz Napierala
2563914ddf8SEdward Tomasz Napierala if (newvp != NULL) {
2573914ddf8SEdward Tomasz Napierala /*
258213ed838SEdward Tomasz Napierala * The target filesystem got automounted.
259213ed838SEdward Tomasz Napierala * Let the lookup(9) go around with the same
260213ed838SEdward Tomasz Napierala * path component.
2613914ddf8SEdward Tomasz Napierala */
2623914ddf8SEdward Tomasz Napierala vput(newvp);
263213ed838SEdward Tomasz Napierala return (ERELOOKUP);
2643914ddf8SEdward Tomasz Napierala }
2653914ddf8SEdward Tomasz Napierala }
2663914ddf8SEdward Tomasz Napierala
2672eaebf35SEdward Tomasz Napierala AUTOFS_SLOCK(amp);
2683914ddf8SEdward Tomasz Napierala error = autofs_node_find(anp, cnp->cn_nameptr, cnp->cn_namelen, &child);
2693914ddf8SEdward Tomasz Napierala if (error != 0) {
2703914ddf8SEdward Tomasz Napierala if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) {
2712eaebf35SEdward Tomasz Napierala AUTOFS_SUNLOCK(amp);
2723914ddf8SEdward Tomasz Napierala return (EJUSTRETURN);
2733914ddf8SEdward Tomasz Napierala }
2743914ddf8SEdward Tomasz Napierala
2752eaebf35SEdward Tomasz Napierala AUTOFS_SUNLOCK(amp);
2763914ddf8SEdward Tomasz Napierala return (ENOENT);
2773914ddf8SEdward Tomasz Napierala }
2783914ddf8SEdward Tomasz Napierala
2793914ddf8SEdward Tomasz Napierala /*
2803914ddf8SEdward Tomasz Napierala * XXX: Dropping the node here is ok, because we never remove nodes.
2813914ddf8SEdward Tomasz Napierala */
2822eaebf35SEdward Tomasz Napierala AUTOFS_SUNLOCK(amp);
2833914ddf8SEdward Tomasz Napierala
284d19c297eSEdward Tomasz Napierala error = autofs_node_vn(child, mp, cnp->cn_lkflags, vpp);
2853914ddf8SEdward Tomasz Napierala if (error != 0) {
2863914ddf8SEdward Tomasz Napierala if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE)
2873914ddf8SEdward Tomasz Napierala return (EJUSTRETURN);
2883914ddf8SEdward Tomasz Napierala
2893914ddf8SEdward Tomasz Napierala return (error);
2903914ddf8SEdward Tomasz Napierala }
2913914ddf8SEdward Tomasz Napierala
2923914ddf8SEdward Tomasz Napierala return (0);
2933914ddf8SEdward Tomasz Napierala }
2943914ddf8SEdward Tomasz Napierala
2953914ddf8SEdward Tomasz Napierala static int
autofs_mkdir(struct vop_mkdir_args * ap)2963914ddf8SEdward Tomasz Napierala autofs_mkdir(struct vop_mkdir_args *ap)
2973914ddf8SEdward Tomasz Napierala {
2983914ddf8SEdward Tomasz Napierala struct vnode *vp;
2993914ddf8SEdward Tomasz Napierala struct autofs_node *anp;
3003914ddf8SEdward Tomasz Napierala struct autofs_mount *amp;
3013914ddf8SEdward Tomasz Napierala struct autofs_node *child;
3023914ddf8SEdward Tomasz Napierala int error;
3033914ddf8SEdward Tomasz Napierala
3043914ddf8SEdward Tomasz Napierala vp = ap->a_dvp;
3053914ddf8SEdward Tomasz Napierala anp = vp->v_data;
3063914ddf8SEdward Tomasz Napierala amp = VFSTOAUTOFS(vp->v_mount);
3073914ddf8SEdward Tomasz Napierala
3083914ddf8SEdward Tomasz Napierala /*
3093914ddf8SEdward Tomasz Napierala * Do not allow mkdir() if the calling thread is not
3103914ddf8SEdward Tomasz Napierala * automountd(8) descendant.
3113914ddf8SEdward Tomasz Napierala */
3123914ddf8SEdward Tomasz Napierala if (autofs_ignore_thread(curthread) == false)
3133914ddf8SEdward Tomasz Napierala return (EPERM);
3143914ddf8SEdward Tomasz Napierala
3152eaebf35SEdward Tomasz Napierala AUTOFS_XLOCK(amp);
3163914ddf8SEdward Tomasz Napierala error = autofs_node_new(anp, amp, ap->a_cnp->cn_nameptr,
3173914ddf8SEdward Tomasz Napierala ap->a_cnp->cn_namelen, &child);
3183914ddf8SEdward Tomasz Napierala if (error != 0) {
3192eaebf35SEdward Tomasz Napierala AUTOFS_XUNLOCK(amp);
3203914ddf8SEdward Tomasz Napierala return (error);
3213914ddf8SEdward Tomasz Napierala }
3222eaebf35SEdward Tomasz Napierala AUTOFS_XUNLOCK(amp);
3233914ddf8SEdward Tomasz Napierala
324d19c297eSEdward Tomasz Napierala error = autofs_node_vn(child, vp->v_mount, LK_EXCLUSIVE, ap->a_vpp);
3253914ddf8SEdward Tomasz Napierala
3263914ddf8SEdward Tomasz Napierala return (error);
3273914ddf8SEdward Tomasz Napierala }
3283914ddf8SEdward Tomasz Napierala
329c1258254SEdward Tomasz Napierala static int
autofs_print(struct vop_print_args * ap)330c1258254SEdward Tomasz Napierala autofs_print(struct vop_print_args *ap)
331c1258254SEdward Tomasz Napierala {
332c1258254SEdward Tomasz Napierala struct vnode *vp;
333c1258254SEdward Tomasz Napierala struct autofs_node *anp;
334c1258254SEdward Tomasz Napierala
335c1258254SEdward Tomasz Napierala vp = ap->a_vp;
336c1258254SEdward Tomasz Napierala anp = vp->v_data;
337c1258254SEdward Tomasz Napierala
338c1258254SEdward Tomasz Napierala printf(" name \"%s\", fileno %d, cached %d, wildcards %d\n",
339c1258254SEdward Tomasz Napierala anp->an_name, anp->an_fileno, anp->an_cached, anp->an_wildcards);
340c1258254SEdward Tomasz Napierala
341c1258254SEdward Tomasz Napierala return (0);
342c1258254SEdward Tomasz Napierala }
343c1258254SEdward Tomasz Napierala
34449d8ebfeSEdward Tomasz Napierala /*
34549d8ebfeSEdward Tomasz Napierala * Write out a single 'struct dirent', based on 'name' and 'fileno' arguments.
34649d8ebfeSEdward Tomasz Napierala */
3473914ddf8SEdward Tomasz Napierala static int
autofs_readdir_one(struct uio * uio,const char * name,int fileno,size_t * reclenp)34849d8ebfeSEdward Tomasz Napierala autofs_readdir_one(struct uio *uio, const char *name, int fileno,
34949d8ebfeSEdward Tomasz Napierala size_t *reclenp)
3503914ddf8SEdward Tomasz Napierala {
3513914ddf8SEdward Tomasz Napierala struct dirent dirent;
3526d2e2df7SMark Johnston size_t namlen, reclen;
35349d8ebfeSEdward Tomasz Napierala int error;
3543914ddf8SEdward Tomasz Napierala
35549d8ebfeSEdward Tomasz Napierala namlen = strlen(name);
3566d2e2df7SMark Johnston reclen = _GENERIC_DIRLEN(namlen);
35749d8ebfeSEdward Tomasz Napierala if (reclenp != NULL)
35849d8ebfeSEdward Tomasz Napierala *reclenp = reclen;
35949d8ebfeSEdward Tomasz Napierala
36049d8ebfeSEdward Tomasz Napierala if (uio == NULL)
36149d8ebfeSEdward Tomasz Napierala return (0);
36249d8ebfeSEdward Tomasz Napierala
36349d8ebfeSEdward Tomasz Napierala if (uio->uio_resid < reclen)
36449d8ebfeSEdward Tomasz Napierala return (EINVAL);
36549d8ebfeSEdward Tomasz Napierala
3663914ddf8SEdward Tomasz Napierala dirent.d_fileno = fileno;
36790f580b9SMark Johnston dirent.d_off = uio->uio_offset + reclen;
36849d8ebfeSEdward Tomasz Napierala dirent.d_reclen = reclen;
36949d8ebfeSEdward Tomasz Napierala dirent.d_type = DT_DIR;
37049d8ebfeSEdward Tomasz Napierala dirent.d_namlen = namlen;
37149d8ebfeSEdward Tomasz Napierala memcpy(dirent.d_name, name, namlen);
3726d2e2df7SMark Johnston dirent_terminate(&dirent);
37349d8ebfeSEdward Tomasz Napierala error = uiomove(&dirent, reclen, uio);
3743914ddf8SEdward Tomasz Napierala
3753914ddf8SEdward Tomasz Napierala return (error);
3763914ddf8SEdward Tomasz Napierala }
3773914ddf8SEdward Tomasz Napierala
37849d8ebfeSEdward Tomasz Napierala static size_t
autofs_dirent_reclen(const char * name)37949d8ebfeSEdward Tomasz Napierala autofs_dirent_reclen(const char *name)
38049d8ebfeSEdward Tomasz Napierala {
38149d8ebfeSEdward Tomasz Napierala size_t reclen;
38249d8ebfeSEdward Tomasz Napierala
383f8eecb97SEdward Tomasz Napierala (void)autofs_readdir_one(NULL, name, -1, &reclen);
38449d8ebfeSEdward Tomasz Napierala
38549d8ebfeSEdward Tomasz Napierala return (reclen);
38649d8ebfeSEdward Tomasz Napierala }
38749d8ebfeSEdward Tomasz Napierala
3883914ddf8SEdward Tomasz Napierala static int
autofs_readdir(struct vop_readdir_args * ap)3893914ddf8SEdward Tomasz Napierala autofs_readdir(struct vop_readdir_args *ap)
3903914ddf8SEdward Tomasz Napierala {
3913914ddf8SEdward Tomasz Napierala struct vnode *vp, *newvp;
3923914ddf8SEdward Tomasz Napierala struct autofs_mount *amp;
3933914ddf8SEdward Tomasz Napierala struct autofs_node *anp, *child;
3943914ddf8SEdward Tomasz Napierala struct uio *uio;
39549d8ebfeSEdward Tomasz Napierala size_t reclen, reclens;
39649d8ebfeSEdward Tomasz Napierala ssize_t initial_resid;
39749d8ebfeSEdward Tomasz Napierala int error;
3983914ddf8SEdward Tomasz Napierala
3993914ddf8SEdward Tomasz Napierala vp = ap->a_vp;
4003914ddf8SEdward Tomasz Napierala amp = VFSTOAUTOFS(vp->v_mount);
4013914ddf8SEdward Tomasz Napierala anp = vp->v_data;
4023914ddf8SEdward Tomasz Napierala uio = ap->a_uio;
40349d8ebfeSEdward Tomasz Napierala initial_resid = ap->a_uio->uio_resid;
4043914ddf8SEdward Tomasz Napierala
4053914ddf8SEdward Tomasz Napierala KASSERT(vp->v_type == VDIR, ("!VDIR"));
4063914ddf8SEdward Tomasz Napierala
4073914ddf8SEdward Tomasz Napierala if (autofs_cached(anp, NULL, 0) == false &&
4083914ddf8SEdward Tomasz Napierala autofs_ignore_thread(curthread) == false) {
4093914ddf8SEdward Tomasz Napierala error = autofs_trigger_vn(vp, "", 0, &newvp);
4103914ddf8SEdward Tomasz Napierala if (error != 0)
4113914ddf8SEdward Tomasz Napierala return (error);
4123914ddf8SEdward Tomasz Napierala
4133914ddf8SEdward Tomasz Napierala if (newvp != NULL) {
4143914ddf8SEdward Tomasz Napierala error = VOP_READDIR(newvp, ap->a_uio, ap->a_cred,
4153914ddf8SEdward Tomasz Napierala ap->a_eofflag, ap->a_ncookies, ap->a_cookies);
4163914ddf8SEdward Tomasz Napierala vput(newvp);
4173914ddf8SEdward Tomasz Napierala return (error);
4183914ddf8SEdward Tomasz Napierala }
4193914ddf8SEdward Tomasz Napierala }
4203914ddf8SEdward Tomasz Napierala
42149d8ebfeSEdward Tomasz Napierala if (uio->uio_offset < 0)
4223914ddf8SEdward Tomasz Napierala return (EINVAL);
42349d8ebfeSEdward Tomasz Napierala
42449d8ebfeSEdward Tomasz Napierala if (ap->a_eofflag != NULL)
42549d8ebfeSEdward Tomasz Napierala *ap->a_eofflag = FALSE;
42649d8ebfeSEdward Tomasz Napierala
42749d8ebfeSEdward Tomasz Napierala /*
42849d8ebfeSEdward Tomasz Napierala * Write out the directory entry for ".". This is conditional
42949d8ebfeSEdward Tomasz Napierala * on the current offset into the directory; same applies to the
43049d8ebfeSEdward Tomasz Napierala * other two cases below.
43149d8ebfeSEdward Tomasz Napierala */
43249d8ebfeSEdward Tomasz Napierala if (uio->uio_offset == 0) {
43349d8ebfeSEdward Tomasz Napierala error = autofs_readdir_one(uio, ".", anp->an_fileno, &reclen);
43449d8ebfeSEdward Tomasz Napierala if (error != 0)
43549d8ebfeSEdward Tomasz Napierala goto out;
43649d8ebfeSEdward Tomasz Napierala }
43749d8ebfeSEdward Tomasz Napierala reclens = autofs_dirent_reclen(".");
43849d8ebfeSEdward Tomasz Napierala
43949d8ebfeSEdward Tomasz Napierala /*
44049d8ebfeSEdward Tomasz Napierala * Write out the directory entry for "..".
44149d8ebfeSEdward Tomasz Napierala */
44249d8ebfeSEdward Tomasz Napierala if (uio->uio_offset <= reclens) {
44349d8ebfeSEdward Tomasz Napierala if (uio->uio_offset != reclens)
44449d8ebfeSEdward Tomasz Napierala return (EINVAL);
44549d8ebfeSEdward Tomasz Napierala if (anp->an_parent == NULL) {
44649d8ebfeSEdward Tomasz Napierala error = autofs_readdir_one(uio, "..",
44749d8ebfeSEdward Tomasz Napierala anp->an_fileno, &reclen);
44849d8ebfeSEdward Tomasz Napierala } else {
44949d8ebfeSEdward Tomasz Napierala error = autofs_readdir_one(uio, "..",
45049d8ebfeSEdward Tomasz Napierala anp->an_parent->an_fileno, &reclen);
45149d8ebfeSEdward Tomasz Napierala }
45249d8ebfeSEdward Tomasz Napierala if (error != 0)
45349d8ebfeSEdward Tomasz Napierala goto out;
45449d8ebfeSEdward Tomasz Napierala }
45549d8ebfeSEdward Tomasz Napierala
45649d8ebfeSEdward Tomasz Napierala reclens += autofs_dirent_reclen("..");
45749d8ebfeSEdward Tomasz Napierala
45849d8ebfeSEdward Tomasz Napierala /*
45949d8ebfeSEdward Tomasz Napierala * Write out the directory entries for subdirectories.
46049d8ebfeSEdward Tomasz Napierala */
46149d8ebfeSEdward Tomasz Napierala AUTOFS_SLOCK(amp);
46242ed64e3SEdward Tomasz Napierala RB_FOREACH(child, autofs_node_tree, &anp->an_children) {
46349d8ebfeSEdward Tomasz Napierala /*
46449d8ebfeSEdward Tomasz Napierala * Check the offset to skip entries returned by previous
46549d8ebfeSEdward Tomasz Napierala * calls to getdents().
46649d8ebfeSEdward Tomasz Napierala */
46749d8ebfeSEdward Tomasz Napierala if (uio->uio_offset > reclens) {
46849d8ebfeSEdward Tomasz Napierala reclens += autofs_dirent_reclen(child->an_name);
46949d8ebfeSEdward Tomasz Napierala continue;
47049d8ebfeSEdward Tomasz Napierala }
47149d8ebfeSEdward Tomasz Napierala
47249d8ebfeSEdward Tomasz Napierala /*
47349d8ebfeSEdward Tomasz Napierala * Prevent seeking into the middle of dirent.
47449d8ebfeSEdward Tomasz Napierala */
47549d8ebfeSEdward Tomasz Napierala if (uio->uio_offset != reclens) {
47649d8ebfeSEdward Tomasz Napierala AUTOFS_SUNLOCK(amp);
47749d8ebfeSEdward Tomasz Napierala return (EINVAL);
47849d8ebfeSEdward Tomasz Napierala }
47949d8ebfeSEdward Tomasz Napierala
48049d8ebfeSEdward Tomasz Napierala error = autofs_readdir_one(uio, child->an_name,
48149d8ebfeSEdward Tomasz Napierala child->an_fileno, &reclen);
48249d8ebfeSEdward Tomasz Napierala reclens += reclen;
48349d8ebfeSEdward Tomasz Napierala if (error != 0) {
48449d8ebfeSEdward Tomasz Napierala AUTOFS_SUNLOCK(amp);
48549d8ebfeSEdward Tomasz Napierala goto out;
48649d8ebfeSEdward Tomasz Napierala }
48749d8ebfeSEdward Tomasz Napierala }
48849d8ebfeSEdward Tomasz Napierala AUTOFS_SUNLOCK(amp);
4893914ddf8SEdward Tomasz Napierala
4903914ddf8SEdward Tomasz Napierala if (ap->a_eofflag != NULL)
4913914ddf8SEdward Tomasz Napierala *ap->a_eofflag = TRUE;
4923914ddf8SEdward Tomasz Napierala
4933914ddf8SEdward Tomasz Napierala return (0);
49449d8ebfeSEdward Tomasz Napierala
49549d8ebfeSEdward Tomasz Napierala out:
49649d8ebfeSEdward Tomasz Napierala /*
49749d8ebfeSEdward Tomasz Napierala * Return error if the initial buffer was too small to do anything.
49849d8ebfeSEdward Tomasz Napierala */
49949d8ebfeSEdward Tomasz Napierala if (uio->uio_resid == initial_resid)
50049d8ebfeSEdward Tomasz Napierala return (error);
50149d8ebfeSEdward Tomasz Napierala
50249d8ebfeSEdward Tomasz Napierala /*
50349d8ebfeSEdward Tomasz Napierala * Don't return an error if we managed to copy out some entries.
50449d8ebfeSEdward Tomasz Napierala */
50549d8ebfeSEdward Tomasz Napierala if (uio->uio_resid < reclen)
50649d8ebfeSEdward Tomasz Napierala return (0);
50749d8ebfeSEdward Tomasz Napierala
50849d8ebfeSEdward Tomasz Napierala return (error);
5093914ddf8SEdward Tomasz Napierala }
5103914ddf8SEdward Tomasz Napierala
5113914ddf8SEdward Tomasz Napierala static int
autofs_reclaim(struct vop_reclaim_args * ap)5123914ddf8SEdward Tomasz Napierala autofs_reclaim(struct vop_reclaim_args *ap)
5133914ddf8SEdward Tomasz Napierala {
51416092308SEdward Tomasz Napierala struct vnode *vp;
51516092308SEdward Tomasz Napierala struct autofs_node *anp;
5163914ddf8SEdward Tomasz Napierala
5173914ddf8SEdward Tomasz Napierala vp = ap->a_vp;
5183914ddf8SEdward Tomasz Napierala anp = vp->v_data;
5193914ddf8SEdward Tomasz Napierala
5203914ddf8SEdward Tomasz Napierala /*
5213914ddf8SEdward Tomasz Napierala * We do not free autofs_node here; instead we are
5223914ddf8SEdward Tomasz Napierala * destroying them in autofs_node_delete().
5233914ddf8SEdward Tomasz Napierala */
5243914ddf8SEdward Tomasz Napierala sx_xlock(&anp->an_vnode_lock);
5253914ddf8SEdward Tomasz Napierala anp->an_vnode = NULL;
5263914ddf8SEdward Tomasz Napierala vp->v_data = NULL;
5273914ddf8SEdward Tomasz Napierala sx_xunlock(&anp->an_vnode_lock);
5283914ddf8SEdward Tomasz Napierala
5293914ddf8SEdward Tomasz Napierala return (0);
5303914ddf8SEdward Tomasz Napierala }
5313914ddf8SEdward Tomasz Napierala
5323914ddf8SEdward Tomasz Napierala struct vop_vector autofs_vnodeops = {
5333914ddf8SEdward Tomasz Napierala .vop_default = &default_vnodeops,
5343914ddf8SEdward Tomasz Napierala
5353914ddf8SEdward Tomasz Napierala .vop_access = autofs_access,
5363914ddf8SEdward Tomasz Napierala .vop_lookup = autofs_lookup,
5373914ddf8SEdward Tomasz Napierala .vop_create = VOP_EOPNOTSUPP,
5383914ddf8SEdward Tomasz Napierala .vop_getattr = autofs_getattr,
5393914ddf8SEdward Tomasz Napierala .vop_link = VOP_EOPNOTSUPP,
5403914ddf8SEdward Tomasz Napierala .vop_mkdir = autofs_mkdir,
5413914ddf8SEdward Tomasz Napierala .vop_mknod = VOP_EOPNOTSUPP,
542c1258254SEdward Tomasz Napierala .vop_print = autofs_print,
5433914ddf8SEdward Tomasz Napierala .vop_read = VOP_EOPNOTSUPP,
5443914ddf8SEdward Tomasz Napierala .vop_readdir = autofs_readdir,
5453914ddf8SEdward Tomasz Napierala .vop_remove = VOP_EOPNOTSUPP,
5463914ddf8SEdward Tomasz Napierala .vop_rename = VOP_EOPNOTSUPP,
5473914ddf8SEdward Tomasz Napierala .vop_rmdir = VOP_EOPNOTSUPP,
5483914ddf8SEdward Tomasz Napierala .vop_setattr = VOP_EOPNOTSUPP,
5493914ddf8SEdward Tomasz Napierala .vop_symlink = VOP_EOPNOTSUPP,
5503914ddf8SEdward Tomasz Napierala .vop_write = VOP_EOPNOTSUPP,
5513914ddf8SEdward Tomasz Napierala .vop_reclaim = autofs_reclaim,
5523914ddf8SEdward Tomasz Napierala };
5536fa079fcSMateusz Guzik VFS_VOP_VECTOR_REGISTER(autofs_vnodeops);
5543914ddf8SEdward Tomasz Napierala
5553914ddf8SEdward Tomasz Napierala int
autofs_node_new(struct autofs_node * parent,struct autofs_mount * amp,const char * name,int namelen,struct autofs_node ** anpp)5563914ddf8SEdward Tomasz Napierala autofs_node_new(struct autofs_node *parent, struct autofs_mount *amp,
5573914ddf8SEdward Tomasz Napierala const char *name, int namelen, struct autofs_node **anpp)
5583914ddf8SEdward Tomasz Napierala {
5593914ddf8SEdward Tomasz Napierala struct autofs_node *anp;
5603914ddf8SEdward Tomasz Napierala
5613e4adf76SEdward Tomasz Napierala if (parent != NULL) {
5622eaebf35SEdward Tomasz Napierala AUTOFS_ASSERT_XLOCKED(parent->an_mount);
5633914ddf8SEdward Tomasz Napierala
5643e4adf76SEdward Tomasz Napierala KASSERT(autofs_node_find(parent, name, namelen, NULL) == ENOENT,
5653e4adf76SEdward Tomasz Napierala ("node \"%s\" already exists", name));
5663e4adf76SEdward Tomasz Napierala }
5673e4adf76SEdward Tomasz Napierala
5683914ddf8SEdward Tomasz Napierala anp = uma_zalloc(autofs_node_zone, M_WAITOK | M_ZERO);
5693914ddf8SEdward Tomasz Napierala if (namelen >= 0)
5703914ddf8SEdward Tomasz Napierala anp->an_name = strndup(name, namelen, M_AUTOFS);
5713914ddf8SEdward Tomasz Napierala else
5723914ddf8SEdward Tomasz Napierala anp->an_name = strdup(name, M_AUTOFS);
5733914ddf8SEdward Tomasz Napierala anp->an_fileno = atomic_fetchadd_int(&->am_last_fileno, 1);
5743914ddf8SEdward Tomasz Napierala callout_init(&anp->an_callout, 1);
5753914ddf8SEdward Tomasz Napierala /*
5763914ddf8SEdward Tomasz Napierala * The reason for SX_NOWITNESS here is that witness(4)
5773914ddf8SEdward Tomasz Napierala * cannot tell vnodes apart, so the following perfectly
5783914ddf8SEdward Tomasz Napierala * valid lock order...
5793914ddf8SEdward Tomasz Napierala *
5803914ddf8SEdward Tomasz Napierala * vnode lock A -> autofsvlk B -> vnode lock B
5813914ddf8SEdward Tomasz Napierala *
5823914ddf8SEdward Tomasz Napierala * ... gets reported as a LOR.
5833914ddf8SEdward Tomasz Napierala */
5843914ddf8SEdward Tomasz Napierala sx_init_flags(&anp->an_vnode_lock, "autofsvlk", SX_NOWITNESS);
5853914ddf8SEdward Tomasz Napierala getnanotime(&anp->an_ctime);
5863914ddf8SEdward Tomasz Napierala anp->an_parent = parent;
5873914ddf8SEdward Tomasz Napierala anp->an_mount = amp;
5883914ddf8SEdward Tomasz Napierala if (parent != NULL)
58942ed64e3SEdward Tomasz Napierala RB_INSERT(autofs_node_tree, &parent->an_children, anp);
59042ed64e3SEdward Tomasz Napierala RB_INIT(&anp->an_children);
5913914ddf8SEdward Tomasz Napierala
5923914ddf8SEdward Tomasz Napierala *anpp = anp;
5933914ddf8SEdward Tomasz Napierala return (0);
5943914ddf8SEdward Tomasz Napierala }
5953914ddf8SEdward Tomasz Napierala
5963914ddf8SEdward Tomasz Napierala int
autofs_node_find(struct autofs_node * parent,const char * name,int namelen,struct autofs_node ** anpp)5973914ddf8SEdward Tomasz Napierala autofs_node_find(struct autofs_node *parent, const char *name,
5983914ddf8SEdward Tomasz Napierala int namelen, struct autofs_node **anpp)
5993914ddf8SEdward Tomasz Napierala {
60042ed64e3SEdward Tomasz Napierala struct autofs_node *anp, find;
60142ed64e3SEdward Tomasz Napierala int error;
6023914ddf8SEdward Tomasz Napierala
6033914ddf8SEdward Tomasz Napierala AUTOFS_ASSERT_LOCKED(parent->an_mount);
6043914ddf8SEdward Tomasz Napierala
60542ed64e3SEdward Tomasz Napierala if (namelen >= 0)
60642ed64e3SEdward Tomasz Napierala find.an_name = strndup(name, namelen, M_AUTOFS);
60742ed64e3SEdward Tomasz Napierala else
60842ed64e3SEdward Tomasz Napierala find.an_name = strdup(name, M_AUTOFS);
6093914ddf8SEdward Tomasz Napierala
61042ed64e3SEdward Tomasz Napierala anp = RB_FIND(autofs_node_tree, &parent->an_children, &find);
61142ed64e3SEdward Tomasz Napierala if (anp != NULL) {
61242ed64e3SEdward Tomasz Napierala error = 0;
6133914ddf8SEdward Tomasz Napierala if (anpp != NULL)
6143914ddf8SEdward Tomasz Napierala *anpp = anp;
61542ed64e3SEdward Tomasz Napierala } else {
61642ed64e3SEdward Tomasz Napierala error = ENOENT;
6173914ddf8SEdward Tomasz Napierala }
6183914ddf8SEdward Tomasz Napierala
61942ed64e3SEdward Tomasz Napierala free(find.an_name, M_AUTOFS);
62042ed64e3SEdward Tomasz Napierala
62142ed64e3SEdward Tomasz Napierala return (error);
6223914ddf8SEdward Tomasz Napierala }
6233914ddf8SEdward Tomasz Napierala
6243914ddf8SEdward Tomasz Napierala void
autofs_node_delete(struct autofs_node * anp)6253914ddf8SEdward Tomasz Napierala autofs_node_delete(struct autofs_node *anp)
6263914ddf8SEdward Tomasz Napierala {
6273914ddf8SEdward Tomasz Napierala struct autofs_node *parent;
6283914ddf8SEdward Tomasz Napierala
6292eaebf35SEdward Tomasz Napierala AUTOFS_ASSERT_XLOCKED(anp->an_mount);
63042ed64e3SEdward Tomasz Napierala KASSERT(RB_EMPTY(&anp->an_children), ("have children"));
6313914ddf8SEdward Tomasz Napierala
6323914ddf8SEdward Tomasz Napierala callout_drain(&anp->an_callout);
6333914ddf8SEdward Tomasz Napierala
6343914ddf8SEdward Tomasz Napierala parent = anp->an_parent;
6353914ddf8SEdward Tomasz Napierala if (parent != NULL)
63642ed64e3SEdward Tomasz Napierala RB_REMOVE(autofs_node_tree, &parent->an_children, anp);
6373914ddf8SEdward Tomasz Napierala sx_destroy(&anp->an_vnode_lock);
6383914ddf8SEdward Tomasz Napierala free(anp->an_name, M_AUTOFS);
6393914ddf8SEdward Tomasz Napierala uma_zfree(autofs_node_zone, anp);
6403914ddf8SEdward Tomasz Napierala }
6413914ddf8SEdward Tomasz Napierala
6423914ddf8SEdward Tomasz Napierala int
autofs_node_vn(struct autofs_node * anp,struct mount * mp,int flags,struct vnode ** vpp)643d19c297eSEdward Tomasz Napierala autofs_node_vn(struct autofs_node *anp, struct mount *mp, int flags,
644d19c297eSEdward Tomasz Napierala struct vnode **vpp)
6453914ddf8SEdward Tomasz Napierala {
6463914ddf8SEdward Tomasz Napierala struct vnode *vp;
6473914ddf8SEdward Tomasz Napierala int error;
6483914ddf8SEdward Tomasz Napierala
6493914ddf8SEdward Tomasz Napierala AUTOFS_ASSERT_UNLOCKED(anp->an_mount);
6503914ddf8SEdward Tomasz Napierala
6513914ddf8SEdward Tomasz Napierala sx_xlock(&anp->an_vnode_lock);
6523914ddf8SEdward Tomasz Napierala
6533914ddf8SEdward Tomasz Napierala vp = anp->an_vnode;
6543914ddf8SEdward Tomasz Napierala if (vp != NULL) {
655a92a971bSMateusz Guzik error = vget(vp, flags | LK_RETRY);
6563914ddf8SEdward Tomasz Napierala if (error != 0) {
6573914ddf8SEdward Tomasz Napierala AUTOFS_WARN("vget failed with error %d", error);
6583914ddf8SEdward Tomasz Napierala sx_xunlock(&anp->an_vnode_lock);
6593914ddf8SEdward Tomasz Napierala return (error);
6603914ddf8SEdward Tomasz Napierala }
661abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vp)) {
6623914ddf8SEdward Tomasz Napierala /*
6633914ddf8SEdward Tomasz Napierala * We got forcibly unmounted.
6643914ddf8SEdward Tomasz Napierala */
6653914ddf8SEdward Tomasz Napierala AUTOFS_DEBUG("doomed vnode");
6663914ddf8SEdward Tomasz Napierala sx_xunlock(&anp->an_vnode_lock);
6673914ddf8SEdward Tomasz Napierala vput(vp);
6683914ddf8SEdward Tomasz Napierala
6693914ddf8SEdward Tomasz Napierala return (ENOENT);
6703914ddf8SEdward Tomasz Napierala }
6713914ddf8SEdward Tomasz Napierala
6723914ddf8SEdward Tomasz Napierala *vpp = vp;
6733914ddf8SEdward Tomasz Napierala sx_xunlock(&anp->an_vnode_lock);
6743914ddf8SEdward Tomasz Napierala return (0);
6753914ddf8SEdward Tomasz Napierala }
6763914ddf8SEdward Tomasz Napierala
6773914ddf8SEdward Tomasz Napierala error = getnewvnode("autofs", mp, &autofs_vnodeops, &vp);
6783914ddf8SEdward Tomasz Napierala if (error != 0) {
6793914ddf8SEdward Tomasz Napierala sx_xunlock(&anp->an_vnode_lock);
6803914ddf8SEdward Tomasz Napierala return (error);
6813914ddf8SEdward Tomasz Napierala }
6823914ddf8SEdward Tomasz Napierala
68310aec599SMateusz Guzik vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
6843914ddf8SEdward Tomasz Napierala
6853914ddf8SEdward Tomasz Napierala vp->v_type = VDIR;
6863914ddf8SEdward Tomasz Napierala if (anp->an_parent == NULL)
6873914ddf8SEdward Tomasz Napierala vp->v_vflag |= VV_ROOT;
6883914ddf8SEdward Tomasz Napierala vp->v_data = anp;
6893914ddf8SEdward Tomasz Napierala
690d19c297eSEdward Tomasz Napierala VN_LOCK_ASHARE(vp);
691d19c297eSEdward Tomasz Napierala
6923914ddf8SEdward Tomasz Napierala error = insmntque(vp, mp);
6933914ddf8SEdward Tomasz Napierala if (error != 0) {
694e6350113SEdward Tomasz Napierala AUTOFS_DEBUG("insmntque() failed with error %d", error);
6953914ddf8SEdward Tomasz Napierala sx_xunlock(&anp->an_vnode_lock);
6963914ddf8SEdward Tomasz Napierala return (error);
6973914ddf8SEdward Tomasz Napierala }
6983914ddf8SEdward Tomasz Napierala
6993914ddf8SEdward Tomasz Napierala KASSERT(anp->an_vnode == NULL, ("lost race"));
7003914ddf8SEdward Tomasz Napierala anp->an_vnode = vp;
7013914ddf8SEdward Tomasz Napierala
7023914ddf8SEdward Tomasz Napierala sx_xunlock(&anp->an_vnode_lock);
7033914ddf8SEdward Tomasz Napierala
704829f0bcbSMateusz Guzik vn_set_state(vp, VSTATE_CONSTRUCTED);
7053914ddf8SEdward Tomasz Napierala *vpp = vp;
7063914ddf8SEdward Tomasz Napierala return (0);
7073914ddf8SEdward Tomasz Napierala }
708