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