xref: /freebsd-src/sys/fs/autofs/autofs_vnops.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
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(&amp->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