xref: /freebsd/sys/fs/autofs/autofs_vfsops.c (revision 18dffafade16edcbc7f021f53c1c34f35ac2cfa8)
13914ddf8SEdward Tomasz Napierala /*-
2*18dffafaSEdward Tomasz Napierala  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*18dffafaSEdward Tomasz Napierala  *
43914ddf8SEdward Tomasz Napierala  * Copyright (c) 2014 The FreeBSD Foundation
53914ddf8SEdward Tomasz Napierala  * All rights reserved.
63914ddf8SEdward Tomasz Napierala  *
73914ddf8SEdward Tomasz Napierala  * This software was developed by Edward Tomasz Napierala under sponsorship
83914ddf8SEdward Tomasz Napierala  * from the FreeBSD Foundation.
93914ddf8SEdward Tomasz Napierala  *
103914ddf8SEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
113914ddf8SEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
123914ddf8SEdward Tomasz Napierala  * are met:
133914ddf8SEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
143914ddf8SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer.
153914ddf8SEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
163914ddf8SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
173914ddf8SEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
183914ddf8SEdward Tomasz Napierala  *
193914ddf8SEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
203914ddf8SEdward Tomasz Napierala  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
213914ddf8SEdward Tomasz Napierala  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
223914ddf8SEdward Tomasz Napierala  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
233914ddf8SEdward Tomasz Napierala  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
243914ddf8SEdward Tomasz Napierala  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
253914ddf8SEdward Tomasz Napierala  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
263914ddf8SEdward Tomasz Napierala  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
273914ddf8SEdward Tomasz Napierala  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
283914ddf8SEdward Tomasz Napierala  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
293914ddf8SEdward Tomasz Napierala  * SUCH DAMAGE.
303914ddf8SEdward Tomasz Napierala  *
313914ddf8SEdward Tomasz Napierala  */
323914ddf8SEdward Tomasz Napierala 
33925fd945SEdward Tomasz Napierala #include <sys/cdefs.h>
34925fd945SEdward Tomasz Napierala  __FBSDID("$FreeBSD$");
35925fd945SEdward Tomasz Napierala 
363914ddf8SEdward Tomasz Napierala #include <sys/param.h>
373914ddf8SEdward Tomasz Napierala #include <sys/systm.h>
383914ddf8SEdward Tomasz Napierala #include <sys/conf.h>
393914ddf8SEdward Tomasz Napierala #include <sys/condvar.h>
403914ddf8SEdward Tomasz Napierala #include <sys/ioccom.h>
413914ddf8SEdward Tomasz Napierala #include <sys/kernel.h>
423914ddf8SEdward Tomasz Napierala #include <sys/module.h>
433914ddf8SEdward Tomasz Napierala #include <sys/mount.h>
447571d313SEdward Tomasz Napierala #include <sys/stat.h>
453914ddf8SEdward Tomasz Napierala #include <sys/sx.h>
46759489f9SEdward Tomasz Napierala #include <sys/taskqueue.h>
4742ed64e3SEdward Tomasz Napierala #include <sys/tree.h>
483914ddf8SEdward Tomasz Napierala #include <sys/vnode.h>
493914ddf8SEdward Tomasz Napierala 
50f5440d1aSEdward Tomasz Napierala #include <fs/autofs/autofs.h>
513914ddf8SEdward Tomasz Napierala 
523914ddf8SEdward Tomasz Napierala static const char *autofs_opts[] = {
533914ddf8SEdward Tomasz Napierala 	"from", "master_options", "master_prefix", NULL
543914ddf8SEdward Tomasz Napierala };
553914ddf8SEdward Tomasz Napierala 
56f81018caSEdward Tomasz Napierala extern struct autofs_softc	*autofs_softc;
573914ddf8SEdward Tomasz Napierala 
583914ddf8SEdward Tomasz Napierala static int
593914ddf8SEdward Tomasz Napierala autofs_mount(struct mount *mp)
603914ddf8SEdward Tomasz Napierala {
613914ddf8SEdward Tomasz Napierala 	struct autofs_mount *amp;
623914ddf8SEdward Tomasz Napierala 	char *from, *fspath, *options, *prefix;
633914ddf8SEdward Tomasz Napierala 	int error;
643914ddf8SEdward Tomasz Napierala 
653914ddf8SEdward Tomasz Napierala 	if (vfs_filteropt(mp->mnt_optnew, autofs_opts))
663914ddf8SEdward Tomasz Napierala 		return (EINVAL);
673914ddf8SEdward Tomasz Napierala 
68e3d5f1feSEdward Tomasz Napierala 	if (mp->mnt_flag & MNT_UPDATE) {
69e3d5f1feSEdward Tomasz Napierala 		autofs_flush(VFSTOAUTOFS(mp));
703914ddf8SEdward Tomasz Napierala 		return (0);
71e3d5f1feSEdward Tomasz Napierala 	}
723914ddf8SEdward Tomasz Napierala 
733914ddf8SEdward Tomasz Napierala 	if (vfs_getopt(mp->mnt_optnew, "from", (void **)&from, NULL))
743914ddf8SEdward Tomasz Napierala 		return (EINVAL);
753914ddf8SEdward Tomasz Napierala 
763914ddf8SEdward Tomasz Napierala 	if (vfs_getopt(mp->mnt_optnew, "fspath", (void **)&fspath, NULL))
773914ddf8SEdward Tomasz Napierala 		return (EINVAL);
783914ddf8SEdward Tomasz Napierala 
793914ddf8SEdward Tomasz Napierala 	if (vfs_getopt(mp->mnt_optnew, "master_options", (void **)&options, NULL))
803914ddf8SEdward Tomasz Napierala 		return (EINVAL);
813914ddf8SEdward Tomasz Napierala 
823914ddf8SEdward Tomasz Napierala 	if (vfs_getopt(mp->mnt_optnew, "master_prefix", (void **)&prefix, NULL))
833914ddf8SEdward Tomasz Napierala 		return (EINVAL);
843914ddf8SEdward Tomasz Napierala 
853914ddf8SEdward Tomasz Napierala 	amp = malloc(sizeof(*amp), M_AUTOFS, M_WAITOK | M_ZERO);
863914ddf8SEdward Tomasz Napierala 	mp->mnt_data = amp;
873914ddf8SEdward Tomasz Napierala 	amp->am_mp = mp;
883914ddf8SEdward Tomasz Napierala 	strlcpy(amp->am_from, from, sizeof(amp->am_from));
893914ddf8SEdward Tomasz Napierala 	strlcpy(amp->am_mountpoint, fspath, sizeof(amp->am_mountpoint));
903914ddf8SEdward Tomasz Napierala 	strlcpy(amp->am_options, options, sizeof(amp->am_options));
913914ddf8SEdward Tomasz Napierala 	strlcpy(amp->am_prefix, prefix, sizeof(amp->am_prefix));
923914ddf8SEdward Tomasz Napierala 	sx_init(&amp->am_lock, "autofslk");
933914ddf8SEdward Tomasz Napierala 	amp->am_last_fileno = 1;
943914ddf8SEdward Tomasz Napierala 
953914ddf8SEdward Tomasz Napierala 	vfs_getnewfsid(mp);
963914ddf8SEdward Tomasz Napierala 
97d19c297eSEdward Tomasz Napierala 	MNT_ILOCK(mp);
98d19c297eSEdward Tomasz Napierala 	mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED;
99d19c297eSEdward Tomasz Napierala 	MNT_IUNLOCK(mp);
100d19c297eSEdward Tomasz Napierala 
1012eaebf35SEdward Tomasz Napierala 	AUTOFS_XLOCK(amp);
1023914ddf8SEdward Tomasz Napierala 	error = autofs_node_new(NULL, amp, ".", -1, &amp->am_root);
1033914ddf8SEdward Tomasz Napierala 	if (error != 0) {
1042eaebf35SEdward Tomasz Napierala 		AUTOFS_XUNLOCK(amp);
1053914ddf8SEdward Tomasz Napierala 		free(amp, M_AUTOFS);
1063914ddf8SEdward Tomasz Napierala 		return (error);
1073914ddf8SEdward Tomasz Napierala 	}
1082eaebf35SEdward Tomasz Napierala 	AUTOFS_XUNLOCK(amp);
1093914ddf8SEdward Tomasz Napierala 
1103914ddf8SEdward Tomasz Napierala 	vfs_mountedfrom(mp, from);
1113914ddf8SEdward Tomasz Napierala 
1123914ddf8SEdward Tomasz Napierala 	return (0);
1133914ddf8SEdward Tomasz Napierala }
1143914ddf8SEdward Tomasz Napierala 
1153914ddf8SEdward Tomasz Napierala static int
1163914ddf8SEdward Tomasz Napierala autofs_unmount(struct mount *mp, int mntflags)
1173914ddf8SEdward Tomasz Napierala {
1183914ddf8SEdward Tomasz Napierala 	struct autofs_mount *amp;
1193914ddf8SEdward Tomasz Napierala 	struct autofs_node *anp;
1203914ddf8SEdward Tomasz Napierala 	struct autofs_request *ar;
1213914ddf8SEdward Tomasz Napierala 	int error, flags;
1223914ddf8SEdward Tomasz Napierala 	bool found;
1233914ddf8SEdward Tomasz Napierala 
1243914ddf8SEdward Tomasz Napierala 	amp = VFSTOAUTOFS(mp);
1253914ddf8SEdward Tomasz Napierala 
1263914ddf8SEdward Tomasz Napierala 	flags = 0;
1273914ddf8SEdward Tomasz Napierala 	if (mntflags & MNT_FORCE)
1283914ddf8SEdward Tomasz Napierala 		flags |= FORCECLOSE;
1293914ddf8SEdward Tomasz Napierala 	error = vflush(mp, 0, flags, curthread);
1303914ddf8SEdward Tomasz Napierala 	if (error != 0) {
1313914ddf8SEdward Tomasz Napierala 		AUTOFS_WARN("vflush failed with error %d", error);
1323914ddf8SEdward Tomasz Napierala 		return (error);
1333914ddf8SEdward Tomasz Napierala 	}
1343914ddf8SEdward Tomasz Napierala 
1353914ddf8SEdward Tomasz Napierala 	/*
1363914ddf8SEdward Tomasz Napierala 	 * All vnodes are gone, and new one will not appear - so,
1373914ddf8SEdward Tomasz Napierala 	 * no new triggerings.  We can iterate over outstanding
1383914ddf8SEdward Tomasz Napierala 	 * autofs_requests and terminate them.
1393914ddf8SEdward Tomasz Napierala 	 */
1403914ddf8SEdward Tomasz Napierala 	for (;;) {
1413914ddf8SEdward Tomasz Napierala 		found = false;
142f81018caSEdward Tomasz Napierala 		sx_xlock(&autofs_softc->sc_lock);
143f81018caSEdward Tomasz Napierala 		TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
1443914ddf8SEdward Tomasz Napierala 			if (ar->ar_mount != amp)
1453914ddf8SEdward Tomasz Napierala 				continue;
1463914ddf8SEdward Tomasz Napierala 			ar->ar_error = ENXIO;
1473914ddf8SEdward Tomasz Napierala 			ar->ar_done = true;
1483914ddf8SEdward Tomasz Napierala 			ar->ar_in_progress = false;
1493914ddf8SEdward Tomasz Napierala 			found = true;
1503914ddf8SEdward Tomasz Napierala 		}
151f81018caSEdward Tomasz Napierala 		sx_xunlock(&autofs_softc->sc_lock);
1523914ddf8SEdward Tomasz Napierala 		if (found == false)
1533914ddf8SEdward Tomasz Napierala 			break;
1543914ddf8SEdward Tomasz Napierala 
155f81018caSEdward Tomasz Napierala 		cv_broadcast(&autofs_softc->sc_cv);
1563914ddf8SEdward Tomasz Napierala 		pause("autofs_umount", 1);
1573914ddf8SEdward Tomasz Napierala 	}
1583914ddf8SEdward Tomasz Napierala 
1592eaebf35SEdward Tomasz Napierala 	AUTOFS_XLOCK(amp);
1603914ddf8SEdward Tomasz Napierala 
1613914ddf8SEdward Tomasz Napierala 	/*
1623914ddf8SEdward Tomasz Napierala 	 * Not terribly efficient, but at least not recursive.
1633914ddf8SEdward Tomasz Napierala 	 */
16442ed64e3SEdward Tomasz Napierala 	while (!RB_EMPTY(&amp->am_root->an_children)) {
16542ed64e3SEdward Tomasz Napierala 		anp = RB_MIN(autofs_node_tree, &amp->am_root->an_children);
16642ed64e3SEdward Tomasz Napierala 		while (!RB_EMPTY(&anp->an_children))
16742ed64e3SEdward Tomasz Napierala 			anp = RB_MIN(autofs_node_tree, &anp->an_children);
1683914ddf8SEdward Tomasz Napierala 		autofs_node_delete(anp);
1693914ddf8SEdward Tomasz Napierala 	}
1703914ddf8SEdward Tomasz Napierala 	autofs_node_delete(amp->am_root);
1713914ddf8SEdward Tomasz Napierala 
1723914ddf8SEdward Tomasz Napierala 	mp->mnt_data = NULL;
1732eaebf35SEdward Tomasz Napierala 	AUTOFS_XUNLOCK(amp);
1743914ddf8SEdward Tomasz Napierala 
1753914ddf8SEdward Tomasz Napierala 	sx_destroy(&amp->am_lock);
1763914ddf8SEdward Tomasz Napierala 
1773914ddf8SEdward Tomasz Napierala 	free(amp, M_AUTOFS);
1783914ddf8SEdward Tomasz Napierala 
1793914ddf8SEdward Tomasz Napierala 	return (0);
1803914ddf8SEdward Tomasz Napierala }
1813914ddf8SEdward Tomasz Napierala 
1823914ddf8SEdward Tomasz Napierala static int
1833914ddf8SEdward Tomasz Napierala autofs_root(struct mount *mp, int flags, struct vnode **vpp)
1843914ddf8SEdward Tomasz Napierala {
1853914ddf8SEdward Tomasz Napierala 	struct autofs_mount *amp;
1863914ddf8SEdward Tomasz Napierala 	int error;
1873914ddf8SEdward Tomasz Napierala 
1883914ddf8SEdward Tomasz Napierala 	amp = VFSTOAUTOFS(mp);
1893914ddf8SEdward Tomasz Napierala 
190d19c297eSEdward Tomasz Napierala 	error = autofs_node_vn(amp->am_root, mp, flags, vpp);
1913914ddf8SEdward Tomasz Napierala 
1923914ddf8SEdward Tomasz Napierala 	return (error);
1933914ddf8SEdward Tomasz Napierala }
1943914ddf8SEdward Tomasz Napierala 
1953914ddf8SEdward Tomasz Napierala static int
1963914ddf8SEdward Tomasz Napierala autofs_statfs(struct mount *mp, struct statfs *sbp)
1973914ddf8SEdward Tomasz Napierala {
1983914ddf8SEdward Tomasz Napierala 
1997571d313SEdward Tomasz Napierala 	sbp->f_bsize = S_BLKSIZE;
2003914ddf8SEdward Tomasz Napierala 	sbp->f_iosize = 0;
2013914ddf8SEdward Tomasz Napierala 	sbp->f_blocks = 0;
2023914ddf8SEdward Tomasz Napierala 	sbp->f_bfree = 0;
2033914ddf8SEdward Tomasz Napierala 	sbp->f_bavail = 0;
2043914ddf8SEdward Tomasz Napierala 	sbp->f_files = 0;
2053914ddf8SEdward Tomasz Napierala 	sbp->f_ffree = 0;
2063914ddf8SEdward Tomasz Napierala 
2073914ddf8SEdward Tomasz Napierala 	return (0);
2083914ddf8SEdward Tomasz Napierala }
2093914ddf8SEdward Tomasz Napierala 
2103914ddf8SEdward Tomasz Napierala static struct vfsops autofs_vfsops = {
2113914ddf8SEdward Tomasz Napierala 	.vfs_fhtovp =		NULL, /* XXX */
2123914ddf8SEdward Tomasz Napierala 	.vfs_mount =		autofs_mount,
2133914ddf8SEdward Tomasz Napierala 	.vfs_unmount =		autofs_unmount,
2143914ddf8SEdward Tomasz Napierala 	.vfs_root =		autofs_root,
2153914ddf8SEdward Tomasz Napierala 	.vfs_statfs =		autofs_statfs,
2163914ddf8SEdward Tomasz Napierala 	.vfs_init =		autofs_init,
2173914ddf8SEdward Tomasz Napierala 	.vfs_uninit =		autofs_uninit,
2183914ddf8SEdward Tomasz Napierala };
2193914ddf8SEdward Tomasz Napierala 
2203914ddf8SEdward Tomasz Napierala VFS_SET(autofs_vfsops, autofs, VFCF_SYNTHETIC | VFCF_NETWORK);
2213914ddf8SEdward Tomasz Napierala MODULE_VERSION(autofs, 1);
222