autofs.c revision 270096
1/*-
2 * Copyright (c) 2014 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Edward Tomasz Napierala under sponsorship
6 * from the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sys/fs/autofs/autofs.c 270096 2014-08-17 09:44:42Z trasz $
30 */
31/*-
32 * Copyright (c) 1989, 1991, 1993, 1995
33 *	The Regents of the University of California.  All rights reserved.
34 *
35 * This code is derived from software contributed to Berkeley by
36 * Rick Macklem at The University of Guelph.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 *    notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 *    notice, this list of conditions and the following disclaimer in the
45 *    documentation and/or other materials provided with the distribution.
46 * 4. Neither the name of the University nor the names of its contributors
47 *    may be used to endorse or promote products derived from this software
48 *    without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 */
63
64#include <sys/param.h>
65#include <sys/systm.h>
66#include <sys/buf.h>
67#include <sys/conf.h>
68#include <sys/dirent.h>
69#include <sys/ioccom.h>
70#include <sys/kernel.h>
71#include <sys/module.h>
72#include <sys/mount.h>
73#include <sys/refcount.h>
74#include <sys/sx.h>
75#include <sys/sysctl.h>
76#include <sys/syscallsubr.h>
77#include <sys/vnode.h>
78#include <machine/atomic.h>
79#include <vm/uma.h>
80
81#include "autofs.h"
82#include "autofs_ioctl.h"
83
84MALLOC_DEFINE(M_AUTOFS, "autofs", "Automounter filesystem");
85
86uma_zone_t autofs_request_zone;
87uma_zone_t autofs_node_zone;
88
89static int	autofs_open(struct cdev *dev, int flags, int fmt,
90		    struct thread *td);
91static int	autofs_close(struct cdev *dev, int flag, int fmt,
92		    struct thread *td);
93static int	autofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg,
94		    int mode, struct thread *td);
95
96static struct cdevsw autofs_cdevsw = {
97     .d_version = D_VERSION,
98     .d_open   = autofs_open,
99     .d_close   = autofs_close,
100     .d_ioctl   = autofs_ioctl,
101     .d_name    = "autofs",
102};
103
104/*
105 * List of signals that can interrupt an autofs trigger.  Might be a good
106 * idea to keep it synchronised with list in sys/fs/nfs/nfs_commonkrpc.c.
107 */
108int autofs_sig_set[] = {
109	SIGINT,
110	SIGTERM,
111	SIGHUP,
112	SIGKILL,
113	SIGQUIT
114};
115
116struct autofs_softc	*sc;
117
118SYSCTL_NODE(_vfs, OID_AUTO, autofs, CTLFLAG_RD, 0, "Automounter filesystem");
119int autofs_debug = 1;
120TUNABLE_INT("vfs.autofs.debug", &autofs_debug);
121SYSCTL_INT(_vfs_autofs, OID_AUTO, debug, CTLFLAG_RWTUN,
122    &autofs_debug, 1, "Enable debug messages");
123int autofs_mount_on_stat = 0;
124TUNABLE_INT("vfs.autofs.mount_on_stat", &autofs_mount_on_stat);
125SYSCTL_INT(_vfs_autofs, OID_AUTO, mount_on_stat, CTLFLAG_RWTUN,
126    &autofs_mount_on_stat, 0, "Trigger mount on stat(2) on mountpoint");
127int autofs_timeout = 30;
128TUNABLE_INT("vfs.autofs.timeout", &autofs_timeout);
129SYSCTL_INT(_vfs_autofs, OID_AUTO, timeout, CTLFLAG_RWTUN,
130    &autofs_timeout, 30, "Number of seconds to wait for automountd(8)");
131int autofs_cache = 600;
132TUNABLE_INT("vfs.autofs.cache", &autofs_cache);
133SYSCTL_INT(_vfs_autofs, OID_AUTO, cache, CTLFLAG_RWTUN,
134    &autofs_cache, 600, "Number of seconds to wait before reinvoking "
135    "automountd(8) for any given file or directory");
136int autofs_retry_attempts = 3;
137TUNABLE_INT("vfs.autofs.retry_attempts", &autofs_retry_attempts);
138SYSCTL_INT(_vfs_autofs, OID_AUTO, retry_attempts, CTLFLAG_RWTUN,
139    &autofs_retry_attempts, 3, "Number of attempts before failing mount");
140int autofs_retry_delay = 1;
141TUNABLE_INT("vfs.autofs.retry_delay", &autofs_retry_delay);
142SYSCTL_INT(_vfs_autofs, OID_AUTO, retry_delay, CTLFLAG_RWTUN,
143    &autofs_retry_delay, 1, "Number of seconds before retrying");
144int autofs_interruptible = 1;
145TUNABLE_INT("vfs.autofs.interruptible", &autofs_interruptible);
146SYSCTL_INT(_vfs_autofs, OID_AUTO, interruptible, CTLFLAG_RWTUN,
147    &autofs_interruptible, 1, "Allow requests to be interrupted by signal");
148
149int
150autofs_init(struct vfsconf *vfsp)
151{
152	int error;
153
154	sc = malloc(sizeof(*sc), M_AUTOFS, M_WAITOK | M_ZERO);
155
156	autofs_request_zone = uma_zcreate("autofs_request",
157	    sizeof(struct autofs_request), NULL, NULL, NULL, NULL,
158	    UMA_ALIGN_PTR, 0);
159	autofs_node_zone = uma_zcreate("autofs_node",
160	    sizeof(struct autofs_node), NULL, NULL, NULL, NULL,
161	    UMA_ALIGN_PTR, 0);
162
163	TAILQ_INIT(&sc->sc_requests);
164	cv_init(&sc->sc_cv, "autofscv");
165	sx_init(&sc->sc_lock, "autofslk");
166
167	error = make_dev_p(MAKEDEV_CHECKNAME, &sc->sc_cdev, &autofs_cdevsw,
168	    NULL, UID_ROOT, GID_WHEEL, 0600, "autofs");
169	if (error != 0) {
170		AUTOFS_WARN("failed to create device node, error %d", error);
171		free(sc, M_AUTOFS);
172		return (error);
173	}
174	sc->sc_cdev->si_drv1 = sc;
175
176	return (0);
177}
178
179int
180autofs_uninit(struct vfsconf *vfsp)
181{
182
183	sx_xlock(&sc->sc_lock);
184	if (sc->sc_dev_opened) {
185		sx_xunlock(&sc->sc_lock);
186		return (EBUSY);
187	}
188	if (sc->sc_cdev != NULL)
189		destroy_dev(sc->sc_cdev);
190
191	uma_zdestroy(autofs_request_zone);
192	uma_zdestroy(autofs_node_zone);
193
194	sx_xunlock(&sc->sc_lock);
195	/*
196	 * XXX: Race with open?
197	 */
198	free(sc, M_AUTOFS);
199
200	return (0);
201}
202
203bool
204autofs_ignore_thread(const struct thread *td)
205{
206	struct proc *p;
207
208	p = td->td_proc;
209
210	if (sc->sc_dev_opened == false)
211		return (false);
212
213	PROC_LOCK(p);
214	if (p->p_session->s_sid == sc->sc_dev_sid) {
215		PROC_UNLOCK(p);
216		return (true);
217	}
218	PROC_UNLOCK(p);
219
220	return (false);
221}
222
223static char *
224autofs_path(struct autofs_node *anp)
225{
226	struct autofs_mount *amp;
227	char *path, *tmp;
228
229	amp = anp->an_mount;
230
231	path = strdup("", M_AUTOFS);
232	for (; anp->an_parent != NULL; anp = anp->an_parent) {
233		tmp = malloc(strlen(anp->an_name) + strlen(path) + 2,
234		    M_AUTOFS, M_WAITOK);
235		strcpy(tmp, anp->an_name);
236		strcat(tmp, "/");
237		strcat(tmp, path);
238		free(path, M_AUTOFS);
239		path = tmp;
240	}
241
242	tmp = malloc(strlen(amp->am_mountpoint) + strlen(path) + 2,
243	    M_AUTOFS, M_WAITOK);
244	strcpy(tmp, amp->am_mountpoint);
245	strcat(tmp, "/");
246	strcat(tmp, path);
247	free(path, M_AUTOFS);
248	path = tmp;
249
250	return (path);
251}
252
253static void
254autofs_callout(void *context)
255{
256	struct autofs_request *ar;
257	struct autofs_softc *sc;
258
259	ar = context;
260	sc = ar->ar_mount->am_softc;
261
262	sx_xlock(&sc->sc_lock);
263	AUTOFS_WARN("request %d for %s timed out after %d seconds",
264	    ar->ar_id, ar->ar_path, autofs_timeout);
265	/*
266	 * XXX: EIO perhaps?
267	 */
268	ar->ar_error = ETIMEDOUT;
269	ar->ar_done = true;
270	ar->ar_in_progress = false;
271	cv_broadcast(&sc->sc_cv);
272	sx_xunlock(&sc->sc_lock);
273}
274
275bool
276autofs_cached(struct autofs_node *anp, const char *component, int componentlen)
277{
278	int error;
279	struct autofs_mount *amp;
280
281	amp = anp->an_mount;
282
283	AUTOFS_ASSERT_UNLOCKED(amp);
284
285	/*
286	 * For top-level nodes we need to request automountd(8)
287	 * assistance even if the node is marked as cached,
288	 * but the requested subdirectory does not exist.  This
289	 * is necessary for wildcard indirect map keys to work.
290	 */
291	if (anp->an_parent == NULL && componentlen != 0) {
292		AUTOFS_LOCK(amp);
293		error = autofs_node_find(anp, component, componentlen, NULL);
294		AUTOFS_UNLOCK(amp);
295		if (error != 0)
296			return (false);
297	}
298
299	return (anp->an_cached);
300}
301
302static void
303autofs_cache_callout(void *context)
304{
305	struct autofs_node *anp;
306
307	anp = context;
308	anp->an_cached = false;
309}
310
311/*
312 * The set/restore sigmask functions are used to (temporarily) overwrite
313 * the thread td_sigmask during triggering.
314 */
315static void
316autofs_set_sigmask(sigset_t *oldset)
317{
318	sigset_t newset;
319	int i;
320
321	SIGFILLSET(newset);
322	/* Remove the autofs set of signals from newset */
323	PROC_LOCK(curproc);
324	mtx_lock(&curproc->p_sigacts->ps_mtx);
325	for (i = 0 ; i < sizeof(autofs_sig_set)/sizeof(int) ; i++) {
326		/*
327		 * But make sure we leave the ones already masked
328		 * by the process, i.e. remove the signal from the
329		 * temporary signalmask only if it wasn't already
330		 * in p_sigmask.
331		 */
332		if (!SIGISMEMBER(curthread->td_sigmask, autofs_sig_set[i]) &&
333		    !SIGISMEMBER(curproc->p_sigacts->ps_sigignore,
334		    autofs_sig_set[i])) {
335			SIGDELSET(newset, autofs_sig_set[i]);
336		}
337	}
338	mtx_unlock(&curproc->p_sigacts->ps_mtx);
339	kern_sigprocmask(curthread, SIG_SETMASK, &newset, oldset,
340	    SIGPROCMASK_PROC_LOCKED);
341	PROC_UNLOCK(curproc);
342}
343
344static void
345autofs_restore_sigmask(sigset_t *set)
346{
347
348	kern_sigprocmask(curthread, SIG_SETMASK, set, NULL, 0);
349}
350
351static int
352autofs_trigger_one(struct autofs_node *anp,
353    const char *component, int componentlen)
354{
355	sigset_t oldset;
356	struct autofs_mount *amp;
357	struct autofs_softc *sc;
358	struct autofs_node *firstanp;
359	struct autofs_request *ar;
360	char *key, *path;
361	int error = 0, request_error, last;
362
363	amp = VFSTOAUTOFS(anp->an_vnode->v_mount);
364	sc = amp->am_softc;
365
366	sx_assert(&sc->sc_lock, SA_XLOCKED);
367
368	if (anp->an_parent == NULL) {
369		key = strndup(component, componentlen, M_AUTOFS);
370	} else {
371		for (firstanp = anp; firstanp->an_parent->an_parent != NULL;
372		    firstanp = firstanp->an_parent)
373			continue;
374		key = strdup(firstanp->an_name, M_AUTOFS);
375	}
376
377	path = autofs_path(anp);
378
379	TAILQ_FOREACH(ar, &sc->sc_requests, ar_next) {
380		if (strcmp(ar->ar_path, path) != 0)
381			continue;
382		if (strcmp(ar->ar_key, key) != 0)
383			continue;
384
385		KASSERT(strcmp(ar->ar_from, amp->am_from) == 0,
386		    ("from changed; %s != %s", ar->ar_from, amp->am_from));
387		KASSERT(strcmp(ar->ar_prefix, amp->am_prefix) == 0,
388		    ("prefix changed; %s != %s",
389		     ar->ar_prefix, amp->am_prefix));
390		KASSERT(strcmp(ar->ar_options, amp->am_options) == 0,
391		    ("options changed; %s != %s",
392		     ar->ar_options, amp->am_options));
393
394		break;
395	}
396
397	if (ar != NULL) {
398		refcount_acquire(&ar->ar_refcount);
399	} else {
400		ar = uma_zalloc(autofs_request_zone, M_WAITOK | M_ZERO);
401		ar->ar_mount = amp;
402
403		ar->ar_id = atomic_fetchadd_int(&sc->sc_last_request_id, 1);
404		strlcpy(ar->ar_from, amp->am_from, sizeof(ar->ar_from));
405		strlcpy(ar->ar_path, path, sizeof(ar->ar_path));
406		strlcpy(ar->ar_prefix, amp->am_prefix, sizeof(ar->ar_prefix));
407		strlcpy(ar->ar_key, key, sizeof(ar->ar_key));
408		strlcpy(ar->ar_options,
409		    amp->am_options, sizeof(ar->ar_options));
410
411		callout_init(&ar->ar_callout, 1);
412		callout_reset(&ar->ar_callout,
413		    autofs_timeout * hz, autofs_callout, ar);
414		refcount_init(&ar->ar_refcount, 1);
415		TAILQ_INSERT_TAIL(&sc->sc_requests, ar, ar_next);
416	}
417
418	cv_broadcast(&sc->sc_cv);
419	while (ar->ar_done == false) {
420		if (autofs_interruptible != 0) {
421			autofs_set_sigmask(&oldset);
422			error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock);
423			autofs_restore_sigmask(&oldset);
424			if (error != 0) {
425				/*
426				 * XXX: For some reson this returns -1
427				 *	instead of EINTR, wtf?!
428				 */
429				error = EINTR;
430				AUTOFS_WARN("cv_wait_sig for %s failed "
431				    "with error %d", ar->ar_path, error);
432				break;
433			}
434		} else {
435			cv_wait(&sc->sc_cv, &sc->sc_lock);
436		}
437	}
438
439	request_error = ar->ar_error;
440	if (request_error != 0) {
441		AUTOFS_WARN("request for %s completed with error %d",
442		    ar->ar_path, request_error);
443	}
444
445	last = refcount_release(&ar->ar_refcount);
446	if (last) {
447		TAILQ_REMOVE(&sc->sc_requests, ar, ar_next);
448		/*
449		 * XXX: Is it safe?
450		 */
451		sx_xunlock(&sc->sc_lock);
452		callout_drain(&ar->ar_callout);
453		sx_xlock(&sc->sc_lock);
454		uma_zfree(autofs_request_zone, ar);
455	}
456
457	/*
458	 * Note that we do not do negative caching on purpose.  This
459	 * way the user can retry access at any time, e.g. after fixing
460	 * the failure reason, without waiting for cache timer to expire.
461	 */
462	if (error == 0 && request_error == 0 && autofs_cache > 0) {
463		anp->an_cached = true;
464		callout_reset(&anp->an_callout, autofs_cache * hz,
465		    autofs_cache_callout, anp);
466	}
467
468	free(key, M_AUTOFS);
469	free(path, M_AUTOFS);
470
471	if (error != 0)
472		return (error);
473	return (request_error);
474}
475
476/*
477 * Send request to automountd(8) and wait for completion.
478 */
479int
480autofs_trigger(struct autofs_node *anp,
481    const char *component, int componentlen)
482{
483	int error;
484
485	for (;;) {
486		error = autofs_trigger_one(anp, component, componentlen);
487		if (error == 0) {
488			anp->an_retries = 0;
489			return (0);
490		}
491		if (error == EINTR) {
492			AUTOFS_DEBUG("trigger interrupted by signal, "
493			    "not retrying");
494			anp->an_retries = 0;
495			return (error);
496		}
497		anp->an_retries++;
498		if (anp->an_retries >= autofs_retry_attempts) {
499			AUTOFS_DEBUG("trigger failed %d times; returning "
500			    "error %d", anp->an_retries, error);
501			anp->an_retries = 0;
502			return (error);
503
504		}
505		AUTOFS_DEBUG("trigger failed with error %d; will retry in "
506		    "%d seconds, %d attempts left", error, autofs_retry_delay,
507		    autofs_retry_attempts - anp->an_retries);
508		sx_xunlock(&sc->sc_lock);
509		pause("autofs_retry", autofs_retry_delay * hz);
510		sx_xlock(&sc->sc_lock);
511	}
512}
513
514static int
515autofs_ioctl_request(struct autofs_softc *sc, struct autofs_daemon_request *adr)
516{
517	struct autofs_request *ar;
518	int error;
519
520	sx_xlock(&sc->sc_lock);
521	for (;;) {
522		TAILQ_FOREACH(ar, &sc->sc_requests, ar_next) {
523			if (ar->ar_done)
524				continue;
525			if (ar->ar_in_progress)
526				continue;
527
528			break;
529		}
530
531		if (ar != NULL)
532			break;
533
534		error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock);
535		if (error != 0) {
536			/*
537			 * XXX: For some reson this returns -1 instead
538			 * 	of EINTR, wtf?!
539			 */
540			error = EINTR;
541			sx_xunlock(&sc->sc_lock);
542			AUTOFS_DEBUG("failed with error %d", error);
543			return (error);
544		}
545	}
546
547	ar->ar_in_progress = true;
548	sx_xunlock(&sc->sc_lock);
549
550	adr->adr_id = ar->ar_id;
551	strlcpy(adr->adr_from, ar->ar_from, sizeof(adr->adr_from));
552	strlcpy(adr->adr_path, ar->ar_path, sizeof(adr->adr_path));
553	strlcpy(adr->adr_prefix, ar->ar_prefix, sizeof(adr->adr_prefix));
554	strlcpy(adr->adr_key, ar->ar_key, sizeof(adr->adr_key));
555	strlcpy(adr->adr_options, ar->ar_options, sizeof(adr->adr_options));
556
557	PROC_LOCK(curproc);
558	sc->sc_dev_sid = curproc->p_session->s_sid;
559	PROC_UNLOCK(curproc);
560
561	return (0);
562}
563
564static int
565autofs_ioctl_done(struct autofs_softc *sc, struct autofs_daemon_done *add)
566{
567	struct autofs_request *ar;
568
569	sx_xlock(&sc->sc_lock);
570	TAILQ_FOREACH(ar, &sc->sc_requests, ar_next) {
571		if (ar->ar_id == add->add_id)
572			break;
573	}
574
575	if (ar == NULL) {
576		sx_xunlock(&sc->sc_lock);
577		AUTOFS_DEBUG("id %d not found", add->add_id);
578		return (ESRCH);
579	}
580
581	ar->ar_error = add->add_error;
582	ar->ar_done = true;
583	ar->ar_in_progress = false;
584	cv_broadcast(&sc->sc_cv);
585
586	sx_xunlock(&sc->sc_lock);
587
588	return (0);
589}
590
591static int
592autofs_open(struct cdev *dev, int flags, int fmt, struct thread *td)
593{
594
595	sx_xlock(&sc->sc_lock);
596	if (sc->sc_dev_opened) {
597		sx_xunlock(&sc->sc_lock);
598		return (EBUSY);
599	}
600
601	sc->sc_dev_opened = true;
602	sx_xunlock(&sc->sc_lock);
603
604	return (0);
605}
606
607static int
608autofs_close(struct cdev *dev, int flag, int fmt, struct thread *td)
609{
610
611	sx_xlock(&sc->sc_lock);
612	KASSERT(sc->sc_dev_opened, ("not opened?"));
613	sc->sc_dev_opened = false;
614	sx_xunlock(&sc->sc_lock);
615
616	return (0);
617}
618
619static int
620autofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode,
621    struct thread *td)
622{
623
624	KASSERT(sc->sc_dev_opened, ("not opened?"));
625
626	switch (cmd) {
627	case AUTOFSREQUEST:
628		return (autofs_ioctl_request(sc,
629		    (struct autofs_daemon_request *)arg));
630	case AUTOFSDONE:
631		return (autofs_ioctl_done(sc,
632		    (struct autofs_daemon_done *)arg));
633	default:
634		AUTOFS_DEBUG("invalid cmd %lx", cmd);
635		return (EINVAL);
636	}
637}
638