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/cdefs.h> 63 #include <sys/param.h> 64 #include <sys/systm.h> 65 #include <sys/buf.h> 66 #include <sys/conf.h> 67 #include <sys/dirent.h> 68 #include <sys/ioccom.h> 69 #include <sys/kernel.h> 70 #include <sys/module.h> 71 #include <sys/mount.h> 72 #include <sys/refcount.h> 73 #include <sys/sx.h> 74 #include <sys/sysctl.h> 75 #include <sys/syscallsubr.h> 76 #include <sys/taskqueue.h> 77 #include <sys/tree.h> 78 #include <sys/vnode.h> 79 #include <machine/atomic.h> 80 #include <vm/uma.h> 81 82 #include <fs/autofs/autofs.h> 83 #include <fs/autofs/autofs_ioctl.h> 84 85 MALLOC_DEFINE(M_AUTOFS, "autofs", "Automounter filesystem"); 86 87 uma_zone_t autofs_request_zone; 88 uma_zone_t autofs_node_zone; 89 90 static int autofs_open(struct cdev *dev, int flags, int fmt, 91 struct thread *td); 92 static int autofs_close(struct cdev *dev, int flag, int fmt, 93 struct thread *td); 94 static int autofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, 95 int mode, struct thread *td); 96 97 static struct cdevsw autofs_cdevsw = { 98 .d_version = D_VERSION, 99 .d_open = autofs_open, 100 .d_close = autofs_close, 101 .d_ioctl = autofs_ioctl, 102 .d_name = "autofs", 103 }; 104 105 /* 106 * List of signals that can interrupt an autofs trigger. Might be a good 107 * idea to keep it synchronised with list in sys/fs/nfs/nfs_commonkrpc.c. 108 */ 109 int autofs_sig_set[] = { 110 SIGINT, 111 SIGTERM, 112 SIGHUP, 113 SIGKILL, 114 SIGQUIT 115 }; 116 117 struct autofs_softc *autofs_softc; 118 119 SYSCTL_NODE(_vfs, OID_AUTO, autofs, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 120 "Automounter filesystem"); 121 int autofs_debug = 1; 122 TUNABLE_INT("vfs.autofs.debug", &autofs_debug); 123 SYSCTL_INT(_vfs_autofs, OID_AUTO, debug, CTLFLAG_RWTUN, 124 &autofs_debug, 1, "Enable debug messages"); 125 int autofs_mount_on_stat = 0; 126 TUNABLE_INT("vfs.autofs.mount_on_stat", &autofs_mount_on_stat); 127 SYSCTL_INT(_vfs_autofs, OID_AUTO, mount_on_stat, CTLFLAG_RWTUN, 128 &autofs_mount_on_stat, 0, "Trigger mount on stat(2) on mountpoint"); 129 int autofs_timeout = 30; 130 TUNABLE_INT("vfs.autofs.timeout", &autofs_timeout); 131 SYSCTL_INT(_vfs_autofs, OID_AUTO, timeout, CTLFLAG_RWTUN, 132 &autofs_timeout, 30, "Number of seconds to wait for automountd(8)"); 133 int autofs_cache = 600; 134 TUNABLE_INT("vfs.autofs.cache", &autofs_cache); 135 SYSCTL_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"); 138 int autofs_retry_attempts = 3; 139 TUNABLE_INT("vfs.autofs.retry_attempts", &autofs_retry_attempts); 140 SYSCTL_INT(_vfs_autofs, OID_AUTO, retry_attempts, CTLFLAG_RWTUN, 141 &autofs_retry_attempts, 3, "Number of attempts before failing mount"); 142 int autofs_retry_delay = 1; 143 TUNABLE_INT("vfs.autofs.retry_delay", &autofs_retry_delay); 144 SYSCTL_INT(_vfs_autofs, OID_AUTO, retry_delay, CTLFLAG_RWTUN, 145 &autofs_retry_delay, 1, "Number of seconds before retrying"); 146 int autofs_interruptible = 1; 147 TUNABLE_INT("vfs.autofs.interruptible", &autofs_interruptible); 148 SYSCTL_INT(_vfs_autofs, OID_AUTO, interruptible, CTLFLAG_RWTUN, 149 &autofs_interruptible, 1, "Allow requests to be interrupted by signal"); 150 151 static int 152 autofs_node_cmp(const struct autofs_node *a, const struct autofs_node *b) 153 { 154 155 return (strcmp(a->an_name, b->an_name)); 156 } 157 158 RB_GENERATE(autofs_node_tree, autofs_node, an_link, autofs_node_cmp); 159 160 int 161 autofs_init(struct vfsconf *vfsp) 162 { 163 int error; 164 165 KASSERT(autofs_softc == NULL, 166 ("softc %p, should be NULL", autofs_softc)); 167 168 autofs_softc = malloc(sizeof(*autofs_softc), M_AUTOFS, 169 M_WAITOK | M_ZERO); 170 171 autofs_request_zone = uma_zcreate("autofs_request", 172 sizeof(struct autofs_request), NULL, NULL, NULL, NULL, 173 UMA_ALIGN_PTR, 0); 174 autofs_node_zone = uma_zcreate("autofs_node", 175 sizeof(struct autofs_node), NULL, NULL, NULL, NULL, 176 UMA_ALIGN_PTR, 0); 177 178 TAILQ_INIT(&autofs_softc->sc_requests); 179 cv_init(&autofs_softc->sc_cv, "autofscv"); 180 sx_init(&autofs_softc->sc_lock, "autofslk"); 181 182 error = make_dev_p(MAKEDEV_CHECKNAME, &autofs_softc->sc_cdev, 183 &autofs_cdevsw, NULL, UID_ROOT, GID_WHEEL, 0600, "autofs"); 184 if (error != 0) { 185 AUTOFS_WARN("failed to create device node, error %d", error); 186 uma_zdestroy(autofs_request_zone); 187 uma_zdestroy(autofs_node_zone); 188 free(autofs_softc, M_AUTOFS); 189 190 return (error); 191 } 192 autofs_softc->sc_cdev->si_drv1 = autofs_softc; 193 194 return (0); 195 } 196 197 int 198 autofs_uninit(struct vfsconf *vfsp) 199 { 200 201 sx_xlock(&autofs_softc->sc_lock); 202 if (autofs_softc->sc_dev_opened) { 203 sx_xunlock(&autofs_softc->sc_lock); 204 return (EBUSY); 205 } 206 if (autofs_softc->sc_cdev != NULL) 207 destroy_dev(autofs_softc->sc_cdev); 208 209 uma_zdestroy(autofs_request_zone); 210 uma_zdestroy(autofs_node_zone); 211 212 sx_xunlock(&autofs_softc->sc_lock); 213 /* 214 * XXX: Race with open? 215 */ 216 free(autofs_softc, M_AUTOFS); 217 218 return (0); 219 } 220 221 bool 222 autofs_ignore_thread(const struct thread *td) 223 { 224 struct proc *p; 225 226 p = td->td_proc; 227 228 if (autofs_softc->sc_dev_opened == false) 229 return (false); 230 231 PROC_LOCK(p); 232 if (p->p_session->s_sid == autofs_softc->sc_dev_sid) { 233 PROC_UNLOCK(p); 234 return (true); 235 } 236 PROC_UNLOCK(p); 237 238 return (false); 239 } 240 241 static char * 242 autofs_path(struct autofs_node *anp) 243 { 244 struct autofs_mount *amp; 245 char *path, *tmp; 246 247 amp = anp->an_mount; 248 249 path = strdup("", M_AUTOFS); 250 for (; anp->an_parent != NULL; anp = anp->an_parent) { 251 tmp = malloc(strlen(anp->an_name) + strlen(path) + 2, 252 M_AUTOFS, M_WAITOK); 253 strcpy(tmp, anp->an_name); 254 strcat(tmp, "/"); 255 strcat(tmp, path); 256 free(path, M_AUTOFS); 257 path = tmp; 258 } 259 260 tmp = malloc(strlen(amp->am_mountpoint) + strlen(path) + 2, 261 M_AUTOFS, M_WAITOK); 262 strcpy(tmp, amp->am_mountpoint); 263 strcat(tmp, "/"); 264 strcat(tmp, path); 265 free(path, M_AUTOFS); 266 path = tmp; 267 268 return (path); 269 } 270 271 static void 272 autofs_task(void *context, int pending) 273 { 274 struct autofs_request *ar; 275 276 ar = context; 277 278 sx_xlock(&autofs_softc->sc_lock); 279 AUTOFS_WARN("request %d for %s timed out after %d seconds", 280 ar->ar_id, ar->ar_path, autofs_timeout); 281 /* 282 * XXX: EIO perhaps? 283 */ 284 ar->ar_error = ETIMEDOUT; 285 ar->ar_wildcards = true; 286 ar->ar_done = true; 287 ar->ar_in_progress = false; 288 cv_broadcast(&autofs_softc->sc_cv); 289 sx_xunlock(&autofs_softc->sc_lock); 290 } 291 292 bool 293 autofs_cached(struct autofs_node *anp, const char *component, int componentlen) 294 { 295 int error; 296 struct autofs_mount *amp; 297 298 amp = anp->an_mount; 299 300 AUTOFS_ASSERT_UNLOCKED(amp); 301 302 /* 303 * For root node we need to request automountd(8) assistance even 304 * if the node is marked as cached, but the requested top-level 305 * directory does not exist. This is necessary for wildcard indirect 306 * map keys to work. We don't do this if we know that there are 307 * no wildcards. 308 */ 309 if (anp->an_parent == NULL && componentlen != 0 && anp->an_wildcards) { 310 AUTOFS_SLOCK(amp); 311 error = autofs_node_find(anp, component, componentlen, NULL); 312 AUTOFS_SUNLOCK(amp); 313 if (error != 0) 314 return (false); 315 } 316 317 return (anp->an_cached); 318 } 319 320 static void 321 autofs_cache_callout(void *context) 322 { 323 struct autofs_node *anp; 324 325 anp = context; 326 anp->an_cached = false; 327 } 328 329 void 330 autofs_flush(struct autofs_mount *amp) 331 { 332 333 /* 334 * XXX: This will do for now, but ideally we should iterate 335 * over all the nodes. 336 */ 337 amp->am_root->an_cached = false; 338 AUTOFS_DEBUG("%s flushed", amp->am_mountpoint); 339 } 340 341 /* 342 * The set/restore sigmask functions are used to (temporarily) overwrite 343 * the thread td_sigmask during triggering. 344 */ 345 static void 346 autofs_set_sigmask(sigset_t *oldset) 347 { 348 sigset_t newset; 349 int i; 350 351 SIGFILLSET(newset); 352 /* Remove the autofs set of signals from newset */ 353 PROC_LOCK(curproc); 354 mtx_lock(&curproc->p_sigacts->ps_mtx); 355 for (i = 0 ; i < nitems(autofs_sig_set); i++) { 356 /* 357 * But make sure we leave the ones already masked 358 * by the process, i.e. remove the signal from the 359 * temporary signalmask only if it wasn't already 360 * in p_sigmask. 361 */ 362 if (!SIGISMEMBER(curthread->td_sigmask, autofs_sig_set[i]) && 363 !SIGISMEMBER(curproc->p_sigacts->ps_sigignore, 364 autofs_sig_set[i])) { 365 SIGDELSET(newset, autofs_sig_set[i]); 366 } 367 } 368 mtx_unlock(&curproc->p_sigacts->ps_mtx); 369 kern_sigprocmask(curthread, SIG_SETMASK, &newset, oldset, 370 SIGPROCMASK_PROC_LOCKED); 371 PROC_UNLOCK(curproc); 372 } 373 374 static void 375 autofs_restore_sigmask(sigset_t *set) 376 { 377 378 kern_sigprocmask(curthread, SIG_SETMASK, set, NULL, 0); 379 } 380 381 static int 382 autofs_trigger_one(struct autofs_node *anp, 383 const char *component, int componentlen) 384 { 385 sigset_t oldset; 386 struct autofs_mount *amp; 387 struct autofs_node *firstanp; 388 struct autofs_request *ar; 389 char *key, *path; 390 int error = 0, request_error, last; 391 bool wildcards; 392 393 amp = anp->an_mount; 394 395 sx_assert(&autofs_softc->sc_lock, SA_XLOCKED); 396 397 if (anp->an_parent == NULL) { 398 key = strndup(component, componentlen, M_AUTOFS); 399 } else { 400 for (firstanp = anp; firstanp->an_parent->an_parent != NULL; 401 firstanp = firstanp->an_parent) 402 continue; 403 key = strdup(firstanp->an_name, M_AUTOFS); 404 } 405 406 path = autofs_path(anp); 407 408 TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 409 if (strcmp(ar->ar_path, path) != 0) 410 continue; 411 if (strcmp(ar->ar_key, key) != 0) 412 continue; 413 414 KASSERT(strcmp(ar->ar_from, amp->am_from) == 0, 415 ("from changed; %s != %s", ar->ar_from, amp->am_from)); 416 KASSERT(strcmp(ar->ar_prefix, amp->am_prefix) == 0, 417 ("prefix changed; %s != %s", 418 ar->ar_prefix, amp->am_prefix)); 419 KASSERT(strcmp(ar->ar_options, amp->am_options) == 0, 420 ("options changed; %s != %s", 421 ar->ar_options, amp->am_options)); 422 423 break; 424 } 425 426 if (ar != NULL) { 427 refcount_acquire(&ar->ar_refcount); 428 } else { 429 ar = uma_zalloc(autofs_request_zone, M_WAITOK | M_ZERO); 430 ar->ar_mount = amp; 431 432 ar->ar_id = 433 atomic_fetchadd_int(&autofs_softc->sc_last_request_id, 1); 434 strlcpy(ar->ar_from, amp->am_from, sizeof(ar->ar_from)); 435 strlcpy(ar->ar_path, path, sizeof(ar->ar_path)); 436 strlcpy(ar->ar_prefix, amp->am_prefix, sizeof(ar->ar_prefix)); 437 strlcpy(ar->ar_key, key, sizeof(ar->ar_key)); 438 strlcpy(ar->ar_options, 439 amp->am_options, sizeof(ar->ar_options)); 440 441 TIMEOUT_TASK_INIT(taskqueue_thread, &ar->ar_task, 0, 442 autofs_task, ar); 443 taskqueue_enqueue_timeout(taskqueue_thread, &ar->ar_task, 444 autofs_timeout * hz); 445 refcount_init(&ar->ar_refcount, 1); 446 TAILQ_INSERT_TAIL(&autofs_softc->sc_requests, ar, ar_next); 447 } 448 449 cv_broadcast(&autofs_softc->sc_cv); 450 while (ar->ar_done == false) { 451 if (autofs_interruptible != 0) { 452 autofs_set_sigmask(&oldset); 453 error = cv_wait_sig(&autofs_softc->sc_cv, 454 &autofs_softc->sc_lock); 455 autofs_restore_sigmask(&oldset); 456 if (error != 0) { 457 AUTOFS_WARN("cv_wait_sig for %s failed " 458 "with error %d", ar->ar_path, error); 459 break; 460 } 461 } else { 462 cv_wait(&autofs_softc->sc_cv, &autofs_softc->sc_lock); 463 } 464 } 465 466 request_error = ar->ar_error; 467 if (request_error != 0) { 468 AUTOFS_WARN("request for %s completed with error %d, " 469 "pid %d (%s)", ar->ar_path, request_error, 470 curproc->p_pid, curproc->p_comm); 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 */ 511 int 512 autofs_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 || error == ERESTART) { 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 AUTOFS_DEBUG("trigger failed with error %d; will retry in " 537 "%d seconds, %d attempts left", error, autofs_retry_delay, 538 autofs_retry_attempts - anp->an_retries); 539 sx_xunlock(&autofs_softc->sc_lock); 540 pause("autofs_retry", autofs_retry_delay * hz); 541 sx_xlock(&autofs_softc->sc_lock); 542 } 543 } 544 545 static int 546 autofs_ioctl_request(struct autofs_daemon_request *adr) 547 { 548 struct autofs_request *ar; 549 int error; 550 551 sx_xlock(&autofs_softc->sc_lock); 552 for (;;) { 553 TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 554 if (ar->ar_done) 555 continue; 556 if (ar->ar_in_progress) 557 continue; 558 559 break; 560 } 561 562 if (ar != NULL) 563 break; 564 565 error = cv_wait_sig(&autofs_softc->sc_cv, 566 &autofs_softc->sc_lock); 567 if (error != 0) { 568 sx_xunlock(&autofs_softc->sc_lock); 569 return (error); 570 } 571 } 572 573 ar->ar_in_progress = true; 574 sx_xunlock(&autofs_softc->sc_lock); 575 576 adr->adr_id = ar->ar_id; 577 strlcpy(adr->adr_from, ar->ar_from, sizeof(adr->adr_from)); 578 strlcpy(adr->adr_path, ar->ar_path, sizeof(adr->adr_path)); 579 strlcpy(adr->adr_prefix, ar->ar_prefix, sizeof(adr->adr_prefix)); 580 strlcpy(adr->adr_key, ar->ar_key, sizeof(adr->adr_key)); 581 strlcpy(adr->adr_options, ar->ar_options, sizeof(adr->adr_options)); 582 583 PROC_LOCK(curproc); 584 autofs_softc->sc_dev_sid = curproc->p_session->s_sid; 585 PROC_UNLOCK(curproc); 586 587 return (0); 588 } 589 590 static int 591 autofs_ioctl_done_101(struct autofs_daemon_done_101 *add) 592 { 593 struct autofs_request *ar; 594 595 sx_xlock(&autofs_softc->sc_lock); 596 TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 597 if (ar->ar_id == add->add_id) 598 break; 599 } 600 601 if (ar == NULL) { 602 sx_xunlock(&autofs_softc->sc_lock); 603 AUTOFS_DEBUG("id %d not found", add->add_id); 604 return (ESRCH); 605 } 606 607 ar->ar_error = add->add_error; 608 ar->ar_wildcards = true; 609 ar->ar_done = true; 610 ar->ar_in_progress = false; 611 cv_broadcast(&autofs_softc->sc_cv); 612 613 sx_xunlock(&autofs_softc->sc_lock); 614 615 return (0); 616 } 617 618 static int 619 autofs_ioctl_done(struct autofs_daemon_done *add) 620 { 621 struct autofs_request *ar; 622 623 sx_xlock(&autofs_softc->sc_lock); 624 TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 625 if (ar->ar_id == add->add_id) 626 break; 627 } 628 629 if (ar == NULL) { 630 sx_xunlock(&autofs_softc->sc_lock); 631 AUTOFS_DEBUG("id %d not found", add->add_id); 632 return (ESRCH); 633 } 634 635 ar->ar_error = add->add_error; 636 ar->ar_wildcards = add->add_wildcards; 637 ar->ar_done = true; 638 ar->ar_in_progress = false; 639 cv_broadcast(&autofs_softc->sc_cv); 640 641 sx_xunlock(&autofs_softc->sc_lock); 642 643 return (0); 644 } 645 646 static int 647 autofs_open(struct cdev *dev, int flags, int fmt, struct thread *td) 648 { 649 650 sx_xlock(&autofs_softc->sc_lock); 651 /* 652 * We must never block automountd(8) and its descendants, and we use 653 * session ID to determine that: we store session id of the process 654 * that opened the device, and then compare it with session ids 655 * of triggering processes. This means running a second automountd(8) 656 * instance would break the previous one. The check below prevents 657 * it from happening. 658 */ 659 if (autofs_softc->sc_dev_opened) { 660 sx_xunlock(&autofs_softc->sc_lock); 661 return (EBUSY); 662 } 663 664 autofs_softc->sc_dev_opened = true; 665 sx_xunlock(&autofs_softc->sc_lock); 666 667 return (0); 668 } 669 670 static int 671 autofs_close(struct cdev *dev, int flag, int fmt, struct thread *td) 672 { 673 674 sx_xlock(&autofs_softc->sc_lock); 675 KASSERT(autofs_softc->sc_dev_opened, ("not opened?")); 676 autofs_softc->sc_dev_opened = false; 677 sx_xunlock(&autofs_softc->sc_lock); 678 679 return (0); 680 } 681 682 static int 683 autofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, 684 struct thread *td) 685 { 686 687 KASSERT(autofs_softc->sc_dev_opened, ("not opened?")); 688 689 switch (cmd) { 690 case AUTOFSREQUEST: 691 return (autofs_ioctl_request( 692 (struct autofs_daemon_request *)arg)); 693 case AUTOFSDONE101: 694 return (autofs_ioctl_done_101( 695 (struct autofs_daemon_done_101 *)arg)); 696 case AUTOFSDONE: 697 return (autofs_ioctl_done( 698 (struct autofs_daemon_done *)arg)); 699 default: 700 AUTOFS_DEBUG("invalid cmd %lx", cmd); 701 return (EINVAL); 702 } 703 } 704