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