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