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