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