xref: /netbsd-src/sys/fs/autofs/autofs_vfsops.c (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
1 /*-
2  * Copyright (c) 2017 The NetBSD Foundation, Inc.
3  * Copyright (c) 2016 The DragonFly Project
4  * Copyright (c) 2014 The FreeBSD Foundation
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Tomohiro Kusumi <kusumi.tomohiro@gmail.com>.
9  *
10  * This software was developed by Edward Tomasz Napierala under sponsorship
11  * from the FreeBSD Foundation.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: autofs_vfsops.c,v 1.4 2018/01/14 22:43:18 christos Exp $");
37 
38 
39 #include "autofs.h"
40 #include "autofs_mount.h"
41 
42 #include <sys/stat.h>
43 #include <sys/sysctl.h>
44 #include <miscfs/genfs/genfs.h>
45 
46 MODULE(MODULE_CLASS_VFS, autofs, NULL);
47 
48 static int	autofs_statvfs(struct mount *, struct statvfs *);
49 static int	autofs_sysctl_create(void);
50 
51 static void
52 autofs_init(void)
53 {
54 
55 	KASSERT(!autofs_softc);
56 
57 	autofs_softc = kmem_zalloc(sizeof(*autofs_softc), KM_SLEEP);
58 
59 	pool_init(&autofs_request_pool, sizeof(struct autofs_request), 0, 0, 0,
60 	    "autofs_request", &pool_allocator_nointr, IPL_NONE);
61 	pool_init(&autofs_node_pool, sizeof(struct autofs_node), 0, 0, 0,
62 	    "autofs_node", &pool_allocator_nointr, IPL_NONE);
63 
64 	TAILQ_INIT(&autofs_softc->sc_requests);
65 	cv_init(&autofs_softc->sc_cv, "autofscv");
66 	mutex_init(&autofs_softc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
67 	autofs_softc->sc_dev_opened = false;
68 
69 	autofs_sysctl_create();
70 	workqueue_create(&autofs_tmo_wq, "autofstmo",
71 	    autofs_timeout_wq, NULL, 0, 0, WQ_MPSAFE);
72 }
73 
74 static void
75 autofs_done(void)
76 {
77 	KASSERT(autofs_softc);
78 	KASSERT(!autofs_softc->sc_dev_opened);
79 
80 	workqueue_destroy(autofs_tmo_wq);
81 
82 	struct autofs_softc *sc = autofs_softc;
83 	autofs_softc = NULL;
84 
85 	cv_destroy(&sc->sc_cv);
86 	mutex_destroy(&sc->sc_lock);
87 
88 	pool_destroy(&autofs_request_pool);
89 	pool_destroy(&autofs_node_pool);
90 
91 	kmem_free(sc, sizeof(*sc));
92 }
93 
94 static int
95 autofs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
96 {
97 	struct autofs_args *args = data;
98 	struct autofs_mount *amp = VFSTOAUTOFS(mp);
99 	struct statvfs *sbp = &mp->mnt_stat;
100 	int error;
101 
102 	if (mp->mnt_flag & MNT_UPDATE) {
103 		if (amp == NULL)
104 			return EIO;
105 		autofs_flush(amp);
106 		return 0;
107 	}
108 
109 	if (!args)
110 		return EINVAL;
111 
112 	if (mp->mnt_flag & MNT_GETARGS) {
113 		if (amp == NULL)
114 			return EIO;
115 		error = copyoutstr(amp->am_from, args->from,
116 		    sizeof(amp->am_from), NULL);
117 		if (error)
118 			return error;
119 		error = copyoutstr(amp->am_options, args->master_options,
120 		    sizeof(amp->am_options), NULL);
121 		if (error)
122 			return error;
123 		error = copyoutstr(amp->am_prefix, args->master_prefix,
124 		    sizeof(amp->am_prefix), NULL);
125 		return error;
126 	}
127 
128 	if (amp != NULL)
129 		return EBUSY;
130 
131 	/*
132 	 * Allocate the autofs mount.
133 	 */
134 	amp = kmem_zalloc(sizeof(*amp), KM_SLEEP);
135 	mp->mnt_data = amp;
136 	amp->am_mp = mp;
137 
138 	/*
139 	 * Copy-in master_options string.
140 	 */
141 	error = copyinstr(args->master_options, amp->am_options,
142 	    sizeof(amp->am_options), NULL);
143 	if (error)
144 		goto fail;
145 
146 	/*
147 	 * Copy-in master_prefix string.
148 	 */
149 	error = copyinstr(args->master_prefix, amp->am_prefix,
150 	    sizeof(amp->am_prefix), NULL);
151 	if (error)
152 		goto fail;
153 
154 	/*
155 	 * Initialize the autofs mount.
156 	 */
157 	mutex_init(&amp->am_lock, MUTEX_DEFAULT, IPL_NONE);
158 	amp->am_last_ino = AUTOFS_ROOTINO;
159 
160 	mutex_enter(&amp->am_lock);
161 	error = autofs_node_new(NULL, amp, ".", -1, &amp->am_root);
162 	mutex_exit(&amp->am_lock);
163 	if (error)
164 		goto fail1;
165 	KASSERT(amp->am_root->an_ino == AUTOFS_ROOTINO);
166 
167 	autofs_statvfs(mp, sbp);
168 	vfs_getnewfsid(mp);
169 
170 	error = set_statvfs_info(path, UIO_USERSPACE, args->from, UIO_USERSPACE,
171 	    mp->mnt_op->vfs_name, mp, curlwp);
172 	if (error)
173 		goto fail1;
174 	strlcpy(amp->am_from, sbp->f_mntfromname, sizeof(amp->am_from));
175 	strlcpy(amp->am_on, sbp->f_mntonname, sizeof(amp->am_on));
176 
177 	return 0;
178 
179 fail1:
180 	mutex_destroy(&amp->am_lock);
181 fail:
182 	mp->mnt_data = NULL;
183 	kmem_free(amp, sizeof(*amp));
184 	return error;
185 }
186 
187 static int
188 autofs_unmount(struct mount *mp, int mntflags)
189 {
190 	struct autofs_mount *amp = VFSTOAUTOFS(mp);
191 	int error, flags;
192 
193 	flags = 0;
194 	if (mntflags & MNT_FORCE)
195 		flags |= FORCECLOSE;
196 	error = vflush(mp, NULL, flags);
197 	if (error) {
198 		AUTOFS_WARN("vflush failed with error %d", error);
199 		return error;
200 	}
201 
202 	/*
203 	 * All vnodes are gone, and new one will not appear - so,
204 	 * no new triggerings.
205 	 */
206 	for (;;) {
207 		struct autofs_request *ar;
208 		int dummy;
209 		bool found;
210 
211 		found = false;
212 		mutex_enter(&autofs_softc->sc_lock);
213 		TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
214 			if (ar->ar_mount != amp)
215 				continue;
216 			ar->ar_error = ENXIO;
217 			ar->ar_done = true;
218 			ar->ar_in_progress = false;
219 			found = true;
220 		}
221 		if (found == false) {
222 			mutex_exit(&autofs_softc->sc_lock);
223 			break;
224 		}
225 
226 		cv_broadcast(&autofs_softc->sc_cv);
227 		mutex_exit(&autofs_softc->sc_lock);
228 
229 		tsleep(&dummy, 0, "autofs_umount", hz);
230 	}
231 
232 	mutex_enter(&amp->am_lock);
233 	while (!RB_EMPTY(&amp->am_root->an_children)) {
234 		struct autofs_node *anp;
235 		anp = RB_MIN(autofs_node_tree, &amp->am_root->an_children);
236 		if (!RB_EMPTY(&anp->an_children)) {
237 			AUTOFS_DEBUG("%s: %s has children", __func__,
238 			    anp->an_name);
239 			mutex_exit(&amp->am_lock);
240 			return EBUSY;
241 		}
242 
243 		autofs_node_delete(anp);
244 	}
245 	autofs_node_delete(amp->am_root);
246 	mp->mnt_data = NULL;
247 	mutex_exit(&amp->am_lock);
248 
249 	mutex_destroy(&amp->am_lock);
250 
251 	kmem_free(amp, sizeof(*amp));
252 
253 	return 0;
254 }
255 
256 static int
257 autofs_start(struct mount *mp, int flags)
258 {
259 
260 	return 0;
261 }
262 
263 static int
264 autofs_root(struct mount *mp, struct vnode **vpp)
265 {
266 	struct autofs_node *anp = VFSTOAUTOFS(mp)->am_root;
267 	int error;
268 
269 	error = vcache_get(mp, &anp, sizeof(anp), vpp);
270 	if (error)
271 		return error;
272 	error = vn_lock(*vpp, LK_EXCLUSIVE);
273 	if (error) {
274 		vrele(*vpp);
275 		*vpp = NULL;
276 		return error;
277 	}
278 
279 	return 0;
280 }
281 
282 static int
283 autofs_statvfs(struct mount *mp, struct statvfs *sbp)
284 {
285 
286 	sbp->f_bsize = S_BLKSIZE;
287 	sbp->f_frsize = S_BLKSIZE;
288 	sbp->f_iosize = 0;
289 	sbp->f_blocks = 0;
290 	sbp->f_bfree = 0;
291 	sbp->f_bavail = 0;
292 	sbp->f_bresvd = 0;
293 	sbp->f_files = 0;
294 	sbp->f_ffree = 0;
295 	sbp->f_favail = 0;
296 	sbp->f_fresvd = 0;
297 
298 	copy_statvfs_info(sbp, mp);
299 
300 	return 0;
301 }
302 
303 static int
304 autofs_sync(struct mount *mp, int waitfor, kauth_cred_t uc)
305 {
306 
307 	return 0;
308 }
309 
310 static int
311 autofs_loadvnode(struct mount *mp, struct vnode *vp,
312     const void *key, size_t key_len, const void **new_key)
313 {
314 	struct autofs_node *anp;
315 
316 	KASSERT(key_len == sizeof(anp));
317 	memcpy(&anp, key, key_len);
318 	KASSERT(!anp->an_vnode);
319 
320 	vp->v_tag = VT_AUTOFS;
321 	vp->v_type = VDIR;
322 	vp->v_op = autofs_vnodeop_p;
323 	vp->v_data = anp;
324 
325 	if (anp->an_ino == AUTOFS_ROOTINO)
326 		vp->v_vflag |= VV_ROOT;
327 
328 	anp->an_vnode = vp;
329 	uvm_vnp_setsize(vp, 0);
330 
331 	*new_key = &vp->v_data;
332 
333 	return 0;
334 }
335 
336 static const struct vnodeopv_desc * const autofs_vnodeopv_descs[] = {
337 	&autofs_vnodeop_opv_desc,
338 	NULL,
339 };
340 
341 static struct vfsops autofs_vfsops = {
342 	.vfs_name = MOUNT_AUTOFS,
343 	.vfs_min_mount_data = sizeof(struct autofs_args),
344 	.vfs_mount = autofs_mount,
345 	.vfs_start = autofs_start,
346 	.vfs_unmount = autofs_unmount,
347 	.vfs_root = autofs_root,
348 	.vfs_quotactl = (void *)eopnotsupp,
349 	.vfs_statvfs = autofs_statvfs,
350 	.vfs_sync = autofs_sync,
351 	.vfs_vget = (void *)eopnotsupp,
352 	.vfs_loadvnode = (void *)autofs_loadvnode,
353 	.vfs_newvnode = (void *)eopnotsupp,
354 	.vfs_fhtovp = (void *)eopnotsupp,
355 	.vfs_vptofh = (void *)eopnotsupp,
356 	.vfs_init = autofs_init,
357 	.vfs_reinit = (void *)eopnotsupp,
358 	.vfs_done = autofs_done,
359 	.vfs_mountroot = (void *)eopnotsupp,
360 	.vfs_snapshot = (void *)eopnotsupp,
361 	.vfs_extattrctl = (void *)eopnotsupp,
362 	.vfs_suspendctl = (void *)genfs_suspendctl,
363 	.vfs_renamelock_enter = (void *)eopnotsupp,
364 	.vfs_renamelock_exit = (void *)eopnotsupp,
365 	.vfs_fsync = (void *)eopnotsupp,
366 	.vfs_opv_descs = autofs_vnodeopv_descs
367 };
368 
369 #define AUTOFS_SYSCTL_DEBUG		1
370 #define AUTOFS_SYSCTL_MOUNT_ON_STAT	2
371 #define AUTOFS_SYSCTL_TIMEOUT		3
372 #define AUTOFS_SYSCTL_CACHE		4
373 #define AUTOFS_SYSCTL_RETRY_ATTEMPTS	5
374 #define AUTOFS_SYSCTL_RETRY_DELAY	6
375 #define AUTOFS_SYSCTL_INTERRUPTIBLE	7
376 
377 static struct sysctllog *autofs_sysctl_log;
378 
379 static int
380 autofs_sysctl_create(void)
381 {
382 	int error;
383 
384 	/*
385 	 * XXX the "33" below could be dynamic, thereby eliminating one
386 	 * more instance of the "number to vfs" mapping problem, but
387 	 * "33" is the order as taken from sys/mount.h
388 	 */
389 	error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL,
390 	    CTLFLAG_PERMANENT,
391 	    CTLTYPE_NODE, "autofs",
392 	    SYSCTL_DESCR("Automounter filesystem"),
393 	    NULL, 0, NULL, 0,
394 	    CTL_VFS, 33, CTL_EOL);
395 	if (error)
396 		goto fail;
397 
398 	error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL,
399 	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
400 	    CTLTYPE_INT, "autofs_debug",
401 	    SYSCTL_DESCR("Enable debug messages"),
402 	    NULL, 0, &autofs_debug, 0,
403 	    CTL_VFS, 33, AUTOFS_SYSCTL_DEBUG, CTL_EOL);
404 	if (error)
405 		goto fail;
406 
407 	error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL,
408 	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
409 	    CTLTYPE_INT, "autofs_mount_on_stat",
410 	    SYSCTL_DESCR("Trigger mount on stat(2) on mountpoint"),
411 	    NULL, 0, &autofs_mount_on_stat, 0,
412 	    CTL_VFS, 33, AUTOFS_SYSCTL_MOUNT_ON_STAT, CTL_EOL);
413 	if (error)
414 		goto fail;
415 
416 	error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL,
417 	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
418 	    CTLTYPE_INT, "autofs_timeout",
419 	    SYSCTL_DESCR("Number of seconds to wait for automountd(8)"),
420 	    NULL, 0, &autofs_timeout, 0,
421 	    CTL_VFS, 33, AUTOFS_SYSCTL_TIMEOUT, CTL_EOL);
422 	if (error)
423 		goto fail;
424 
425 	error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL,
426 	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
427 	    CTLTYPE_INT, "autofs_cache",
428 	    SYSCTL_DESCR("Number of seconds to wait before reinvoking"),
429 	    NULL, 0, &autofs_cache, 0,
430 	    CTL_VFS, 33, AUTOFS_SYSCTL_CACHE, CTL_EOL);
431 	if (error)
432 		goto fail;
433 
434 	error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL,
435 	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
436 	    CTLTYPE_INT, "autofs_retry_attempts",
437 	    SYSCTL_DESCR("Number of attempts before failing mount"),
438 	    NULL, 0, &autofs_retry_attempts, 0,
439 	    CTL_VFS, 33, AUTOFS_SYSCTL_RETRY_ATTEMPTS, CTL_EOL);
440 	if (error)
441 		goto fail;
442 
443 	error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL,
444 	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
445 	    CTLTYPE_INT, "autofs_retry_delay",
446 	    SYSCTL_DESCR("Number of seconds before retrying"),
447 	    NULL, 0, &autofs_retry_delay, 0,
448 	    CTL_VFS, 33, AUTOFS_SYSCTL_RETRY_DELAY, CTL_EOL);
449 	if (error)
450 		goto fail;
451 
452 	error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL,
453 	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
454 	    CTLTYPE_INT, "autofs_interruptible",
455 	    SYSCTL_DESCR("Allow requests to be interrupted by signal"),
456 	    NULL, 0, &autofs_interruptible, 0,
457 	    CTL_VFS, 33, AUTOFS_SYSCTL_INTERRUPTIBLE, CTL_EOL);
458 	if (error)
459 		goto fail;
460 
461 	return 0;
462 fail:
463 	AUTOFS_WARN("sysctl_createv failed with error %d", error);
464 
465 	return error;
466 }
467 
468 extern const struct cdevsw autofs_cdevsw;
469 
470 static int
471 autofs_modcmd(modcmd_t cmd, void *arg)
472 {
473 #ifdef _MODULE
474 	devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR;
475 #endif
476 	int error = 0;
477 
478 	switch (cmd) {
479 	case MODULE_CMD_INIT:
480 		error = vfs_attach(&autofs_vfsops);
481 		if (error)
482 			break;
483 #ifdef _MODULE
484 		error = devsw_attach("autofs", NULL, &bmajor, &autofs_cdevsw,
485 		    &cmajor);
486 		if (error) {
487 			vfs_detach(&autofs_vfsops);
488 			break;
489 		}
490 #endif
491 		break;
492 	case MODULE_CMD_FINI:
493 #ifdef _MODULE
494 		KASSERT(autofs_softc);
495 		mutex_enter(&autofs_softc->sc_lock);
496 		if (autofs_softc->sc_dev_opened) {
497 			mutex_exit(&autofs_softc->sc_lock);
498 			error = EBUSY;
499 			break;
500 		}
501 		mutex_exit(&autofs_softc->sc_lock);
502 
503 		error = devsw_detach(NULL, &autofs_cdevsw);
504 		if (error)
505 			break;
506 #endif
507 		error = vfs_detach(&autofs_vfsops);
508 		if (error)
509 			break;
510 		break;
511 	default:
512 		error = ENOTTY;
513 		break;
514 	}
515 
516 	return error;
517 }
518