autofs.c revision 270898
1151497Sru/*-
2151497Sru * Copyright (c) 2014 The FreeBSD Foundation
3151497Sru * All rights reserved.
4151497Sru *
5151497Sru * This software was developed by Edward Tomasz Napierala under sponsorship
6151497Sru * from the FreeBSD Foundation.
7151497Sru *
8151497Sru * Redistribution and use in source and binary forms, with or without
9151497Sru * modification, are permitted provided that the following conditions
10151497Sru * are met:
11151497Sru * 1. Redistributions of source code must retain the above copyright
12151497Sru *    notice, this list of conditions and the following disclaimer.
13151497Sru * 2. Redistributions in binary form must reproduce the above copyright
14151497Sru *    notice, this list of conditions and the following disclaimer in the
15151497Sru *    documentation and/or other materials provided with the distribution.
16151497Sru *
17151497Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18151497Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19151497Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20151497Sru * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21151497Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22151497Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23151497Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24151497Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25151497Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26151497Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27151497Sru * SUCH DAMAGE.
28151497Sru *
29151497Sru */
30151497Sru/*-
31151497Sru * Copyright (c) 1989, 1991, 1993, 1995
32151497Sru *	The Regents of the University of California.  All rights reserved.
33151497Sru *
34151497Sru * This code is derived from software contributed to Berkeley by
35151497Sru * Rick Macklem at The University of Guelph.
36151497Sru *
37151497Sru * Redistribution and use in source and binary forms, with or without
38151497Sru * modification, are permitted provided that the following conditions
39151497Sru * are met:
40151497Sru * 1. Redistributions of source code must retain the above copyright
41151497Sru *    notice, this list of conditions and the following disclaimer.
42151497Sru * 2. Redistributions in binary form must reproduce the above copyright
43151497Sru *    notice, this list of conditions and the following disclaimer in the
44151497Sru *    documentation and/or other materials provided with the distribution.
45151497Sru * 4. Neither the name of the University nor the names of its contributors
46151497Sru *    may be used to endorse or promote products derived from this software
47151497Sru *    without specific prior written permission.
48151497Sru *
49151497Sru * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50151497Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51151497Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52151497Sru * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53151497Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54151497Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55151497Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56151497Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57151497Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58151497Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59151497Sru * SUCH DAMAGE.
60151497Sru *
61151497Sru */
62151497Sru
63151497Sru#include <sys/cdefs.h>
64151497Sru __FBSDID("$FreeBSD: stable/10/sys/fs/autofs/autofs.c 270898 2014-08-31 21:49:45Z trasz $");
65151497Sru
66151497Sru#include <sys/param.h>
67151497Sru#include <sys/systm.h>
68151497Sru#include <sys/buf.h>
69151497Sru#include <sys/conf.h>
70151497Sru#include <sys/dirent.h>
71151497Sru#include <sys/ioccom.h>
72151497Sru#include <sys/kernel.h>
73151497Sru#include <sys/module.h>
74151497Sru#include <sys/mount.h>
75151497Sru#include <sys/refcount.h>
76151497Sru#include <sys/sx.h>
77151497Sru#include <sys/sysctl.h>
78151497Sru#include <sys/syscallsubr.h>
79151497Sru#include <sys/vnode.h>
80151497Sru#include <machine/atomic.h>
81151497Sru#include <vm/uma.h>
82151497Sru
83151497Sru#include <fs/autofs/autofs.h>
84151497Sru#include <fs/autofs/autofs_ioctl.h>
85151497Sru
86151497SruMALLOC_DEFINE(M_AUTOFS, "autofs", "Automounter filesystem");
87151497Sru
88151497Sruuma_zone_t autofs_request_zone;
89151497Sruuma_zone_t autofs_node_zone;
90151497Sru
91151497Srustatic int	autofs_open(struct cdev *dev, int flags, int fmt,
92151497Sru		    struct thread *td);
93151497Srustatic int	autofs_close(struct cdev *dev, int flag, int fmt,
94151497Sru		    struct thread *td);
95151497Srustatic int	autofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg,
96151497Sru		    int mode, struct thread *td);
97151497Sru
98151497Srustatic struct cdevsw autofs_cdevsw = {
99151497Sru     .d_version = D_VERSION,
100151497Sru     .d_open   = autofs_open,
101151497Sru     .d_close   = autofs_close,
102151497Sru     .d_ioctl   = autofs_ioctl,
103151497Sru     .d_name    = "autofs",
104151497Sru};
105151497Sru
106151497Sru/*
107151497Sru * List of signals that can interrupt an autofs trigger.  Might be a good
108151497Sru * idea to keep it synchronised with list in sys/fs/nfs/nfs_commonkrpc.c.
109151497Sru */
110151497Sruint autofs_sig_set[] = {
111151497Sru	SIGINT,
112151497Sru	SIGTERM,
113151497Sru	SIGHUP,
114151497Sru	SIGKILL,
115151497Sru	SIGQUIT
116151497Sru};
117151497Sru
118151497Srustruct autofs_softc	*sc;
119151497Sru
120151497SruSYSCTL_NODE(_vfs, OID_AUTO, autofs, CTLFLAG_RD, 0, "Automounter filesystem");
121151497Sruint autofs_debug = 1;
122151497SruTUNABLE_INT("vfs.autofs.debug", &autofs_debug);
123151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, debug, CTLFLAG_RWTUN,
124151497Sru    &autofs_debug, 1, "Enable debug messages");
125151497Sruint autofs_mount_on_stat = 0;
126151497SruTUNABLE_INT("vfs.autofs.mount_on_stat", &autofs_mount_on_stat);
127151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, mount_on_stat, CTLFLAG_RWTUN,
128151497Sru    &autofs_mount_on_stat, 0, "Trigger mount on stat(2) on mountpoint");
129151497Sruint autofs_timeout = 30;
130151497SruTUNABLE_INT("vfs.autofs.timeout", &autofs_timeout);
131151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, timeout, CTLFLAG_RWTUN,
132151497Sru    &autofs_timeout, 30, "Number of seconds to wait for automountd(8)");
133151497Sruint autofs_cache = 600;
134151497SruTUNABLE_INT("vfs.autofs.cache", &autofs_cache);
135151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, cache, CTLFLAG_RWTUN,
136151497Sru    &autofs_cache, 600, "Number of seconds to wait before reinvoking "
137151497Sru    "automountd(8) for any given file or directory");
138151497Sruint autofs_retry_attempts = 3;
139151497SruTUNABLE_INT("vfs.autofs.retry_attempts", &autofs_retry_attempts);
140151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, retry_attempts, CTLFLAG_RWTUN,
141151497Sru    &autofs_retry_attempts, 3, "Number of attempts before failing mount");
142151497Sruint autofs_retry_delay = 1;
143151497SruTUNABLE_INT("vfs.autofs.retry_delay", &autofs_retry_delay);
144151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, retry_delay, CTLFLAG_RWTUN,
145151497Sru    &autofs_retry_delay, 1, "Number of seconds before retrying");
146151497Sruint autofs_interruptible = 1;
147151497SruTUNABLE_INT("vfs.autofs.interruptible", &autofs_interruptible);
148151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, interruptible, CTLFLAG_RWTUN,
149151497Sru    &autofs_interruptible, 1, "Allow requests to be interrupted by signal");
150151497Sru
151151497Sruint
152151497Sruautofs_init(struct vfsconf *vfsp)
153151497Sru{
154151497Sru	int error;
155151497Sru
156151497Sru	sc = malloc(sizeof(*sc), M_AUTOFS, M_WAITOK | M_ZERO);
157151497Sru
158151497Sru	autofs_request_zone = uma_zcreate("autofs_request",
159151497Sru	    sizeof(struct autofs_request), NULL, NULL, NULL, NULL,
160151497Sru	    UMA_ALIGN_PTR, 0);
161151497Sru	autofs_node_zone = uma_zcreate("autofs_node",
162151497Sru	    sizeof(struct autofs_node), NULL, NULL, NULL, NULL,
163151497Sru	    UMA_ALIGN_PTR, 0);
164151497Sru
165151497Sru	TAILQ_INIT(&sc->sc_requests);
166151497Sru	cv_init(&sc->sc_cv, "autofscv");
167151497Sru	sx_init(&sc->sc_lock, "autofslk");
168151497Sru
169151497Sru	error = make_dev_p(MAKEDEV_CHECKNAME, &sc->sc_cdev, &autofs_cdevsw,
170151497Sru	    NULL, UID_ROOT, GID_WHEEL, 0600, "autofs");
171151497Sru	if (error != 0) {
172151497Sru		AUTOFS_WARN("failed to create device node, error %d", error);
173151497Sru		free(sc, M_AUTOFS);
174151497Sru		return (error);
175151497Sru	}
176151497Sru	sc->sc_cdev->si_drv1 = sc;
177151497Sru
178151497Sru	return (0);
179151497Sru}
180151497Sru
181151497Sruint
182151497Sruautofs_uninit(struct vfsconf *vfsp)
183151497Sru{
184151497Sru
185151497Sru	sx_xlock(&sc->sc_lock);
186151497Sru	if (sc->sc_dev_opened) {
187151497Sru		sx_xunlock(&sc->sc_lock);
188151497Sru		return (EBUSY);
189151497Sru	}
190151497Sru	if (sc->sc_cdev != NULL)
191151497Sru		destroy_dev(sc->sc_cdev);
192151497Sru
193151497Sru	uma_zdestroy(autofs_request_zone);
194151497Sru	uma_zdestroy(autofs_node_zone);
195151497Sru
196151497Sru	sx_xunlock(&sc->sc_lock);
197151497Sru	/*
198151497Sru	 * XXX: Race with open?
199151497Sru	 */
200151497Sru	free(sc, M_AUTOFS);
201151497Sru
202151497Sru	return (0);
203151497Sru}
204151497Sru
205151497Srubool
206151497Sruautofs_ignore_thread(const struct thread *td)
207151497Sru{
208151497Sru	struct proc *p;
209151497Sru
210151497Sru	p = td->td_proc;
211151497Sru
212151497Sru	if (sc->sc_dev_opened == false)
213151497Sru		return (false);
214151497Sru
215151497Sru	PROC_LOCK(p);
216151497Sru	if (p->p_session->s_sid == sc->sc_dev_sid) {
217151497Sru		PROC_UNLOCK(p);
218151497Sru		return (true);
219151497Sru	}
220151497Sru	PROC_UNLOCK(p);
221151497Sru
222151497Sru	return (false);
223151497Sru}
224151497Sru
225151497Srustatic char *
226151497Sruautofs_path(struct autofs_node *anp)
227151497Sru{
228151497Sru	struct autofs_mount *amp;
229151497Sru	char *path, *tmp;
230151497Sru
231151497Sru	amp = anp->an_mount;
232151497Sru
233151497Sru	path = strdup("", M_AUTOFS);
234151497Sru	for (; anp->an_parent != NULL; anp = anp->an_parent) {
235151497Sru		tmp = malloc(strlen(anp->an_name) + strlen(path) + 2,
236151497Sru		    M_AUTOFS, M_WAITOK);
237151497Sru		strcpy(tmp, anp->an_name);
238151497Sru		strcat(tmp, "/");
239151497Sru		strcat(tmp, path);
240151497Sru		free(path, M_AUTOFS);
241151497Sru		path = tmp;
242151497Sru	}
243151497Sru
244151497Sru	tmp = malloc(strlen(amp->am_mountpoint) + strlen(path) + 2,
245151497Sru	    M_AUTOFS, M_WAITOK);
246151497Sru	strcpy(tmp, amp->am_mountpoint);
247151497Sru	strcat(tmp, "/");
248151497Sru	strcat(tmp, path);
249151497Sru	free(path, M_AUTOFS);
250151497Sru	path = tmp;
251151497Sru
252151497Sru	return (path);
253151497Sru}
254151497Sru
255151497Srustatic void
256151497Sruautofs_callout(void *context)
257151497Sru{
258151497Sru	struct autofs_request *ar;
259151497Sru	struct autofs_softc *sc;
260151497Sru
261151497Sru	ar = context;
262151497Sru	sc = ar->ar_mount->am_softc;
263151497Sru
264151497Sru	sx_xlock(&sc->sc_lock);
265151497Sru	AUTOFS_WARN("request %d for %s timed out after %d seconds",
266151497Sru	    ar->ar_id, ar->ar_path, autofs_timeout);
267151497Sru	/*
268151497Sru	 * XXX: EIO perhaps?
269151497Sru	 */
270151497Sru	ar->ar_error = ETIMEDOUT;
271151497Sru	ar->ar_done = true;
272151497Sru	ar->ar_in_progress = false;
273151497Sru	cv_broadcast(&sc->sc_cv);
274151497Sru	sx_xunlock(&sc->sc_lock);
275151497Sru}
276151497Sru
277151497Srubool
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