1e2950f41STomohiro Kusumi /*-
2*63bc4984STomohiro Kusumi * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*63bc4984STomohiro Kusumi *
449837aefSTomohiro Kusumi * Copyright (c) 2016 Tomohiro Kusumi <tkusumi@netbsd.org>
5e2950f41STomohiro Kusumi * Copyright (c) 2016 The DragonFly Project
6e2950f41STomohiro Kusumi * Copyright (c) 2014 The FreeBSD Foundation
7e2950f41STomohiro Kusumi * All rights reserved.
8e2950f41STomohiro Kusumi *
9e2950f41STomohiro Kusumi * This software was developed by Edward Tomasz Napierala under sponsorship
10e2950f41STomohiro Kusumi * from the FreeBSD Foundation.
11e2950f41STomohiro Kusumi *
12e2950f41STomohiro Kusumi * Redistribution and use in source and binary forms, with or without
13e2950f41STomohiro Kusumi * modification, are permitted provided that the following conditions
14e2950f41STomohiro Kusumi * are met:
15e2950f41STomohiro Kusumi * 1. Redistributions of source code must retain the above copyright
16e2950f41STomohiro Kusumi * notice, this list of conditions and the following disclaimer.
17e2950f41STomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright
18e2950f41STomohiro Kusumi * notice, this list of conditions and the following disclaimer in the
19e2950f41STomohiro Kusumi * documentation and/or other materials provided with the distribution.
20e2950f41STomohiro Kusumi *
21e2950f41STomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22e2950f41STomohiro Kusumi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23e2950f41STomohiro Kusumi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24e2950f41STomohiro Kusumi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25e2950f41STomohiro Kusumi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26e2950f41STomohiro Kusumi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27e2950f41STomohiro Kusumi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28e2950f41STomohiro Kusumi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29e2950f41STomohiro Kusumi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30e2950f41STomohiro Kusumi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31e2950f41STomohiro Kusumi * SUCH DAMAGE.
32e2950f41STomohiro Kusumi *
33e2950f41STomohiro Kusumi */
34e2950f41STomohiro Kusumi
35e2950f41STomohiro Kusumi #include <sys/kernel.h>
36e2950f41STomohiro Kusumi #include <sys/module.h>
37e2950f41STomohiro Kusumi #include <sys/stat.h>
38e2950f41STomohiro Kusumi
39e2950f41STomohiro Kusumi #include "autofs.h"
40e2950f41STomohiro Kusumi #include "autofs_mount.h"
41e2950f41STomohiro Kusumi
42e2950f41STomohiro Kusumi static int autofs_statfs(struct mount *mp, struct statfs *sbp,
43e2950f41STomohiro Kusumi struct ucred *cred);
44e2950f41STomohiro Kusumi
45add630f0STomohiro Kusumi static struct objcache_malloc_args autofs_request_args = {
46add630f0STomohiro Kusumi sizeof(struct autofs_request), M_AUTOFS,
47add630f0STomohiro Kusumi };
48add630f0STomohiro Kusumi static struct objcache_malloc_args autofs_node_args = {
49add630f0STomohiro Kusumi sizeof(struct autofs_node), M_AUTOFS,
50add630f0STomohiro Kusumi };
51add630f0STomohiro Kusumi
52add630f0STomohiro Kusumi static int
autofs_init(struct vfsconf * vfsp)53add630f0STomohiro Kusumi autofs_init(struct vfsconf *vfsp)
54add630f0STomohiro Kusumi {
55add630f0STomohiro Kusumi KASSERT(autofs_softc == NULL,
56add630f0STomohiro Kusumi ("softc %p, should be NULL", autofs_softc));
57add630f0STomohiro Kusumi
58add630f0STomohiro Kusumi autofs_softc = kmalloc(sizeof(*autofs_softc), M_AUTOFS,
59add630f0STomohiro Kusumi M_WAITOK | M_ZERO);
60add630f0STomohiro Kusumi
61add630f0STomohiro Kusumi autofs_request_objcache = objcache_create("autofs_request", 0, 0,
62a5dfdd2bSTomohiro Kusumi NULL, NULL, NULL,
6374565ee0STomohiro Kusumi objcache_malloc_alloc_zero, objcache_malloc_free,
64add630f0STomohiro Kusumi &autofs_request_args);
65add630f0STomohiro Kusumi
66add630f0STomohiro Kusumi autofs_node_objcache = objcache_create("autofs_node", 0, 0,
67a5dfdd2bSTomohiro Kusumi NULL, NULL, NULL,
6874565ee0STomohiro Kusumi objcache_malloc_alloc_zero, objcache_malloc_free,
69add630f0STomohiro Kusumi &autofs_node_args);
70add630f0STomohiro Kusumi
71add630f0STomohiro Kusumi TAILQ_INIT(&autofs_softc->sc_requests);
72add630f0STomohiro Kusumi cv_init(&autofs_softc->sc_cv, "autofscv");
732137724aSTomohiro Kusumi mtx_init(&autofs_softc->sc_lock, "autofssclk");
74add630f0STomohiro Kusumi autofs_softc->sc_dev_opened = false;
75add630f0STomohiro Kusumi
7674565ee0STomohiro Kusumi autofs_softc->sc_cdev = make_dev(&autofs_ops, 0, UID_ROOT, GID_OPERATOR,
7774565ee0STomohiro Kusumi 0640, "autofs");
78add630f0STomohiro Kusumi if (autofs_softc->sc_cdev == NULL) {
79add630f0STomohiro Kusumi AUTOFS_WARN("failed to create device node");
80add630f0STomohiro Kusumi objcache_destroy(autofs_request_objcache);
81add630f0STomohiro Kusumi objcache_destroy(autofs_node_objcache);
82add630f0STomohiro Kusumi kfree(autofs_softc, M_AUTOFS);
83add630f0STomohiro Kusumi return (ENODEV);
84add630f0STomohiro Kusumi }
85add630f0STomohiro Kusumi autofs_softc->sc_cdev->si_drv1 = autofs_softc;
86add630f0STomohiro Kusumi
87add630f0STomohiro Kusumi return (0);
88add630f0STomohiro Kusumi }
89add630f0STomohiro Kusumi
90add630f0STomohiro Kusumi static int
autofs_uninit(struct vfsconf * vfsp)91add630f0STomohiro Kusumi autofs_uninit(struct vfsconf *vfsp)
92add630f0STomohiro Kusumi {
932137724aSTomohiro Kusumi mtx_lock_ex_quick(&autofs_softc->sc_lock);
94add630f0STomohiro Kusumi if (autofs_softc->sc_dev_opened) {
952137724aSTomohiro Kusumi mtx_unlock_ex(&autofs_softc->sc_lock);
96add630f0STomohiro Kusumi return (EBUSY);
97add630f0STomohiro Kusumi }
98add630f0STomohiro Kusumi
99add630f0STomohiro Kusumi if (autofs_softc->sc_cdev != NULL)
100add630f0STomohiro Kusumi destroy_dev(autofs_softc->sc_cdev);
101add630f0STomohiro Kusumi
102add630f0STomohiro Kusumi objcache_destroy(autofs_request_objcache);
103add630f0STomohiro Kusumi objcache_destroy(autofs_node_objcache);
104add630f0STomohiro Kusumi
1052137724aSTomohiro Kusumi mtx_unlock_ex(&autofs_softc->sc_lock);
106add630f0STomohiro Kusumi
107add630f0STomohiro Kusumi kfree(autofs_softc, M_AUTOFS); /* race with open */
108add630f0STomohiro Kusumi autofs_softc = NULL;
109add630f0STomohiro Kusumi
110add630f0STomohiro Kusumi return (0);
111add630f0STomohiro Kusumi }
112e2950f41STomohiro Kusumi
113e2950f41STomohiro Kusumi static int
autofs_mount(struct mount * mp,char * mntpt,caddr_t data,struct ucred * cred)114e2950f41STomohiro Kusumi autofs_mount(struct mount *mp, char *mntpt, caddr_t data, struct ucred *cred)
115e2950f41STomohiro Kusumi {
116e2950f41STomohiro Kusumi struct autofs_mount_info info;
117e2950f41STomohiro Kusumi struct autofs_mount *amp;
118e2950f41STomohiro Kusumi struct statfs *sbp = &mp->mnt_stat;
119e2950f41STomohiro Kusumi int error;
120e2950f41STomohiro Kusumi
121e2950f41STomohiro Kusumi if (mp->mnt_flag & MNT_UPDATE) {
122e2950f41STomohiro Kusumi autofs_flush(VFSTOAUTOFS(mp));
123e2950f41STomohiro Kusumi return (0);
124e2950f41STomohiro Kusumi }
125e2950f41STomohiro Kusumi
126e2950f41STomohiro Kusumi error = copyin(data, &info, sizeof(info));
127e2950f41STomohiro Kusumi if (error)
128e2950f41STomohiro Kusumi return (error);
129e2950f41STomohiro Kusumi
13052d8539fSTomohiro Kusumi /*
13152d8539fSTomohiro Kusumi * Copy-in ->f_mntfromname string.
13252d8539fSTomohiro Kusumi */
133e2950f41STomohiro Kusumi memset(sbp->f_mntfromname, 0, sizeof(sbp->f_mntfromname));
134e2950f41STomohiro Kusumi error = copyinstr(info.from, sbp->f_mntfromname,
135e2950f41STomohiro Kusumi sizeof(sbp->f_mntfromname), NULL);
136e2950f41STomohiro Kusumi if (error)
137e2950f41STomohiro Kusumi return (error);
13852d8539fSTomohiro Kusumi /*
13952d8539fSTomohiro Kusumi * Copy-in ->f_mntonname string.
14052d8539fSTomohiro Kusumi */
141e2950f41STomohiro Kusumi memset(sbp->f_mntonname, 0, sizeof(sbp->f_mntonname));
14274565ee0STomohiro Kusumi error = copyinstr(mntpt, sbp->f_mntonname, sizeof(sbp->f_mntonname),
14374565ee0STomohiro Kusumi NULL);
144e2950f41STomohiro Kusumi if (error)
145e2950f41STomohiro Kusumi return (error);
146e2950f41STomohiro Kusumi
14752d8539fSTomohiro Kusumi /*
14852d8539fSTomohiro Kusumi * Allocate the autofs mount.
14952d8539fSTomohiro Kusumi */
150e2950f41STomohiro Kusumi amp = kmalloc(sizeof(*amp), M_AUTOFS, M_WAITOK | M_ZERO);
151e2950f41STomohiro Kusumi mp->mnt_data = (qaddr_t)amp;
152e2950f41STomohiro Kusumi strlcpy(amp->am_from, sbp->f_mntfromname, sizeof(amp->am_from));
153e2950f41STomohiro Kusumi strlcpy(amp->am_on, sbp->f_mntonname, sizeof(amp->am_on));
154e2950f41STomohiro Kusumi
15552d8539fSTomohiro Kusumi /*
15652d8539fSTomohiro Kusumi * Copy-in master_options string.
15752d8539fSTomohiro Kusumi */
15852d8539fSTomohiro Kusumi error = copyinstr(info.master_options, amp->am_options,
15952d8539fSTomohiro Kusumi sizeof(amp->am_options), NULL);
160e2950f41STomohiro Kusumi if (error)
161e2950f41STomohiro Kusumi goto fail;
16252d8539fSTomohiro Kusumi /*
16352d8539fSTomohiro Kusumi * Copy-in master_prefix string.
16452d8539fSTomohiro Kusumi */
16552d8539fSTomohiro Kusumi error = copyinstr(info.master_prefix, amp->am_prefix,
16652d8539fSTomohiro Kusumi sizeof(amp->am_prefix), NULL);
167e2950f41STomohiro Kusumi if (error)
168e2950f41STomohiro Kusumi goto fail;
169e2950f41STomohiro Kusumi
17052d8539fSTomohiro Kusumi /*
17152d8539fSTomohiro Kusumi * Initialize the autofs mount.
17252d8539fSTomohiro Kusumi */
173bc6139d4STomohiro Kusumi mtx_init(&->am_lock, "autofsmnlk");
174e2950f41STomohiro Kusumi amp->am_last_ino = AUTOFS_ROOTINO;
175e2950f41STomohiro Kusumi
176bc6139d4STomohiro Kusumi mtx_lock_ex_quick(&->am_lock);
177e2950f41STomohiro Kusumi error = autofs_node_new(NULL, amp, ".", -1, &->am_root);
178bc6139d4STomohiro Kusumi mtx_unlock_ex(&->am_lock);
179e2950f41STomohiro Kusumi KKASSERT(error == 0);
180e2950f41STomohiro Kusumi KKASSERT(amp->am_root->an_ino == AUTOFS_ROOTINO);
181e2950f41STomohiro Kusumi
182636b9358STomohiro Kusumi vfs_getnewfsid(mp);
183636b9358STomohiro Kusumi vfs_add_vnodeops(mp, &autofs_vnode_vops, &mp->mnt_vn_norm_ops);
184636b9358STomohiro Kusumi
185aa2533c1STomohiro Kusumi VFS_STATFS(mp, &mp->mnt_stat, cred);
186e2950f41STomohiro Kusumi
187e2950f41STomohiro Kusumi return (0);
188e2950f41STomohiro Kusumi
189e2950f41STomohiro Kusumi fail:
190e2950f41STomohiro Kusumi kfree(amp, M_AUTOFS);
191e2950f41STomohiro Kusumi return (error);
192e2950f41STomohiro Kusumi }
193e2950f41STomohiro Kusumi
194e2950f41STomohiro Kusumi static int
autofs_unmount(struct mount * mp,int mntflags)195e2950f41STomohiro Kusumi autofs_unmount(struct mount *mp, int mntflags)
196e2950f41STomohiro Kusumi {
197e2950f41STomohiro Kusumi struct autofs_mount *amp = VFSTOAUTOFS(mp);
198662e8088STomohiro Kusumi int error, flags;
199e2950f41STomohiro Kusumi
200e2950f41STomohiro Kusumi flags = 0;
201e2950f41STomohiro Kusumi if (mntflags & MNT_FORCE)
202e2950f41STomohiro Kusumi flags |= FORCECLOSE;
203e2950f41STomohiro Kusumi error = vflush(mp, 0, flags);
204e2950f41STomohiro Kusumi if (error) {
20570c400cbSTomohiro Kusumi AUTOFS_DEBUG("vflush failed with error %d", error);
206e2950f41STomohiro Kusumi return (error);
207e2950f41STomohiro Kusumi }
208e2950f41STomohiro Kusumi
209e2950f41STomohiro Kusumi /*
210e2950f41STomohiro Kusumi * All vnodes are gone, and new one will not appear - so,
211e2950f41STomohiro Kusumi * no new triggerings.
212e2950f41STomohiro Kusumi */
213e2950f41STomohiro Kusumi for (;;) {
214662e8088STomohiro Kusumi struct autofs_request *ar;
215662e8088STomohiro Kusumi int dummy;
216662e8088STomohiro Kusumi bool found;
217662e8088STomohiro Kusumi
218e2950f41STomohiro Kusumi found = false;
2192137724aSTomohiro Kusumi mtx_lock_ex_quick(&autofs_softc->sc_lock);
220e2950f41STomohiro Kusumi TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
221e2950f41STomohiro Kusumi if (ar->ar_mount != amp)
222e2950f41STomohiro Kusumi continue;
223e2950f41STomohiro Kusumi ar->ar_error = ENXIO;
224e2950f41STomohiro Kusumi ar->ar_done = true;
225e2950f41STomohiro Kusumi ar->ar_in_progress = false;
226e2950f41STomohiro Kusumi found = true;
227e2950f41STomohiro Kusumi }
228e2950f41STomohiro Kusumi if (found == false) {
2292137724aSTomohiro Kusumi mtx_unlock_ex(&autofs_softc->sc_lock);
230e2950f41STomohiro Kusumi break;
231e2950f41STomohiro Kusumi }
232e2950f41STomohiro Kusumi
233e2950f41STomohiro Kusumi cv_broadcast(&autofs_softc->sc_cv);
2342137724aSTomohiro Kusumi mtx_unlock_ex(&autofs_softc->sc_lock);
235e2950f41STomohiro Kusumi
236e2950f41STomohiro Kusumi tsleep(&dummy, 0, "autofs_umount", hz);
237e2950f41STomohiro Kusumi }
238e2950f41STomohiro Kusumi
239bc6139d4STomohiro Kusumi mtx_lock_ex_quick(&->am_lock);
240e2950f41STomohiro Kusumi while (!RB_EMPTY(&->am_root->an_children)) {
241662e8088STomohiro Kusumi struct autofs_node *anp;
24207235526STomohiro Kusumi /*
24307235526STomohiro Kusumi * Force delete all nodes when more than one level of
24407235526STomohiro Kusumi * directories are created via indirect map. Autofs doesn't
24507235526STomohiro Kusumi * support rmdir(2), thus this is the only way to get out.
24607235526STomohiro Kusumi */
247e2950f41STomohiro Kusumi anp = RB_MIN(autofs_node_tree, &->am_root->an_children);
24807235526STomohiro Kusumi while (!RB_EMPTY(&anp->an_children))
24907235526STomohiro Kusumi anp = RB_MIN(autofs_node_tree, &anp->an_children);
250e2950f41STomohiro Kusumi autofs_node_delete(anp);
251e2950f41STomohiro Kusumi }
252e2950f41STomohiro Kusumi autofs_node_delete(amp->am_root);
253e2950f41STomohiro Kusumi mp->mnt_data = NULL;
254bc6139d4STomohiro Kusumi mtx_unlock_ex(&->am_lock);
255e2950f41STomohiro Kusumi
256bc6139d4STomohiro Kusumi mtx_uninit(&->am_lock);
257e2950f41STomohiro Kusumi
258e2950f41STomohiro Kusumi kfree(amp, M_AUTOFS);
259e2950f41STomohiro Kusumi
260e2950f41STomohiro Kusumi return (0);
261e2950f41STomohiro Kusumi }
262e2950f41STomohiro Kusumi
263e2950f41STomohiro Kusumi static int
autofs_root(struct mount * mp,struct vnode ** vpp)264e2950f41STomohiro Kusumi autofs_root(struct mount *mp, struct vnode **vpp)
265e2950f41STomohiro Kusumi {
266e2950f41STomohiro Kusumi struct autofs_mount *amp = VFSTOAUTOFS(mp);
267e2950f41STomohiro Kusumi int error;
268e2950f41STomohiro Kusumi
269d3e56a2aSTomohiro Kusumi KASSERT(amp->am_root, ("no root node"));
270d3e56a2aSTomohiro Kusumi
271e2950f41STomohiro Kusumi error = autofs_node_vn(amp->am_root, mp, LK_EXCLUSIVE, vpp);
272f94d0241STomohiro Kusumi if (error == 0) {
273f94d0241STomohiro Kusumi struct vnode *vp = *vpp;
274f94d0241STomohiro Kusumi vp->v_flag |= VROOT;
275f94d0241STomohiro Kusumi KKASSERT(vp->v_type == VDIR);
276f94d0241STomohiro Kusumi }
277e2950f41STomohiro Kusumi
278e2950f41STomohiro Kusumi return (error);
279e2950f41STomohiro Kusumi }
280e2950f41STomohiro Kusumi
281e2950f41STomohiro Kusumi static int
autofs_statfs(struct mount * mp,struct statfs * sbp,struct ucred * cred)282e2950f41STomohiro Kusumi autofs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
283e2950f41STomohiro Kusumi {
284e2950f41STomohiro Kusumi sbp->f_bsize = S_BLKSIZE;
285e2950f41STomohiro Kusumi sbp->f_iosize = 0;
286e2950f41STomohiro Kusumi sbp->f_blocks = 0;
287e2950f41STomohiro Kusumi sbp->f_bfree = 0;
288e2950f41STomohiro Kusumi sbp->f_bavail = 0;
289e2950f41STomohiro Kusumi sbp->f_files = 0;
290e2950f41STomohiro Kusumi sbp->f_ffree = 0;
291e2950f41STomohiro Kusumi
292e2950f41STomohiro Kusumi return (0);
293e2950f41STomohiro Kusumi }
294e2950f41STomohiro Kusumi
295e2950f41STomohiro Kusumi static int
autofs_statvfs(struct mount * mp,struct statvfs * sbp,struct ucred * cred)296e2950f41STomohiro Kusumi autofs_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
297e2950f41STomohiro Kusumi {
298e2950f41STomohiro Kusumi sbp->f_bsize = S_BLKSIZE;
299e2950f41STomohiro Kusumi sbp->f_frsize = 0;
300e2950f41STomohiro Kusumi sbp->f_blocks = 0;
301e2950f41STomohiro Kusumi sbp->f_bfree = 0;
302e2950f41STomohiro Kusumi sbp->f_bavail = 0;
303e2950f41STomohiro Kusumi sbp->f_files = 0;
304e2950f41STomohiro Kusumi sbp->f_ffree = 0;
305e2950f41STomohiro Kusumi
306e2950f41STomohiro Kusumi return (0);
307e2950f41STomohiro Kusumi }
308e2950f41STomohiro Kusumi
309e2950f41STomohiro Kusumi static struct vfsops autofs_vfsops = {
31000369c4aSMatthew Dillon .vfs_flags = 0,
311e2950f41STomohiro Kusumi .vfs_mount = autofs_mount,
312e2950f41STomohiro Kusumi .vfs_unmount = autofs_unmount,
313e2950f41STomohiro Kusumi .vfs_root = autofs_root,
314e2950f41STomohiro Kusumi .vfs_statfs = autofs_statfs,
315e2950f41STomohiro Kusumi .vfs_statvfs = autofs_statvfs,
316e2950f41STomohiro Kusumi .vfs_init = autofs_init,
317e2950f41STomohiro Kusumi .vfs_uninit = autofs_uninit,
318e2950f41STomohiro Kusumi };
319e2950f41STomohiro Kusumi
32097db17b9STomohiro Kusumi VFS_SET(autofs_vfsops, autofs, VFCF_SYNTHETIC | VFCF_MPSAFE);
321e2950f41STomohiro Kusumi MODULE_VERSION(autofs, 1);
322