1270096Strasz/*- 2270096Strasz * Copyright (c) 2014 The FreeBSD Foundation 3270096Strasz * All rights reserved. 4270096Strasz * 5270096Strasz * This software was developed by Edward Tomasz Napierala under sponsorship 6270096Strasz * from the FreeBSD Foundation. 7270096Strasz * 8270096Strasz * Redistribution and use in source and binary forms, with or without 9270096Strasz * modification, are permitted provided that the following conditions 10270096Strasz * are met: 11270096Strasz * 1. Redistributions of source code must retain the above copyright 12270096Strasz * notice, this list of conditions and the following disclaimer. 13270096Strasz * 2. Redistributions in binary form must reproduce the above copyright 14270096Strasz * notice, this list of conditions and the following disclaimer in the 15270096Strasz * documentation and/or other materials provided with the distribution. 16270096Strasz * 17270096Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18270096Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19270096Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20270096Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21270096Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22270096Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23270096Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24270096Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25270096Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26270096Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27270096Strasz * SUCH DAMAGE. 28270096Strasz * 29270096Strasz */ 30270096Strasz/*- 31270096Strasz * Copyright (c) 1989, 1991, 1993, 1995 32270096Strasz * The Regents of the University of California. All rights reserved. 33270096Strasz * 34270096Strasz * This code is derived from software contributed to Berkeley by 35270096Strasz * Rick Macklem at The University of Guelph. 36270096Strasz * 37270096Strasz * Redistribution and use in source and binary forms, with or without 38270096Strasz * modification, are permitted provided that the following conditions 39270096Strasz * are met: 40270096Strasz * 1. Redistributions of source code must retain the above copyright 41270096Strasz * notice, this list of conditions and the following disclaimer. 42270096Strasz * 2. Redistributions in binary form must reproduce the above copyright 43270096Strasz * notice, this list of conditions and the following disclaimer in the 44270096Strasz * documentation and/or other materials provided with the distribution. 45270096Strasz * 4. Neither the name of the University nor the names of its contributors 46270096Strasz * may be used to endorse or promote products derived from this software 47270096Strasz * without specific prior written permission. 48270096Strasz * 49270096Strasz * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50270096Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51270096Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52270096Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53270096Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54270096Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55270096Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56270096Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57270096Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58270096Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59270096Strasz * SUCH DAMAGE. 60270096Strasz * 61270096Strasz */ 62270096Strasz 63270897Strasz#include <sys/cdefs.h> 64270897Strasz __FBSDID("$FreeBSD: releng/10.3/sys/fs/autofs/autofs.c 279749 2015-03-07 20:00:26Z trasz $"); 65270897Strasz 66270096Strasz#include <sys/param.h> 67270096Strasz#include <sys/systm.h> 68270096Strasz#include <sys/buf.h> 69270096Strasz#include <sys/conf.h> 70270096Strasz#include <sys/dirent.h> 71270096Strasz#include <sys/ioccom.h> 72270096Strasz#include <sys/kernel.h> 73270096Strasz#include <sys/module.h> 74270096Strasz#include <sys/mount.h> 75270096Strasz#include <sys/refcount.h> 76270096Strasz#include <sys/sx.h> 77270096Strasz#include <sys/sysctl.h> 78270096Strasz#include <sys/syscallsubr.h> 79274232Strasz#include <sys/taskqueue.h> 80270096Strasz#include <sys/vnode.h> 81270096Strasz#include <machine/atomic.h> 82270096Strasz#include <vm/uma.h> 83270096Strasz 84270898Strasz#include <fs/autofs/autofs.h> 85270898Strasz#include <fs/autofs/autofs_ioctl.h> 86270096Strasz 87270096StraszMALLOC_DEFINE(M_AUTOFS, "autofs", "Automounter filesystem"); 88270096Strasz 89270096Straszuma_zone_t autofs_request_zone; 90270096Straszuma_zone_t autofs_node_zone; 91270096Strasz 92270096Straszstatic int autofs_open(struct cdev *dev, int flags, int fmt, 93270096Strasz struct thread *td); 94270096Straszstatic int autofs_close(struct cdev *dev, int flag, int fmt, 95270096Strasz struct thread *td); 96270096Straszstatic int autofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, 97270096Strasz int mode, struct thread *td); 98270096Strasz 99270096Straszstatic struct cdevsw autofs_cdevsw = { 100270096Strasz .d_version = D_VERSION, 101270096Strasz .d_open = autofs_open, 102270096Strasz .d_close = autofs_close, 103270096Strasz .d_ioctl = autofs_ioctl, 104270096Strasz .d_name = "autofs", 105270096Strasz}; 106270096Strasz 107270096Strasz/* 108270096Strasz * List of signals that can interrupt an autofs trigger. Might be a good 109270096Strasz * idea to keep it synchronised with list in sys/fs/nfs/nfs_commonkrpc.c. 110270096Strasz */ 111270096Straszint autofs_sig_set[] = { 112270096Strasz SIGINT, 113270096Strasz SIGTERM, 114270096Strasz SIGHUP, 115270096Strasz SIGKILL, 116270096Strasz SIGQUIT 117270096Strasz}; 118270096Strasz 119270900Straszstruct autofs_softc *autofs_softc; 120270096Strasz 121270096StraszSYSCTL_NODE(_vfs, OID_AUTO, autofs, CTLFLAG_RD, 0, "Automounter filesystem"); 122270096Straszint autofs_debug = 1; 123270096StraszTUNABLE_INT("vfs.autofs.debug", &autofs_debug); 124270096StraszSYSCTL_INT(_vfs_autofs, OID_AUTO, debug, CTLFLAG_RWTUN, 125270096Strasz &autofs_debug, 1, "Enable debug messages"); 126270096Straszint autofs_mount_on_stat = 0; 127270096StraszTUNABLE_INT("vfs.autofs.mount_on_stat", &autofs_mount_on_stat); 128270096StraszSYSCTL_INT(_vfs_autofs, OID_AUTO, mount_on_stat, CTLFLAG_RWTUN, 129270096Strasz &autofs_mount_on_stat, 0, "Trigger mount on stat(2) on mountpoint"); 130270096Straszint autofs_timeout = 30; 131270096StraszTUNABLE_INT("vfs.autofs.timeout", &autofs_timeout); 132270096StraszSYSCTL_INT(_vfs_autofs, OID_AUTO, timeout, CTLFLAG_RWTUN, 133270096Strasz &autofs_timeout, 30, "Number of seconds to wait for automountd(8)"); 134270096Straszint autofs_cache = 600; 135270096StraszTUNABLE_INT("vfs.autofs.cache", &autofs_cache); 136270096StraszSYSCTL_INT(_vfs_autofs, OID_AUTO, cache, CTLFLAG_RWTUN, 137270096Strasz &autofs_cache, 600, "Number of seconds to wait before reinvoking " 138270096Strasz "automountd(8) for any given file or directory"); 139270096Straszint autofs_retry_attempts = 3; 140270096StraszTUNABLE_INT("vfs.autofs.retry_attempts", &autofs_retry_attempts); 141270096StraszSYSCTL_INT(_vfs_autofs, OID_AUTO, retry_attempts, CTLFLAG_RWTUN, 142270096Strasz &autofs_retry_attempts, 3, "Number of attempts before failing mount"); 143270096Straszint autofs_retry_delay = 1; 144270096StraszTUNABLE_INT("vfs.autofs.retry_delay", &autofs_retry_delay); 145270096StraszSYSCTL_INT(_vfs_autofs, OID_AUTO, retry_delay, CTLFLAG_RWTUN, 146270096Strasz &autofs_retry_delay, 1, "Number of seconds before retrying"); 147270096Straszint autofs_interruptible = 1; 148270096StraszTUNABLE_INT("vfs.autofs.interruptible", &autofs_interruptible); 149270096StraszSYSCTL_INT(_vfs_autofs, OID_AUTO, interruptible, CTLFLAG_RWTUN, 150270096Strasz &autofs_interruptible, 1, "Allow requests to be interrupted by signal"); 151270096Strasz 152270096Straszint 153270096Straszautofs_init(struct vfsconf *vfsp) 154270096Strasz{ 155270096Strasz int error; 156270096Strasz 157270900Strasz KASSERT(autofs_softc == NULL, 158270900Strasz ("softc %p, should be NULL", autofs_softc)); 159270096Strasz 160270900Strasz autofs_softc = malloc(sizeof(*autofs_softc), M_AUTOFS, 161270900Strasz M_WAITOK | M_ZERO); 162270900Strasz 163270096Strasz autofs_request_zone = uma_zcreate("autofs_request", 164270096Strasz sizeof(struct autofs_request), NULL, NULL, NULL, NULL, 165270096Strasz UMA_ALIGN_PTR, 0); 166270096Strasz autofs_node_zone = uma_zcreate("autofs_node", 167270096Strasz sizeof(struct autofs_node), NULL, NULL, NULL, NULL, 168270096Strasz UMA_ALIGN_PTR, 0); 169270096Strasz 170270900Strasz TAILQ_INIT(&autofs_softc->sc_requests); 171270900Strasz cv_init(&autofs_softc->sc_cv, "autofscv"); 172270900Strasz sx_init(&autofs_softc->sc_lock, "autofslk"); 173270096Strasz 174270900Strasz error = make_dev_p(MAKEDEV_CHECKNAME, &autofs_softc->sc_cdev, 175270900Strasz &autofs_cdevsw, NULL, UID_ROOT, GID_WHEEL, 0600, "autofs"); 176270096Strasz if (error != 0) { 177270096Strasz AUTOFS_WARN("failed to create device node, error %d", error); 178270900Strasz uma_zdestroy(autofs_request_zone); 179270900Strasz uma_zdestroy(autofs_node_zone); 180270900Strasz free(autofs_softc, M_AUTOFS); 181270900Strasz 182270096Strasz return (error); 183270096Strasz } 184270900Strasz autofs_softc->sc_cdev->si_drv1 = autofs_softc; 185270096Strasz 186270096Strasz return (0); 187270096Strasz} 188270096Strasz 189270096Straszint 190270096Straszautofs_uninit(struct vfsconf *vfsp) 191270096Strasz{ 192270096Strasz 193270900Strasz sx_xlock(&autofs_softc->sc_lock); 194270900Strasz if (autofs_softc->sc_dev_opened) { 195270900Strasz sx_xunlock(&autofs_softc->sc_lock); 196270096Strasz return (EBUSY); 197270096Strasz } 198270900Strasz if (autofs_softc->sc_cdev != NULL) 199270900Strasz destroy_dev(autofs_softc->sc_cdev); 200270096Strasz 201270096Strasz uma_zdestroy(autofs_request_zone); 202270096Strasz uma_zdestroy(autofs_node_zone); 203270096Strasz 204270900Strasz sx_xunlock(&autofs_softc->sc_lock); 205270096Strasz /* 206270096Strasz * XXX: Race with open? 207270096Strasz */ 208270900Strasz free(autofs_softc, M_AUTOFS); 209270096Strasz 210270096Strasz return (0); 211270096Strasz} 212270096Strasz 213270096Straszbool 214270096Straszautofs_ignore_thread(const struct thread *td) 215270096Strasz{ 216270096Strasz struct proc *p; 217270096Strasz 218270096Strasz p = td->td_proc; 219270096Strasz 220270900Strasz if (autofs_softc->sc_dev_opened == false) 221270096Strasz return (false); 222270096Strasz 223270096Strasz PROC_LOCK(p); 224270900Strasz if (p->p_session->s_sid == autofs_softc->sc_dev_sid) { 225270096Strasz PROC_UNLOCK(p); 226270096Strasz return (true); 227270096Strasz } 228270096Strasz PROC_UNLOCK(p); 229270096Strasz 230270096Strasz return (false); 231270096Strasz} 232270096Strasz 233270096Straszstatic char * 234270096Straszautofs_path(struct autofs_node *anp) 235270096Strasz{ 236270096Strasz struct autofs_mount *amp; 237270096Strasz char *path, *tmp; 238270096Strasz 239270096Strasz amp = anp->an_mount; 240270096Strasz 241270096Strasz path = strdup("", M_AUTOFS); 242270096Strasz for (; anp->an_parent != NULL; anp = anp->an_parent) { 243270096Strasz tmp = malloc(strlen(anp->an_name) + strlen(path) + 2, 244270096Strasz M_AUTOFS, M_WAITOK); 245270096Strasz strcpy(tmp, anp->an_name); 246270096Strasz strcat(tmp, "/"); 247270096Strasz strcat(tmp, path); 248270096Strasz free(path, M_AUTOFS); 249270096Strasz path = tmp; 250270096Strasz } 251270096Strasz 252270096Strasz tmp = malloc(strlen(amp->am_mountpoint) + strlen(path) + 2, 253270096Strasz M_AUTOFS, M_WAITOK); 254270096Strasz strcpy(tmp, amp->am_mountpoint); 255270096Strasz strcat(tmp, "/"); 256270096Strasz strcat(tmp, path); 257270096Strasz free(path, M_AUTOFS); 258270096Strasz path = tmp; 259270096Strasz 260270096Strasz return (path); 261270096Strasz} 262270096Strasz 263270096Straszstatic void 264274232Straszautofs_task(void *context, int pending) 265270096Strasz{ 266270096Strasz struct autofs_request *ar; 267270096Strasz 268270096Strasz ar = context; 269270096Strasz 270270900Strasz sx_xlock(&autofs_softc->sc_lock); 271270096Strasz AUTOFS_WARN("request %d for %s timed out after %d seconds", 272270096Strasz ar->ar_id, ar->ar_path, autofs_timeout); 273270096Strasz /* 274270096Strasz * XXX: EIO perhaps? 275270096Strasz */ 276270096Strasz ar->ar_error = ETIMEDOUT; 277279741Strasz ar->ar_wildcards = true; 278270096Strasz ar->ar_done = true; 279270096Strasz ar->ar_in_progress = false; 280270900Strasz cv_broadcast(&autofs_softc->sc_cv); 281270900Strasz sx_xunlock(&autofs_softc->sc_lock); 282270096Strasz} 283270096Strasz 284270096Straszbool 285270096Straszautofs_cached(struct autofs_node *anp, const char *component, int componentlen) 286270096Strasz{ 287270096Strasz int error; 288270096Strasz struct autofs_mount *amp; 289270096Strasz 290270096Strasz amp = anp->an_mount; 291270096Strasz 292270096Strasz AUTOFS_ASSERT_UNLOCKED(amp); 293270096Strasz 294270096Strasz /* 295279741Strasz * For root node we need to request automountd(8) assistance even 296279741Strasz * if the node is marked as cached, but the requested top-level 297279741Strasz * directory does not exist. This is necessary for wildcard indirect 298279741Strasz * map keys to work. We don't do this if we know that there are 299279741Strasz * no wildcards. 300270096Strasz */ 301279741Strasz if (anp->an_parent == NULL && componentlen != 0 && anp->an_wildcards) { 302274234Strasz AUTOFS_SLOCK(amp); 303270096Strasz error = autofs_node_find(anp, component, componentlen, NULL); 304274234Strasz AUTOFS_SUNLOCK(amp); 305270096Strasz if (error != 0) 306270096Strasz return (false); 307270096Strasz } 308270096Strasz 309270096Strasz return (anp->an_cached); 310270096Strasz} 311270096Strasz 312270096Straszstatic void 313270096Straszautofs_cache_callout(void *context) 314270096Strasz{ 315270096Strasz struct autofs_node *anp; 316270096Strasz 317270096Strasz anp = context; 318270096Strasz anp->an_cached = false; 319270096Strasz} 320270096Strasz 321279742Straszvoid 322279742Straszautofs_flush(struct autofs_mount *amp) 323279742Strasz{ 324279742Strasz 325279742Strasz /* 326279742Strasz * XXX: This will do for now, but ideally we should iterate 327279742Strasz * over all the nodes. 328279742Strasz */ 329279742Strasz amp->am_root->an_cached = false; 330279742Strasz AUTOFS_DEBUG("%s flushed", amp->am_mountpoint); 331279742Strasz} 332279742Strasz 333270096Strasz/* 334270096Strasz * The set/restore sigmask functions are used to (temporarily) overwrite 335270096Strasz * the thread td_sigmask during triggering. 336270096Strasz */ 337270096Straszstatic void 338270096Straszautofs_set_sigmask(sigset_t *oldset) 339270096Strasz{ 340270096Strasz sigset_t newset; 341270096Strasz int i; 342270096Strasz 343270096Strasz SIGFILLSET(newset); 344270096Strasz /* Remove the autofs set of signals from newset */ 345270096Strasz PROC_LOCK(curproc); 346270096Strasz mtx_lock(&curproc->p_sigacts->ps_mtx); 347270096Strasz for (i = 0 ; i < sizeof(autofs_sig_set)/sizeof(int) ; i++) { 348270096Strasz /* 349270096Strasz * But make sure we leave the ones already masked 350270096Strasz * by the process, i.e. remove the signal from the 351270096Strasz * temporary signalmask only if it wasn't already 352270096Strasz * in p_sigmask. 353270096Strasz */ 354270096Strasz if (!SIGISMEMBER(curthread->td_sigmask, autofs_sig_set[i]) && 355270096Strasz !SIGISMEMBER(curproc->p_sigacts->ps_sigignore, 356270096Strasz autofs_sig_set[i])) { 357270096Strasz SIGDELSET(newset, autofs_sig_set[i]); 358270096Strasz } 359270096Strasz } 360270096Strasz mtx_unlock(&curproc->p_sigacts->ps_mtx); 361270096Strasz kern_sigprocmask(curthread, SIG_SETMASK, &newset, oldset, 362270096Strasz SIGPROCMASK_PROC_LOCKED); 363270096Strasz PROC_UNLOCK(curproc); 364270096Strasz} 365270096Strasz 366270096Straszstatic void 367270096Straszautofs_restore_sigmask(sigset_t *set) 368270096Strasz{ 369270096Strasz 370270096Strasz kern_sigprocmask(curthread, SIG_SETMASK, set, NULL, 0); 371270096Strasz} 372270096Strasz 373270096Straszstatic int 374270096Straszautofs_trigger_one(struct autofs_node *anp, 375270096Strasz const char *component, int componentlen) 376270096Strasz{ 377270096Strasz sigset_t oldset; 378270096Strasz struct autofs_mount *amp; 379270096Strasz struct autofs_node *firstanp; 380270096Strasz struct autofs_request *ar; 381270096Strasz char *key, *path; 382270096Strasz int error = 0, request_error, last; 383279741Strasz bool wildcards; 384270096Strasz 385274237Strasz amp = anp->an_mount; 386270096Strasz 387270900Strasz sx_assert(&autofs_softc->sc_lock, SA_XLOCKED); 388270096Strasz 389270096Strasz if (anp->an_parent == NULL) { 390270096Strasz key = strndup(component, componentlen, M_AUTOFS); 391270096Strasz } else { 392270096Strasz for (firstanp = anp; firstanp->an_parent->an_parent != NULL; 393270096Strasz firstanp = firstanp->an_parent) 394270096Strasz continue; 395270096Strasz key = strdup(firstanp->an_name, M_AUTOFS); 396270096Strasz } 397270096Strasz 398270096Strasz path = autofs_path(anp); 399270096Strasz 400270900Strasz TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 401270096Strasz if (strcmp(ar->ar_path, path) != 0) 402270096Strasz continue; 403270096Strasz if (strcmp(ar->ar_key, key) != 0) 404270096Strasz continue; 405270096Strasz 406270096Strasz KASSERT(strcmp(ar->ar_from, amp->am_from) == 0, 407270096Strasz ("from changed; %s != %s", ar->ar_from, amp->am_from)); 408270096Strasz KASSERT(strcmp(ar->ar_prefix, amp->am_prefix) == 0, 409270096Strasz ("prefix changed; %s != %s", 410270096Strasz ar->ar_prefix, amp->am_prefix)); 411270096Strasz KASSERT(strcmp(ar->ar_options, amp->am_options) == 0, 412270096Strasz ("options changed; %s != %s", 413270096Strasz ar->ar_options, amp->am_options)); 414270096Strasz 415270096Strasz break; 416270096Strasz } 417270096Strasz 418270096Strasz if (ar != NULL) { 419270096Strasz refcount_acquire(&ar->ar_refcount); 420270096Strasz } else { 421270096Strasz ar = uma_zalloc(autofs_request_zone, M_WAITOK | M_ZERO); 422270096Strasz ar->ar_mount = amp; 423270096Strasz 424270900Strasz ar->ar_id = 425270900Strasz atomic_fetchadd_int(&autofs_softc->sc_last_request_id, 1); 426270096Strasz strlcpy(ar->ar_from, amp->am_from, sizeof(ar->ar_from)); 427270096Strasz strlcpy(ar->ar_path, path, sizeof(ar->ar_path)); 428270096Strasz strlcpy(ar->ar_prefix, amp->am_prefix, sizeof(ar->ar_prefix)); 429270096Strasz strlcpy(ar->ar_key, key, sizeof(ar->ar_key)); 430270096Strasz strlcpy(ar->ar_options, 431270096Strasz amp->am_options, sizeof(ar->ar_options)); 432270096Strasz 433274232Strasz TIMEOUT_TASK_INIT(taskqueue_thread, &ar->ar_task, 0, 434274232Strasz autofs_task, ar); 435274232Strasz error = taskqueue_enqueue_timeout(taskqueue_thread, 436274232Strasz &ar->ar_task, autofs_timeout * hz); 437274232Strasz if (error != 0) { 438274232Strasz AUTOFS_WARN("taskqueue_enqueue_timeout() failed " 439274232Strasz "with error %d", error); 440274232Strasz } 441270096Strasz refcount_init(&ar->ar_refcount, 1); 442270900Strasz TAILQ_INSERT_TAIL(&autofs_softc->sc_requests, ar, ar_next); 443270096Strasz } 444270096Strasz 445270900Strasz cv_broadcast(&autofs_softc->sc_cv); 446270096Strasz while (ar->ar_done == false) { 447270096Strasz if (autofs_interruptible != 0) { 448270096Strasz autofs_set_sigmask(&oldset); 449270900Strasz error = cv_wait_sig(&autofs_softc->sc_cv, 450270900Strasz &autofs_softc->sc_lock); 451270096Strasz autofs_restore_sigmask(&oldset); 452270096Strasz if (error != 0) { 453270096Strasz AUTOFS_WARN("cv_wait_sig for %s failed " 454270096Strasz "with error %d", ar->ar_path, error); 455270096Strasz break; 456270096Strasz } 457270096Strasz } else { 458270900Strasz cv_wait(&autofs_softc->sc_cv, &autofs_softc->sc_lock); 459270096Strasz } 460270096Strasz } 461270096Strasz 462270096Strasz request_error = ar->ar_error; 463270096Strasz if (request_error != 0) { 464270096Strasz AUTOFS_WARN("request for %s completed with error %d", 465270096Strasz ar->ar_path, request_error); 466270096Strasz } 467270096Strasz 468279741Strasz wildcards = ar->ar_wildcards; 469279741Strasz 470270096Strasz last = refcount_release(&ar->ar_refcount); 471270096Strasz if (last) { 472270900Strasz TAILQ_REMOVE(&autofs_softc->sc_requests, ar, ar_next); 473270096Strasz /* 474274233Strasz * Unlock the sc_lock, so that autofs_task() can complete. 475270096Strasz */ 476270900Strasz sx_xunlock(&autofs_softc->sc_lock); 477274232Strasz taskqueue_cancel_timeout(taskqueue_thread, &ar->ar_task, NULL); 478274232Strasz taskqueue_drain_timeout(taskqueue_thread, &ar->ar_task); 479274233Strasz uma_zfree(autofs_request_zone, ar); 480270900Strasz sx_xlock(&autofs_softc->sc_lock); 481270096Strasz } 482270096Strasz 483270096Strasz /* 484270096Strasz * Note that we do not do negative caching on purpose. This 485270096Strasz * way the user can retry access at any time, e.g. after fixing 486270096Strasz * the failure reason, without waiting for cache timer to expire. 487270096Strasz */ 488270096Strasz if (error == 0 && request_error == 0 && autofs_cache > 0) { 489270096Strasz anp->an_cached = true; 490279741Strasz anp->an_wildcards = wildcards; 491270096Strasz callout_reset(&anp->an_callout, autofs_cache * hz, 492270096Strasz autofs_cache_callout, anp); 493270096Strasz } 494270096Strasz 495270096Strasz free(key, M_AUTOFS); 496270096Strasz free(path, M_AUTOFS); 497270096Strasz 498270096Strasz if (error != 0) 499270096Strasz return (error); 500270096Strasz return (request_error); 501270096Strasz} 502270096Strasz 503270096Strasz/* 504270096Strasz * Send request to automountd(8) and wait for completion. 505270096Strasz */ 506270096Straszint 507270096Straszautofs_trigger(struct autofs_node *anp, 508270096Strasz const char *component, int componentlen) 509270096Strasz{ 510270096Strasz int error; 511270096Strasz 512270096Strasz for (;;) { 513270096Strasz error = autofs_trigger_one(anp, component, componentlen); 514270096Strasz if (error == 0) { 515270096Strasz anp->an_retries = 0; 516270096Strasz return (0); 517270096Strasz } 518279749Strasz if (error == EINTR || error == ERESTART) { 519270096Strasz AUTOFS_DEBUG("trigger interrupted by signal, " 520270096Strasz "not retrying"); 521270096Strasz anp->an_retries = 0; 522270096Strasz return (error); 523270096Strasz } 524270096Strasz anp->an_retries++; 525270096Strasz if (anp->an_retries >= autofs_retry_attempts) { 526270096Strasz AUTOFS_DEBUG("trigger failed %d times; returning " 527270096Strasz "error %d", anp->an_retries, error); 528270096Strasz anp->an_retries = 0; 529270096Strasz return (error); 530270096Strasz 531270096Strasz } 532270096Strasz AUTOFS_DEBUG("trigger failed with error %d; will retry in " 533270096Strasz "%d seconds, %d attempts left", error, autofs_retry_delay, 534270096Strasz autofs_retry_attempts - anp->an_retries); 535270900Strasz sx_xunlock(&autofs_softc->sc_lock); 536270096Strasz pause("autofs_retry", autofs_retry_delay * hz); 537270900Strasz sx_xlock(&autofs_softc->sc_lock); 538270096Strasz } 539270096Strasz} 540270096Strasz 541270096Straszstatic int 542270900Straszautofs_ioctl_request(struct autofs_daemon_request *adr) 543270096Strasz{ 544270096Strasz struct autofs_request *ar; 545270096Strasz int error; 546270096Strasz 547270900Strasz sx_xlock(&autofs_softc->sc_lock); 548270096Strasz for (;;) { 549270900Strasz TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 550270096Strasz if (ar->ar_done) 551270096Strasz continue; 552270096Strasz if (ar->ar_in_progress) 553270096Strasz continue; 554270096Strasz 555270096Strasz break; 556270096Strasz } 557270096Strasz 558270096Strasz if (ar != NULL) 559270096Strasz break; 560270096Strasz 561270900Strasz error = cv_wait_sig(&autofs_softc->sc_cv, 562270900Strasz &autofs_softc->sc_lock); 563270096Strasz if (error != 0) { 564270900Strasz sx_xunlock(&autofs_softc->sc_lock); 565270096Strasz AUTOFS_DEBUG("failed with error %d", error); 566270096Strasz return (error); 567270096Strasz } 568270096Strasz } 569270096Strasz 570270096Strasz ar->ar_in_progress = true; 571270900Strasz sx_xunlock(&autofs_softc->sc_lock); 572270096Strasz 573270096Strasz adr->adr_id = ar->ar_id; 574270096Strasz strlcpy(adr->adr_from, ar->ar_from, sizeof(adr->adr_from)); 575270096Strasz strlcpy(adr->adr_path, ar->ar_path, sizeof(adr->adr_path)); 576270096Strasz strlcpy(adr->adr_prefix, ar->ar_prefix, sizeof(adr->adr_prefix)); 577270096Strasz strlcpy(adr->adr_key, ar->ar_key, sizeof(adr->adr_key)); 578270096Strasz strlcpy(adr->adr_options, ar->ar_options, sizeof(adr->adr_options)); 579270096Strasz 580270096Strasz PROC_LOCK(curproc); 581270900Strasz autofs_softc->sc_dev_sid = curproc->p_session->s_sid; 582270096Strasz PROC_UNLOCK(curproc); 583270096Strasz 584270096Strasz return (0); 585270096Strasz} 586270096Strasz 587270096Straszstatic int 588279741Straszautofs_ioctl_done_101(struct autofs_daemon_done_101 *add) 589279741Strasz{ 590279741Strasz struct autofs_request *ar; 591279741Strasz 592279741Strasz sx_xlock(&autofs_softc->sc_lock); 593279741Strasz TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 594279741Strasz if (ar->ar_id == add->add_id) 595279741Strasz break; 596279741Strasz } 597279741Strasz 598279741Strasz if (ar == NULL) { 599279741Strasz sx_xunlock(&autofs_softc->sc_lock); 600279741Strasz AUTOFS_DEBUG("id %d not found", add->add_id); 601279741Strasz return (ESRCH); 602279741Strasz } 603279741Strasz 604279741Strasz ar->ar_error = add->add_error; 605279741Strasz ar->ar_wildcards = true; 606279741Strasz ar->ar_done = true; 607279741Strasz ar->ar_in_progress = false; 608279741Strasz cv_broadcast(&autofs_softc->sc_cv); 609279741Strasz 610279741Strasz sx_xunlock(&autofs_softc->sc_lock); 611279741Strasz 612279741Strasz return (0); 613279741Strasz} 614279741Strasz 615279741Straszstatic int 616270900Straszautofs_ioctl_done(struct autofs_daemon_done *add) 617270096Strasz{ 618270096Strasz struct autofs_request *ar; 619270096Strasz 620270900Strasz sx_xlock(&autofs_softc->sc_lock); 621270900Strasz TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 622270096Strasz if (ar->ar_id == add->add_id) 623270096Strasz break; 624270096Strasz } 625270096Strasz 626270096Strasz if (ar == NULL) { 627270900Strasz sx_xunlock(&autofs_softc->sc_lock); 628270096Strasz AUTOFS_DEBUG("id %d not found", add->add_id); 629270096Strasz return (ESRCH); 630270096Strasz } 631270096Strasz 632270096Strasz ar->ar_error = add->add_error; 633279741Strasz ar->ar_wildcards = add->add_wildcards; 634270096Strasz ar->ar_done = true; 635270096Strasz ar->ar_in_progress = false; 636270900Strasz cv_broadcast(&autofs_softc->sc_cv); 637270096Strasz 638270900Strasz sx_xunlock(&autofs_softc->sc_lock); 639270096Strasz 640270096Strasz return (0); 641270096Strasz} 642270096Strasz 643270096Straszstatic int 644270096Straszautofs_open(struct cdev *dev, int flags, int fmt, struct thread *td) 645270096Strasz{ 646270096Strasz 647270900Strasz sx_xlock(&autofs_softc->sc_lock); 648270899Strasz /* 649270899Strasz * We must never block automountd(8) and its descendants, and we use 650270899Strasz * session ID to determine that: we store session id of the process 651270899Strasz * that opened the device, and then compare it with session ids 652270899Strasz * of triggering processes. This means running a second automountd(8) 653270899Strasz * instance would break the previous one. The check below prevents 654270899Strasz * it from happening. 655270899Strasz */ 656270900Strasz if (autofs_softc->sc_dev_opened) { 657270900Strasz sx_xunlock(&autofs_softc->sc_lock); 658270096Strasz return (EBUSY); 659270096Strasz } 660270096Strasz 661270900Strasz autofs_softc->sc_dev_opened = true; 662270900Strasz sx_xunlock(&autofs_softc->sc_lock); 663270096Strasz 664270096Strasz return (0); 665270096Strasz} 666270096Strasz 667270096Straszstatic int 668270096Straszautofs_close(struct cdev *dev, int flag, int fmt, struct thread *td) 669270096Strasz{ 670270096Strasz 671270900Strasz sx_xlock(&autofs_softc->sc_lock); 672270900Strasz KASSERT(autofs_softc->sc_dev_opened, ("not opened?")); 673270900Strasz autofs_softc->sc_dev_opened = false; 674270900Strasz sx_xunlock(&autofs_softc->sc_lock); 675270096Strasz 676270096Strasz return (0); 677270096Strasz} 678270096Strasz 679270096Straszstatic int 680270096Straszautofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, 681270096Strasz struct thread *td) 682270096Strasz{ 683270096Strasz 684270900Strasz KASSERT(autofs_softc->sc_dev_opened, ("not opened?")); 685270096Strasz 686270096Strasz switch (cmd) { 687270096Strasz case AUTOFSREQUEST: 688270900Strasz return (autofs_ioctl_request( 689270096Strasz (struct autofs_daemon_request *)arg)); 690279741Strasz case AUTOFSDONE101: 691279741Strasz return (autofs_ioctl_done_101( 692279741Strasz (struct autofs_daemon_done_101 *)arg)); 693270096Strasz case AUTOFSDONE: 694270900Strasz return (autofs_ioctl_done( 695270096Strasz (struct autofs_daemon_done *)arg)); 696270096Strasz default: 697270096Strasz AUTOFS_DEBUG("invalid cmd %lx", cmd); 698270096Strasz return (EINVAL); 699270096Strasz } 700270096Strasz} 701