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