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