xref: /netbsd/sys/fs/autofs/autofs.c (revision 14b4bbb2)
1 /*	$NetBSD: autofs.c,v 1.6 2020/05/23 23:42:43 ad Exp $	*/
2 
3 /*-
4  * Copyright (c) 2017 The NetBSD Foundation, Inc.
5  * Copyright (c) 2016 The DragonFly Project
6  * Copyright (c) 2014 The FreeBSD Foundation
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to The NetBSD Foundation
10  * by Tomohiro Kusumi <kusumi.tomohiro@gmail.com>.
11  *
12  * This software was developed by Edward Tomasz Napierala under sponsorship
13  * from the FreeBSD Foundation.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  */
37 /*-
38  * Copyright (c) 1989, 1991, 1993, 1995
39  *	The Regents of the University of California.  All rights reserved.
40  *
41  * This code is derived from software contributed to Berkeley by
42  * Rick Macklem at The University of Guelph.
43  *
44  * Redistribution and use in source and binary forms, with or without
45  * modification, are permitted provided that the following conditions
46  * are met:
47  * 1. Redistributions of source code must retain the above copyright
48  *    notice, this list of conditions and the following disclaimer.
49  * 2. Redistributions in binary form must reproduce the above copyright
50  *    notice, this list of conditions and the following disclaimer in the
51  *    documentation and/or other materials provided with the distribution.
52  * 3. Neither the name of the University nor the names of its contributors
53  *    may be used to endorse or promote products derived from this software
54  *    without specific prior written permission.
55  *
56  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66  * SUCH DAMAGE.
67  *
68  */
69 
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: autofs.c,v 1.6 2020/05/23 23:42:43 ad Exp $");
72 
73 #include "autofs.h"
74 
75 #include "ioconf.h"
76 
77 #include <sys/atomic.h>
78 #include <sys/queue.h>
79 #include <sys/signalvar.h>
80 
81 static dev_type_open(autofs_open);
82 static dev_type_close(autofs_close);
83 static dev_type_ioctl(autofs_ioctl);
84 
85 const struct cdevsw autofs_cdevsw = {
86 	.d_open = autofs_open,
87 	.d_close = autofs_close,
88 	.d_read = noread,
89 	.d_write = nowrite,
90 	.d_ioctl = autofs_ioctl,
91 	.d_stop = nostop,
92 	.d_tty = notty,
93 	.d_poll = nopoll,
94 	.d_mmap = nommap,
95 	.d_kqfilter = nokqfilter,
96 	.d_discard = nodiscard,
97 	.d_flag = D_OTHER,
98 };
99 
100 /*
101  * List of signals that can interrupt an autofs trigger.
102  */
103 static int autofs_sig_set[] = {
104 	SIGINT,
105 	SIGTERM,
106 	SIGHUP,
107 	SIGKILL,
108 	SIGQUIT,
109 };
110 
111 struct pool	autofs_request_pool;
112 struct pool	autofs_node_pool;
113 struct autofs_softc	*autofs_softc = NULL;
114 struct workqueue	*autofs_tmo_wq = NULL;
115 
116 int autofs_debug = 1;
117 int autofs_mount_on_stat = 0;
118 int autofs_timeout = 30;
119 int autofs_cache = 600;
120 int autofs_retry_attempts = 3;
121 int autofs_retry_delay = 1;
122 int autofs_interruptible = 1;
123 
124 void
autofsattach(int n)125 autofsattach(int n)
126 {
127 }
128 
129 static int
autofs_node_cmp(const struct autofs_node * a,const struct autofs_node * b)130 autofs_node_cmp(const struct autofs_node *a, const struct autofs_node *b)
131 {
132 
133 	return strcmp(a->an_name, b->an_name);
134 }
135 
136 RB_GENERATE(autofs_node_tree, autofs_node, an_entry, autofs_node_cmp);
137 
138 bool
autofs_ignore_thread(void)139 autofs_ignore_thread(void)
140 {
141 
142 	if (autofs_softc->sc_dev_opened == false)
143 		return false;
144 
145 	mutex_enter(&proc_lock);
146 	if (autofs_softc->sc_dev_sid == curproc->p_pgrp->pg_id) {
147 		mutex_exit(&proc_lock);
148 		return true;
149 	}
150 	mutex_exit(&proc_lock);
151 
152 	return false;
153 }
154 
155 static char *
autofs_path(struct autofs_node * anp)156 autofs_path(struct autofs_node *anp)
157 {
158 	struct autofs_mount *amp = anp->an_mount;
159 	size_t len;
160 	char *path, *tmp;
161 
162 	path = kmem_strdup("", KM_SLEEP);
163 	for (; anp->an_parent; anp = anp->an_parent) {
164 		len = strlen(anp->an_name) + strlen(path) + 2;
165 		tmp = kmem_alloc(len, KM_SLEEP);
166 		snprintf(tmp, len, "%s/%s", anp->an_name, path);
167 		kmem_strfree(path);
168 		path = tmp;
169 	}
170 
171 	len = strlen(amp->am_on) + strlen(path) + 2;
172 	tmp = kmem_alloc(len, KM_SLEEP);
173 	snprintf(tmp, len, "%s/%s", amp->am_on, path);
174 	kmem_strfree(path);
175 
176 	return tmp;
177 }
178 
179 void
autofs_timeout_wq(struct work * wk,void * arg)180 autofs_timeout_wq(struct work *wk, void *arg)
181 {
182 	struct autofs_request *ar = (void *)wk;
183 
184 	mutex_enter(&autofs_softc->sc_lock);
185 	AUTOFS_WARN("request %d for %s timed out after %d seconds",
186 	    ar->ar_id, ar->ar_path, autofs_timeout);
187 
188 	ar->ar_error = ETIMEDOUT;
189 	ar->ar_wildcards = true;
190 	ar->ar_done = true;
191 	ar->ar_in_progress = false;
192 	cv_broadcast(&autofs_softc->sc_cv);
193 	mutex_exit(&autofs_softc->sc_lock);
194 }
195 
196 static void
autofs_timeout_callout(void * context)197 autofs_timeout_callout(void *context)
198 {
199 	struct autofs_request *ar = context;
200 
201 	workqueue_enqueue(autofs_tmo_wq, &ar->ar_wk, NULL);
202 }
203 
204 bool
autofs_cached(struct autofs_node * anp,const char * component,int componentlen)205 autofs_cached(struct autofs_node *anp, const char *component, int componentlen)
206 {
207 	struct autofs_mount *amp = anp->an_mount;
208 
209 	KASSERT(!mutex_owned(&amp->am_lock));
210 
211 	/*
212 	 * For root node we need to request automountd(8) assistance even
213 	 * if the node is marked as cached, but the requested top-level
214 	 * directory does not exist.  This is necessary for wildcard indirect
215 	 * map keys to work.  We don't do this if we know that there are
216 	 * no wildcards.
217 	 */
218 	if (!anp->an_parent && componentlen && anp->an_wildcards) {
219 		int error;
220 		KASSERT(amp->am_root == anp);
221 		mutex_enter(&amp->am_lock);
222 		error = autofs_node_find(anp, component, componentlen, NULL);
223 		mutex_exit(&amp->am_lock);
224 		if (error)
225 			return false;
226 	}
227 
228 	return anp->an_cached;
229 }
230 
231 static void
autofs_cache_callout(void * context)232 autofs_cache_callout(void *context)
233 {
234 	struct autofs_node *anp = context;
235 
236 	autofs_node_uncache(anp);
237 }
238 
239 void
autofs_flush(struct autofs_mount * amp)240 autofs_flush(struct autofs_mount *amp)
241 {
242 	struct autofs_node *anp = amp->am_root;
243 	struct autofs_node *child;
244 
245 	mutex_enter(&amp->am_lock);
246 	RB_FOREACH(child, autofs_node_tree, &anp->an_children) {
247 		autofs_node_uncache(child);
248 	}
249 	autofs_node_uncache(amp->am_root);
250 	mutex_exit(&amp->am_lock);
251 
252 	AUTOFS_DEBUG("%s flushed", amp->am_on);
253 }
254 
255 /*
256  * The set/restore sigmask functions are used to (temporarily) overwrite
257  * the thread sigmask during triggering.
258  */
259 static void
autofs_set_sigmask(sigset_t * oldset)260 autofs_set_sigmask(sigset_t *oldset)
261 {
262 	sigset_t newset;
263 	int i;
264 
265 	sigfillset(&newset);
266 	/* Remove the autofs set of signals from newset */
267 	mutex_enter(&proc_lock);
268 	mutex_enter(curproc->p_lock);
269 
270 	for (i = 0; i < __arraycount(autofs_sig_set); i++) {
271 		/*
272 		 * But make sure we leave the ones already masked
273 		 * by the process, i.e. remove the signal from the
274 		 * temporary signalmask only if it wasn't already
275 		 * in sigmask.
276 		 */
277 		if (!sigismasked(curlwp, autofs_sig_set[i]))
278 			sigdelset(&newset, autofs_sig_set[i]);
279 	}
280 	sigprocmask1(curlwp, SIG_SETMASK, &newset, oldset);
281 
282 	mutex_exit(curproc->p_lock);
283 	mutex_exit(&proc_lock);
284 }
285 
286 static void
autofs_restore_sigmask(sigset_t * set)287 autofs_restore_sigmask(sigset_t *set)
288 {
289 
290 	mutex_enter(&proc_lock);
291 	mutex_enter(curproc->p_lock);
292 
293 	sigprocmask1(curlwp, SIG_SETMASK, set, NULL);
294 
295 	mutex_exit(curproc->p_lock);
296 	mutex_exit(&proc_lock);
297 }
298 
299 static int
autofs_trigger_one(struct autofs_node * anp,const char * component,int componentlen)300 autofs_trigger_one(struct autofs_node *anp, const char *component,
301     int componentlen)
302 {
303 	struct autofs_mount *amp = anp->an_mount;
304 	struct autofs_request *ar;
305 	char *key, *path;
306 	int error = 0, request_error;
307 	bool wildcards;
308 
309 	KASSERT(mutex_owned(&autofs_softc->sc_lock));
310 
311 	if (!anp->an_parent) {
312 		key = autofs_strndup(component, componentlen, KM_SLEEP);
313 	} else {
314 		struct autofs_node *firstanp;
315 		for (firstanp = anp; firstanp->an_parent->an_parent;
316 		    firstanp = firstanp->an_parent)
317 			continue;
318 		key = kmem_strdup(firstanp->an_name, KM_SLEEP);
319 	}
320 
321 	path = autofs_path(anp);
322 
323 	TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
324 		if (strcmp(ar->ar_path, path))
325 			continue;
326 		if (strcmp(ar->ar_key, key))
327 			continue;
328 
329 		KASSERT(!strcmp(ar->ar_from, amp->am_from));
330 		KASSERT(!strcmp(ar->ar_prefix, amp->am_prefix));
331 		KASSERT(!strcmp(ar->ar_options, amp->am_options));
332 		break;
333 	}
334 
335 	if (ar) {
336 		atomic_add_int(&ar->ar_refcount, 1);
337 	} else {
338 		ar = pool_get(&autofs_request_pool, PR_WAITOK);
339 		ar->ar_mount = amp;
340 		ar->ar_id = autofs_softc->sc_last_request_id++;
341 		ar->ar_done = false;
342 		ar->ar_error = 0;
343 		ar->ar_wildcards = false;
344 		ar->ar_in_progress = false;
345 		strlcpy(ar->ar_from, amp->am_from, sizeof(ar->ar_from));
346 		strlcpy(ar->ar_path, path, sizeof(ar->ar_path));
347 		strlcpy(ar->ar_prefix, amp->am_prefix, sizeof(ar->ar_prefix));
348 		strlcpy(ar->ar_key, key, sizeof(ar->ar_key));
349 		strlcpy(ar->ar_options,
350 		    amp->am_options, sizeof(ar->ar_options));
351 
352 		callout_init(&ar->ar_callout, 0);
353 		callout_reset(&ar->ar_callout, autofs_timeout * hz,
354 		    autofs_timeout_callout, ar);
355 		ar->ar_refcount = 1;
356 		TAILQ_INSERT_TAIL(&autofs_softc->sc_requests, ar, ar_next);
357 	}
358 
359 	cv_broadcast(&autofs_softc->sc_cv);
360 	while (ar->ar_done == false) {
361 		if (autofs_interruptible) {
362 			sigset_t oldset;
363 			autofs_set_sigmask(&oldset);
364 			error = cv_wait_sig(&autofs_softc->sc_cv,
365 			    &autofs_softc->sc_lock);
366 			autofs_restore_sigmask(&oldset);
367 			if (error) {
368 				AUTOFS_WARN("cv_wait_sig for %s failed "
369 				    "with error %d", ar->ar_path, error);
370 				break;
371 			}
372 		} else {
373 			cv_wait(&autofs_softc->sc_cv, &autofs_softc->sc_lock);
374 		}
375 	}
376 
377 	request_error = ar->ar_error;
378 	if (request_error)
379 		AUTOFS_WARN("request for %s completed with error %d, "
380 		    "pid %d (%s)", ar->ar_path, request_error,
381 		    curproc->p_pid, curproc->p_comm);
382 
383 	wildcards = ar->ar_wildcards;
384 
385 	/*
386 	 * Check if this is the last reference.
387 	 */
388 	if (!atomic_add_int_nv(&ar->ar_refcount, -1)) {
389 		TAILQ_REMOVE(&autofs_softc->sc_requests, ar, ar_next);
390 		mutex_exit(&autofs_softc->sc_lock);
391 		callout_halt(&ar->ar_callout, NULL);
392 		pool_put(&autofs_request_pool, ar);
393 		mutex_enter(&autofs_softc->sc_lock);
394 	}
395 
396 	/*
397 	 * Note that we do not do negative caching on purpose.  This
398 	 * way the user can retry access at any time, e.g. after fixing
399 	 * the failure reason, without waiting for cache timer to expire.
400 	 */
401 	if (!error && !request_error && autofs_cache > 0) {
402 		autofs_node_cache(anp);
403 		anp->an_wildcards = wildcards;
404 		callout_reset(&anp->an_callout, autofs_cache * hz,
405 		    autofs_cache_callout, anp);
406 	}
407 
408 	kmem_strfree(key);
409 	kmem_strfree(path);
410 
411 	if (error)
412 		return error;
413 	return request_error;
414 }
415 
416 int
autofs_trigger(struct autofs_node * anp,const char * component,int componentlen)417 autofs_trigger(struct autofs_node *anp, const char *component,
418     int componentlen)
419 {
420 	for (;;) {
421 		int error, dummy;
422 
423 		error = autofs_trigger_one(anp, component, componentlen);
424 		if (!error) {
425 			anp->an_retries = 0;
426 			return 0;
427 		}
428 		if (error == EINTR || error == ERESTART) {
429 			AUTOFS_DEBUG("trigger interrupted by signal, "
430 			    "not retrying");
431 			anp->an_retries = 0;
432 			return error;
433 		}
434 		anp->an_retries++;
435 		if (anp->an_retries >= autofs_retry_attempts) {
436 			AUTOFS_DEBUG("trigger failed %d times; returning "
437 			    "error %d", anp->an_retries, error);
438 			anp->an_retries = 0;
439 			return error;
440 
441 		}
442 		AUTOFS_DEBUG("trigger failed with error %d; will retry in "
443 		    "%d seconds, %d attempts left", error, autofs_retry_delay,
444 		    autofs_retry_attempts - anp->an_retries);
445 		mutex_exit(&autofs_softc->sc_lock);
446 		tsleep(&dummy, 0, "autofs_retry", autofs_retry_delay * hz);
447 		mutex_enter(&autofs_softc->sc_lock);
448 	}
449 }
450 
451 static int
autofs_ioctl_request(struct autofs_daemon_request * adr)452 autofs_ioctl_request(struct autofs_daemon_request *adr)
453 {
454 	struct autofs_request *ar;
455 
456 	mutex_enter(&autofs_softc->sc_lock);
457 	for (;;) {
458 		int error;
459 		TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
460 			if (ar->ar_done)
461 				continue;
462 			if (ar->ar_in_progress)
463 				continue;
464 			break;
465 		}
466 
467 		if (ar)
468 			break;
469 
470 		error = cv_wait_sig(&autofs_softc->sc_cv,
471 		    &autofs_softc->sc_lock);
472 		if (error) {
473 			mutex_exit(&autofs_softc->sc_lock);
474 			return error;
475 		}
476 	}
477 
478 	ar->ar_in_progress = true;
479 	mutex_exit(&autofs_softc->sc_lock);
480 
481 	adr->adr_id = ar->ar_id;
482 	strlcpy(adr->adr_from, ar->ar_from, sizeof(adr->adr_from));
483 	strlcpy(adr->adr_path, ar->ar_path, sizeof(adr->adr_path));
484 	strlcpy(adr->adr_prefix, ar->ar_prefix, sizeof(adr->adr_prefix));
485 	strlcpy(adr->adr_key, ar->ar_key, sizeof(adr->adr_key));
486 	strlcpy(adr->adr_options, ar->ar_options, sizeof(adr->adr_options));
487 
488 	mutex_enter(&proc_lock);
489 	autofs_softc->sc_dev_sid = curproc->p_pgrp->pg_id;
490 	mutex_exit(&proc_lock);
491 
492 	return 0;
493 }
494 
495 static int
autofs_ioctl_done(struct autofs_daemon_done * add)496 autofs_ioctl_done(struct autofs_daemon_done *add)
497 {
498 	struct autofs_request *ar;
499 
500 	mutex_enter(&autofs_softc->sc_lock);
501 	TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
502 		if (ar->ar_id == add->add_id)
503 			break;
504 	}
505 
506 	if (!ar) {
507 		mutex_exit(&autofs_softc->sc_lock);
508 		AUTOFS_DEBUG("id %d not found", add->add_id);
509 		return ESRCH;
510 	}
511 
512 	ar->ar_error = add->add_error;
513 	ar->ar_wildcards = add->add_wildcards;
514 	ar->ar_done = true;
515 	ar->ar_in_progress = false;
516 	cv_broadcast(&autofs_softc->sc_cv);
517 
518 	mutex_exit(&autofs_softc->sc_lock);
519 
520 	return 0;
521 }
522 
523 static int
autofs_open(dev_t dev,int flags,int mode,struct lwp * l)524 autofs_open(dev_t dev, int flags, int mode, struct lwp *l)
525 {
526 
527 	mutex_enter(&autofs_softc->sc_lock);
528 	/*
529 	 * We must never block automountd(8) and its descendants, and we use
530 	 * session ID to determine that: we store session id of the process
531 	 * that opened the device, and then compare it with session ids
532 	 * of triggering processes.  This means running a second automountd(8)
533 	 * instance would break the previous one.  The check below prevents
534 	 * it from happening.
535 	 */
536 	if (autofs_softc->sc_dev_opened) {
537 		mutex_exit(&autofs_softc->sc_lock);
538 		return EBUSY;
539 	}
540 
541 	autofs_softc->sc_dev_opened = true;
542 	mutex_exit(&autofs_softc->sc_lock);
543 
544 	return 0;
545 }
546 
547 static int
autofs_close(dev_t dev,int flags,int mode,struct lwp * l)548 autofs_close(dev_t dev, int flags, int mode, struct lwp *l)
549 {
550 
551 	mutex_enter(&autofs_softc->sc_lock);
552 	KASSERT(autofs_softc->sc_dev_opened);
553 	autofs_softc->sc_dev_opened = false;
554 	mutex_exit(&autofs_softc->sc_lock);
555 
556 	return 0;
557 }
558 
559 static int
autofs_ioctl(dev_t dev,const u_long cmd,void * data,int flag,struct lwp * l)560 autofs_ioctl(dev_t dev, const u_long cmd, void *data, int flag, struct lwp *l)
561 {
562 
563 	KASSERT(autofs_softc->sc_dev_opened);
564 
565 	switch (cmd) {
566 	case AUTOFSREQUEST:
567 		return autofs_ioctl_request(
568 		    (struct autofs_daemon_request *)data);
569 	case AUTOFSDONE:
570 		return autofs_ioctl_done(
571 		    (struct autofs_daemon_done *)data);
572 	default:
573 		AUTOFS_DEBUG("invalid cmd %lx", cmd);
574 		return EINVAL;
575 	}
576 	return EINVAL;
577 }
578