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