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