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/lockd/svc.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  * linux/fs/lockd/svc.c
    3  *
    4  * This is the central lockd service.
    5  *
    6  * FIXME: Separate the lockd NFS server functionality from the lockd NFS
    7  *        client functionality. Oh why didn't Sun create two separate
    8  *        services in the first place?
    9  *
   10  * Authors:     Olaf Kirch (okir@monad.swb.de)
   11  *
   12  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
   13  */
   14 
   15 #define __KERNEL_SYSCALLS__
   16 #include <linux/config.h>
   17 #include <linux/module.h>
   18 #include <linux/init.h>
   19 
   20 #include <linux/sched.h>
   21 #include <linux/errno.h>
   22 #include <linux/in.h>
   23 #include <linux/uio.h>
   24 #include <linux/version.h>
   25 #include <linux/unistd.h>
   26 #include <linux/slab.h>
   27 #include <linux/smp.h>
   28 #include <linux/smp_lock.h>
   29 
   30 #include <linux/sunrpc/types.h>
   31 #include <linux/sunrpc/stats.h>
   32 #include <linux/sunrpc/clnt.h>
   33 #include <linux/sunrpc/svc.h>
   34 #include <linux/sunrpc/svcsock.h>
   35 #include <linux/lockd/lockd.h>
   36 #include <linux/nfs.h>
   37 
   38 #define NLMDBG_FACILITY         NLMDBG_SVC
   39 #define LOCKD_BUFSIZE           (1024 + NLMSSVC_XDRSIZE)
   40 #define ALLOWED_SIGS            (sigmask(SIGKILL))
   41 
   42 extern struct svc_program       nlmsvc_program;
   43 struct nlmsvc_binding *         nlmsvc_ops;
   44 static DECLARE_MUTEX(nlmsvc_sema);
   45 static unsigned int             nlmsvc_users;
   46 static pid_t                    nlmsvc_pid;
   47 int                             nlmsvc_grace_period;
   48 unsigned long                   nlmsvc_timeout;
   49 
   50 static DECLARE_MUTEX_LOCKED(lockd_start);
   51 static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
   52 
   53 /*
   54  * Currently the following can be set only at insmod time.
   55  * Ideally, they would be accessible through the sysctl interface.
   56  */
   57 unsigned long                   nlm_grace_period;
   58 unsigned long                   nlm_timeout = LOCKD_DFLT_TIMEO;
   59 unsigned long                   nlm_udpport, nlm_tcpport;
   60 
   61 static unsigned long set_grace_period(void)
   62 {
   63         unsigned long grace_period;
   64 
   65         /* Note: nlm_timeout should always be nonzero */
   66         if (nlm_grace_period)
   67                 grace_period = ((nlm_grace_period + nlm_timeout - 1)
   68                                 / nlm_timeout) * nlm_timeout * HZ;
   69         else
   70                 grace_period = nlm_timeout * 5 * HZ;
   71         nlmsvc_grace_period = 1;
   72         return grace_period + jiffies;
   73 }
   74 
   75 /*
   76  * This is the lockd kernel thread
   77  */
   78 static void
   79 lockd(struct svc_rqst *rqstp)
   80 {
   81         struct svc_serv *serv = rqstp->rq_server;
   82         int             err = 0;
   83         unsigned long grace_period_expire;
   84 
   85         /* Lock module and set up kernel thread */
   86         MOD_INC_USE_COUNT;
   87         lock_kernel();
   88 
   89         /*
   90          * Let our maker know we're running.
   91          */
   92         nlmsvc_pid = current->pid;
   93         up(&lockd_start);
   94 
   95         daemonize();
   96         reparent_to_init();
   97         sprintf(current->comm, "lockd");
   98 
   99         /* Process request with signals blocked.  */
  100         spin_lock_irq(&current->sigmask_lock);
  101         siginitsetinv(&current->blocked, sigmask(SIGKILL));
  102         recalc_sigpending(current);
  103         spin_unlock_irq(&current->sigmask_lock);
  104 
  105         /* kick rpciod */
  106         rpciod_up();
  107 
  108         dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
  109 
  110         if (!nlm_timeout)
  111                 nlm_timeout = LOCKD_DFLT_TIMEO;
  112         nlmsvc_timeout = nlm_timeout * HZ;
  113 
  114         grace_period_expire = set_grace_period();
  115 
  116         /*
  117          * The main request loop. We don't terminate until the last
  118          * NFS mount or NFS daemon has gone away, and we've been sent a
  119          * signal, or else another process has taken over our job.
  120          */
  121         while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid)
  122         {
  123                 long timeout = MAX_SCHEDULE_TIMEOUT;
  124                 if (signalled()) {
  125                         spin_lock_irq(&current->sigmask_lock);
  126                         flush_signals(current);
  127                         spin_unlock_irq(&current->sigmask_lock);
  128                         if (nlmsvc_ops) {
  129                                 nlmsvc_ops->detach();
  130                                 grace_period_expire = set_grace_period();
  131                         }
  132                 }
  133 
  134                 /*
  135                  * Retry any blocked locks that have been notified by
  136                  * the VFS. Don't do this during grace period.
  137                  * (Theoretically, there shouldn't even be blocked locks
  138                  * during grace period).
  139                  */
  140                 if (!nlmsvc_grace_period)
  141                         timeout = nlmsvc_retry_blocked();
  142 
  143                 /*
  144                  * Find a socket with data available and call its
  145                  * recvfrom routine.
  146                  */
  147                 err = svc_recv(serv, rqstp, timeout);
  148                 if (err == -EAGAIN || err == -EINTR)
  149                         continue;
  150                 if (err < 0) {
  151                         printk(KERN_WARNING
  152                                "lockd: terminating on error %d\n",
  153                                -err);
  154                         break;
  155                 }
  156 
  157                 dprintk("lockd: request from %08x\n",
  158                         (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr));
  159 
  160                 /*
  161                  * Look up the NFS client handle. The handle is needed for
  162                  * all but the GRANTED callback RPCs.
  163                  */
  164                 rqstp->rq_client = NULL;
  165                 if (nlmsvc_ops) {
  166                         nlmsvc_ops->exp_readlock();
  167                         rqstp->rq_client =
  168                                 nlmsvc_ops->exp_getclient(&rqstp->rq_addr);
  169                 }
  170 
  171                 if (nlmsvc_grace_period &&
  172                     time_before(grace_period_expire, jiffies))
  173                         nlmsvc_grace_period = 0;
  174                 svc_process(serv, rqstp);
  175 
  176                 /* Unlock export hash tables */
  177                 if (nlmsvc_ops)
  178                         nlmsvc_ops->exp_unlock();
  179         }
  180 
  181         /*
  182          * Check whether there's a new lockd process before
  183          * shutting down the hosts and clearing the slot.
  184          */
  185         if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
  186                 if (nlmsvc_ops)
  187                         nlmsvc_ops->detach();
  188                 nlm_shutdown_hosts();
  189                 nlmsvc_pid = 0;
  190         } else
  191                 printk(KERN_DEBUG
  192                         "lockd: new process, skipping host shutdown\n");
  193         wake_up(&lockd_exit);
  194                 
  195         /* Exit the RPC thread */
  196         svc_exit_thread(rqstp);
  197 
  198         /* release rpciod */
  199         rpciod_down();
  200 
  201         /* Release module */
  202         MOD_DEC_USE_COUNT;
  203 }
  204 
  205 /*
  206  * Bring up the lockd process if it's not already up.
  207  */
  208 int
  209 lockd_up(void)
  210 {
  211         static int              warned = 0; 
  212         struct svc_serv *       serv;
  213         int                     error = 0;
  214 
  215         down(&nlmsvc_sema);
  216         /*
  217          * Unconditionally increment the user count ... this is
  218          * the number of clients who _want_ a lockd process.
  219          */
  220         nlmsvc_users++; 
  221         /*
  222          * Check whether we're already up and running.
  223          */
  224         if (nlmsvc_pid)
  225                 goto out;
  226 
  227         /*
  228          * Sanity check: if there's no pid,
  229          * we should be the first user ...
  230          */
  231         if (nlmsvc_users > 1)
  232                 printk(KERN_WARNING
  233                         "lockd_up: no pid, %d users??\n", nlmsvc_users);
  234 
  235         error = -ENOMEM;
  236         serv = svc_create(&nlmsvc_program, 0, NLMSVC_XDRSIZE);
  237         if (!serv) {
  238                 printk(KERN_WARNING "lockd_up: create service failed\n");
  239                 goto out;
  240         }
  241 
  242         if ((error = svc_makesock(serv, IPPROTO_UDP, nlm_udpport)) < 0 
  243 #ifdef CONFIG_NFSD_TCP
  244          || (error = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport)) < 0
  245 #endif
  246                 ) {
  247                 if (warned++ == 0) 
  248                         printk(KERN_WARNING
  249                                 "lockd_up: makesock failed, error=%d\n", error);
  250                 goto destroy_and_out;
  251         } 
  252         warned = 0;
  253 
  254         /*
  255          * Create the kernel thread and wait for it to start.
  256          */
  257         error = svc_create_thread(lockd, serv);
  258         if (error) {
  259                 printk(KERN_WARNING
  260                         "lockd_up: create thread failed, error=%d\n", error);
  261                 goto destroy_and_out;
  262         }
  263         down(&lockd_start);
  264 
  265         /*
  266          * Note: svc_serv structures have an initial use count of 1,
  267          * so we exit through here on both success and failure.
  268          */
  269 destroy_and_out:
  270         svc_destroy(serv);
  271 out:
  272         up(&nlmsvc_sema);
  273         return error;
  274 }
  275 
  276 /*
  277  * Decrement the user count and bring down lockd if we're the last.
  278  */
  279 void
  280 lockd_down(void)
  281 {
  282         static int warned = 0; 
  283 
  284         down(&nlmsvc_sema);
  285         if (nlmsvc_users) {
  286                 if (--nlmsvc_users)
  287                         goto out;
  288         } else
  289                 printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid);
  290 
  291         if (!nlmsvc_pid) {
  292                 if (warned++ == 0)
  293                         printk(KERN_WARNING "lockd_down: no lockd running.\n"); 
  294                 goto out;
  295         }
  296         warned = 0;
  297 
  298         kill_proc(nlmsvc_pid, SIGKILL, 1);
  299         /*
  300          * Wait for the lockd process to exit, but since we're holding
  301          * the lockd semaphore, we can't wait around forever ...
  302          */
  303         current->sigpending = 0;
  304         interruptible_sleep_on_timeout(&lockd_exit, HZ);
  305         if (nlmsvc_pid) {
  306                 printk(KERN_WARNING 
  307                         "lockd_down: lockd failed to exit, clearing pid\n");
  308                 nlmsvc_pid = 0;
  309         }
  310         spin_lock_irq(&current->sigmask_lock);
  311         recalc_sigpending(current);
  312         spin_unlock_irq(&current->sigmask_lock);
  313 out:
  314         up(&nlmsvc_sema);
  315 }
  316 
  317 #ifdef MODULE
  318 /* New module support in 2.1.18 */
  319 
  320 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
  321 MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION ".");
  322 MODULE_LICENSE("GPL");
  323 MODULE_PARM(nlm_grace_period, "10-240l");
  324 MODULE_PARM(nlm_timeout, "3-20l");
  325 MODULE_PARM(nlm_udpport, "0-65535l");
  326 MODULE_PARM(nlm_tcpport, "0-65535l");
  327 
  328 int
  329 init_module(void)
  330 {
  331         /* Init the static variables */
  332         init_MUTEX(&nlmsvc_sema);
  333         nlmsvc_users = 0;
  334         nlmsvc_pid = 0;
  335         return 0;
  336 }
  337 
  338 void
  339 cleanup_module(void)
  340 {
  341         /* FIXME: delete all NLM clients */
  342         nlm_shutdown_hosts();
  343 }
  344 #else
  345 /* not a module, so process bootargs
  346  * lockd.udpport and lockd.tcpport
  347  */
  348 
  349 static int __init udpport_set(char *str)
  350 {
  351         nlm_udpport = simple_strtoul(str, NULL, 0);
  352         return 1;
  353 }
  354 static int __init tcpport_set(char *str)
  355 {
  356         nlm_tcpport = simple_strtoul(str, NULL, 0);
  357         return 1;
  358 }
  359 __setup("lockd.udpport=", udpport_set);
  360 __setup("lockd.tcpport=", tcpport_set);
  361 
  362 #endif
  363 
  364 /*
  365  * Define NLM program and procedures
  366  */
  367 static struct svc_version       nlmsvc_version1 = {
  368         1, 17, nlmsvc_procedures, NULL
  369 };
  370 static struct svc_version       nlmsvc_version3 = {
  371         3, 24, nlmsvc_procedures, NULL
  372 };
  373 #ifdef CONFIG_LOCKD_V4
  374 static struct svc_version       nlmsvc_version4 = {
  375         4, 24, nlmsvc_procedures4, NULL
  376 };
  377 #endif
  378 static struct svc_version *     nlmsvc_version[] = {
  379         NULL,
  380         &nlmsvc_version1,
  381         NULL,
  382         &nlmsvc_version3,
  383 #ifdef CONFIG_LOCKD_V4
  384         &nlmsvc_version4,
  385 #endif
  386 };
  387 
  388 static struct svc_stat          nlmsvc_stats;
  389 
  390 #define NLM_NRVERS      (sizeof(nlmsvc_version)/sizeof(nlmsvc_version[0]))
  391 struct svc_program              nlmsvc_program = {
  392         NLM_PROGRAM,            /* program number */
  393         1, NLM_NRVERS-1,        /* version range */
  394         NLM_NRVERS,             /* number of entries in nlmsvc_version */
  395         nlmsvc_version,         /* version table */
  396         "lockd",                /* service name */
  397         &nlmsvc_stats,          /* stats table */
  398 };

Cache object: d076566050eae333238e2e4d8a1be08d


[ 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.