The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/autofs/autofs.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 57f373c76825ede2ee1f32ffc439aa73


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.