xref: /freebsd/sys/fs/autofs/autofs_vfsops.c (revision dfc016587a1e11191676c42672aeeee5eb8cd64b)
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 
32925fd945SEdward Tomasz Napierala 
333914ddf8SEdward Tomasz Napierala #include <sys/param.h>
343914ddf8SEdward Tomasz Napierala #include <sys/systm.h>
353914ddf8SEdward Tomasz Napierala #include <sys/conf.h>
363914ddf8SEdward Tomasz Napierala #include <sys/condvar.h>
373914ddf8SEdward Tomasz Napierala #include <sys/ioccom.h>
383914ddf8SEdward Tomasz Napierala #include <sys/kernel.h>
393914ddf8SEdward Tomasz Napierala #include <sys/module.h>
403914ddf8SEdward Tomasz Napierala #include <sys/mount.h>
417571d313SEdward Tomasz Napierala #include <sys/stat.h>
423914ddf8SEdward Tomasz Napierala #include <sys/sx.h>
43759489f9SEdward Tomasz Napierala #include <sys/taskqueue.h>
4442ed64e3SEdward Tomasz Napierala #include <sys/tree.h>
453914ddf8SEdward Tomasz Napierala #include <sys/vnode.h>
463914ddf8SEdward Tomasz Napierala 
47f5440d1aSEdward Tomasz Napierala #include <fs/autofs/autofs.h>
483914ddf8SEdward Tomasz Napierala 
493914ddf8SEdward Tomasz Napierala static const char *autofs_opts[] = {
503914ddf8SEdward Tomasz Napierala 	"from", "master_options", "master_prefix", NULL
513914ddf8SEdward Tomasz Napierala };
523914ddf8SEdward Tomasz Napierala 
53f81018caSEdward Tomasz Napierala extern struct autofs_softc	*autofs_softc;
543914ddf8SEdward Tomasz Napierala 
553914ddf8SEdward Tomasz Napierala static int
autofs_mount(struct mount * mp)563914ddf8SEdward Tomasz Napierala autofs_mount(struct mount *mp)
573914ddf8SEdward Tomasz Napierala {
583914ddf8SEdward Tomasz Napierala 	struct autofs_mount *amp;
593914ddf8SEdward Tomasz Napierala 	char *from, *fspath, *options, *prefix;
603914ddf8SEdward Tomasz Napierala 	int error;
613914ddf8SEdward Tomasz Napierala 
623914ddf8SEdward Tomasz Napierala 	if (vfs_filteropt(mp->mnt_optnew, autofs_opts))
633914ddf8SEdward Tomasz Napierala 		return (EINVAL);
643914ddf8SEdward Tomasz Napierala 
65e3d5f1feSEdward Tomasz Napierala 	if (mp->mnt_flag & MNT_UPDATE) {
66e3d5f1feSEdward Tomasz Napierala 		autofs_flush(VFSTOAUTOFS(mp));
673914ddf8SEdward Tomasz Napierala 		return (0);
68e3d5f1feSEdward Tomasz Napierala 	}
693914ddf8SEdward Tomasz Napierala 
703914ddf8SEdward Tomasz Napierala 	if (vfs_getopt(mp->mnt_optnew, "from", (void **)&from, NULL))
713914ddf8SEdward Tomasz Napierala 		return (EINVAL);
723914ddf8SEdward Tomasz Napierala 
733914ddf8SEdward Tomasz Napierala 	if (vfs_getopt(mp->mnt_optnew, "fspath", (void **)&fspath, NULL))
743914ddf8SEdward Tomasz Napierala 		return (EINVAL);
753914ddf8SEdward Tomasz Napierala 
763914ddf8SEdward Tomasz Napierala 	if (vfs_getopt(mp->mnt_optnew, "master_options", (void **)&options, NULL))
773914ddf8SEdward Tomasz Napierala 		return (EINVAL);
783914ddf8SEdward Tomasz Napierala 
793914ddf8SEdward Tomasz Napierala 	if (vfs_getopt(mp->mnt_optnew, "master_prefix", (void **)&prefix, NULL))
803914ddf8SEdward Tomasz Napierala 		return (EINVAL);
813914ddf8SEdward Tomasz Napierala 
823914ddf8SEdward Tomasz Napierala 	amp = malloc(sizeof(*amp), M_AUTOFS, M_WAITOK | M_ZERO);
833914ddf8SEdward Tomasz Napierala 	mp->mnt_data = amp;
843914ddf8SEdward Tomasz Napierala 	amp->am_mp = mp;
853914ddf8SEdward Tomasz Napierala 	strlcpy(amp->am_from, from, sizeof(amp->am_from));
863914ddf8SEdward Tomasz Napierala 	strlcpy(amp->am_mountpoint, fspath, sizeof(amp->am_mountpoint));
873914ddf8SEdward Tomasz Napierala 	strlcpy(amp->am_options, options, sizeof(amp->am_options));
883914ddf8SEdward Tomasz Napierala 	strlcpy(amp->am_prefix, prefix, sizeof(amp->am_prefix));
893914ddf8SEdward Tomasz Napierala 	sx_init(&amp->am_lock, "autofslk");
903914ddf8SEdward Tomasz Napierala 	amp->am_last_fileno = 1;
913914ddf8SEdward Tomasz Napierala 
923914ddf8SEdward Tomasz Napierala 	vfs_getnewfsid(mp);
933914ddf8SEdward Tomasz Napierala 
94d19c297eSEdward Tomasz Napierala 	MNT_ILOCK(mp);
95d19c297eSEdward Tomasz Napierala 	mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED;
96d19c297eSEdward Tomasz Napierala 	MNT_IUNLOCK(mp);
97d19c297eSEdward Tomasz Napierala 
982eaebf35SEdward Tomasz Napierala 	AUTOFS_XLOCK(amp);
993914ddf8SEdward Tomasz Napierala 	error = autofs_node_new(NULL, amp, ".", -1, &amp->am_root);
1003914ddf8SEdward Tomasz Napierala 	if (error != 0) {
1012eaebf35SEdward Tomasz Napierala 		AUTOFS_XUNLOCK(amp);
1023914ddf8SEdward Tomasz Napierala 		free(amp, M_AUTOFS);
1033914ddf8SEdward Tomasz Napierala 		return (error);
1043914ddf8SEdward Tomasz Napierala 	}
1052eaebf35SEdward Tomasz Napierala 	AUTOFS_XUNLOCK(amp);
1063914ddf8SEdward Tomasz Napierala 
1073914ddf8SEdward Tomasz Napierala 	vfs_mountedfrom(mp, from);
1083914ddf8SEdward Tomasz Napierala 
1093914ddf8SEdward Tomasz Napierala 	return (0);
1103914ddf8SEdward Tomasz Napierala }
1113914ddf8SEdward Tomasz Napierala 
1123914ddf8SEdward Tomasz Napierala static int
autofs_unmount(struct mount * mp,int mntflags)1133914ddf8SEdward Tomasz Napierala autofs_unmount(struct mount *mp, int mntflags)
1143914ddf8SEdward Tomasz Napierala {
1153914ddf8SEdward Tomasz Napierala 	struct autofs_mount *amp;
1163914ddf8SEdward Tomasz Napierala 	struct autofs_node *anp;
1173914ddf8SEdward Tomasz Napierala 	struct autofs_request *ar;
1183914ddf8SEdward Tomasz Napierala 	int error, flags;
1193914ddf8SEdward Tomasz Napierala 	bool found;
1203914ddf8SEdward Tomasz Napierala 
1213914ddf8SEdward Tomasz Napierala 	amp = VFSTOAUTOFS(mp);
1223914ddf8SEdward Tomasz Napierala 
1233914ddf8SEdward Tomasz Napierala 	flags = 0;
1243914ddf8SEdward Tomasz Napierala 	if (mntflags & MNT_FORCE)
1253914ddf8SEdward Tomasz Napierala 		flags |= FORCECLOSE;
1263914ddf8SEdward Tomasz Napierala 	error = vflush(mp, 0, flags, curthread);
1273914ddf8SEdward Tomasz Napierala 	if (error != 0) {
128d499502dSEdward Tomasz Napierala 		AUTOFS_DEBUG("vflush failed with error %d", error);
1293914ddf8SEdward Tomasz Napierala 		return (error);
1303914ddf8SEdward Tomasz Napierala 	}
1313914ddf8SEdward Tomasz Napierala 
1323914ddf8SEdward Tomasz Napierala 	/*
1333914ddf8SEdward Tomasz Napierala 	 * All vnodes are gone, and new one will not appear - so,
1343914ddf8SEdward Tomasz Napierala 	 * no new triggerings.  We can iterate over outstanding
1353914ddf8SEdward Tomasz Napierala 	 * autofs_requests and terminate them.
1363914ddf8SEdward Tomasz Napierala 	 */
1373914ddf8SEdward Tomasz Napierala 	for (;;) {
1383914ddf8SEdward Tomasz Napierala 		found = false;
139f81018caSEdward Tomasz Napierala 		sx_xlock(&autofs_softc->sc_lock);
140f81018caSEdward Tomasz Napierala 		TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
1413914ddf8SEdward Tomasz Napierala 			if (ar->ar_mount != amp)
1423914ddf8SEdward Tomasz Napierala 				continue;
1433914ddf8SEdward Tomasz Napierala 			ar->ar_error = ENXIO;
1443914ddf8SEdward Tomasz Napierala 			ar->ar_done = true;
1453914ddf8SEdward Tomasz Napierala 			ar->ar_in_progress = false;
1463914ddf8SEdward Tomasz Napierala 			found = true;
1473914ddf8SEdward Tomasz Napierala 		}
148f81018caSEdward Tomasz Napierala 		sx_xunlock(&autofs_softc->sc_lock);
1493914ddf8SEdward Tomasz Napierala 		if (found == false)
1503914ddf8SEdward Tomasz Napierala 			break;
1513914ddf8SEdward Tomasz Napierala 
152f81018caSEdward Tomasz Napierala 		cv_broadcast(&autofs_softc->sc_cv);
1533914ddf8SEdward Tomasz Napierala 		pause("autofs_umount", 1);
1543914ddf8SEdward Tomasz Napierala 	}
1553914ddf8SEdward Tomasz Napierala 
1562eaebf35SEdward Tomasz Napierala 	AUTOFS_XLOCK(amp);
1573914ddf8SEdward Tomasz Napierala 
1583914ddf8SEdward Tomasz Napierala 	/*
1593914ddf8SEdward Tomasz Napierala 	 * Not terribly efficient, but at least not recursive.
1603914ddf8SEdward Tomasz Napierala 	 */
16142ed64e3SEdward Tomasz Napierala 	while (!RB_EMPTY(&amp->am_root->an_children)) {
16242ed64e3SEdward Tomasz Napierala 		anp = RB_MIN(autofs_node_tree, &amp->am_root->an_children);
16342ed64e3SEdward Tomasz Napierala 		while (!RB_EMPTY(&anp->an_children))
16442ed64e3SEdward Tomasz Napierala 			anp = RB_MIN(autofs_node_tree, &anp->an_children);
1653914ddf8SEdward Tomasz Napierala 		autofs_node_delete(anp);
1663914ddf8SEdward Tomasz Napierala 	}
1673914ddf8SEdward Tomasz Napierala 	autofs_node_delete(amp->am_root);
1683914ddf8SEdward Tomasz Napierala 
1693914ddf8SEdward Tomasz Napierala 	mp->mnt_data = NULL;
1702eaebf35SEdward Tomasz Napierala 	AUTOFS_XUNLOCK(amp);
1713914ddf8SEdward Tomasz Napierala 
1723914ddf8SEdward Tomasz Napierala 	sx_destroy(&amp->am_lock);
1733914ddf8SEdward Tomasz Napierala 
1743914ddf8SEdward Tomasz Napierala 	free(amp, M_AUTOFS);
1753914ddf8SEdward Tomasz Napierala 
1763914ddf8SEdward Tomasz Napierala 	return (0);
1773914ddf8SEdward Tomasz Napierala }
1783914ddf8SEdward Tomasz Napierala 
1793914ddf8SEdward Tomasz Napierala static int
autofs_root(struct mount * mp,int flags,struct vnode ** vpp)1803914ddf8SEdward Tomasz Napierala autofs_root(struct mount *mp, int flags, struct vnode **vpp)
1813914ddf8SEdward Tomasz Napierala {
1823914ddf8SEdward Tomasz Napierala 	struct autofs_mount *amp;
1833914ddf8SEdward Tomasz Napierala 	int error;
1843914ddf8SEdward Tomasz Napierala 
1853914ddf8SEdward Tomasz Napierala 	amp = VFSTOAUTOFS(mp);
1863914ddf8SEdward Tomasz Napierala 
187d19c297eSEdward Tomasz Napierala 	error = autofs_node_vn(amp->am_root, mp, flags, vpp);
1883914ddf8SEdward Tomasz Napierala 
1893914ddf8SEdward Tomasz Napierala 	return (error);
1903914ddf8SEdward Tomasz Napierala }
1913914ddf8SEdward Tomasz Napierala 
1923914ddf8SEdward Tomasz Napierala static int
autofs_statfs(struct mount * mp,struct statfs * sbp)1933914ddf8SEdward Tomasz Napierala autofs_statfs(struct mount *mp, struct statfs *sbp)
1943914ddf8SEdward Tomasz Napierala {
1953914ddf8SEdward Tomasz Napierala 
1967571d313SEdward Tomasz Napierala 	sbp->f_bsize = S_BLKSIZE;
1973914ddf8SEdward Tomasz Napierala 	sbp->f_iosize = 0;
1983914ddf8SEdward Tomasz Napierala 	sbp->f_blocks = 0;
1993914ddf8SEdward Tomasz Napierala 	sbp->f_bfree = 0;
2003914ddf8SEdward Tomasz Napierala 	sbp->f_bavail = 0;
2013914ddf8SEdward Tomasz Napierala 	sbp->f_files = 0;
2023914ddf8SEdward Tomasz Napierala 	sbp->f_ffree = 0;
2033914ddf8SEdward Tomasz Napierala 
2043914ddf8SEdward Tomasz Napierala 	return (0);
2053914ddf8SEdward Tomasz Napierala }
2063914ddf8SEdward Tomasz Napierala 
2073914ddf8SEdward Tomasz Napierala static struct vfsops autofs_vfsops = {
2083914ddf8SEdward Tomasz Napierala 	.vfs_fhtovp =		NULL, /* XXX */
2093914ddf8SEdward Tomasz Napierala 	.vfs_mount =		autofs_mount,
2103914ddf8SEdward Tomasz Napierala 	.vfs_unmount =		autofs_unmount,
2113914ddf8SEdward Tomasz Napierala 	.vfs_root =		autofs_root,
2123914ddf8SEdward Tomasz Napierala 	.vfs_statfs =		autofs_statfs,
2133914ddf8SEdward Tomasz Napierala 	.vfs_init =		autofs_init,
2143914ddf8SEdward Tomasz Napierala 	.vfs_uninit =		autofs_uninit,
2153914ddf8SEdward Tomasz Napierala };
2163914ddf8SEdward Tomasz Napierala 
2173914ddf8SEdward Tomasz Napierala VFS_SET(autofs_vfsops, autofs, VFCF_SYNTHETIC | VFCF_NETWORK);
2183914ddf8SEdward Tomasz Napierala MODULE_VERSION(autofs, 1);
219