Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * linux/fs/lockd/svc.c
0004  *
0005  * This is the central lockd service.
0006  *
0007  * FIXME: Separate the lockd NFS server functionality from the lockd NFS
0008  *    client functionality. Oh why didn't Sun create two separate
0009  *    services in the first place?
0010  *
0011  * Authors: Olaf Kirch (okir@monad.swb.de)
0012  *
0013  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
0014  */
0015 
0016 #include <linux/module.h>
0017 #include <linux/init.h>
0018 #include <linux/sysctl.h>
0019 #include <linux/moduleparam.h>
0020 
0021 #include <linux/sched/signal.h>
0022 #include <linux/errno.h>
0023 #include <linux/in.h>
0024 #include <linux/uio.h>
0025 #include <linux/smp.h>
0026 #include <linux/mutex.h>
0027 #include <linux/kthread.h>
0028 #include <linux/freezer.h>
0029 #include <linux/inetdevice.h>
0030 
0031 #include <linux/sunrpc/types.h>
0032 #include <linux/sunrpc/stats.h>
0033 #include <linux/sunrpc/clnt.h>
0034 #include <linux/sunrpc/svc.h>
0035 #include <linux/sunrpc/svcsock.h>
0036 #include <linux/sunrpc/svc_xprt.h>
0037 #include <net/ip.h>
0038 #include <net/addrconf.h>
0039 #include <net/ipv6.h>
0040 #include <linux/lockd/lockd.h>
0041 #include <linux/nfs.h>
0042 
0043 #include "netns.h"
0044 #include "procfs.h"
0045 
0046 #define NLMDBG_FACILITY     NLMDBG_SVC
0047 #define LOCKD_BUFSIZE       (1024 + NLMSVC_XDRSIZE)
0048 #define ALLOWED_SIGS        (sigmask(SIGKILL))
0049 
0050 static struct svc_program   nlmsvc_program;
0051 
0052 const struct nlmsvc_binding *nlmsvc_ops;
0053 EXPORT_SYMBOL_GPL(nlmsvc_ops);
0054 
0055 static DEFINE_MUTEX(nlmsvc_mutex);
0056 static unsigned int     nlmsvc_users;
0057 static struct svc_serv      *nlmsvc_serv;
0058 unsigned long           nlmsvc_timeout;
0059 
0060 unsigned int lockd_net_id;
0061 
0062 /*
0063  * These can be set at insmod time (useful for NFS as root filesystem),
0064  * and also changed through the sysctl interface.  -- Jamie Lokier, Aug 2003
0065  */
0066 static unsigned long        nlm_grace_period;
0067 static unsigned long        nlm_timeout = LOCKD_DFLT_TIMEO;
0068 static int          nlm_udpport, nlm_tcpport;
0069 
0070 /* RLIM_NOFILE defaults to 1024. That seems like a reasonable default here. */
0071 static unsigned int     nlm_max_connections = 1024;
0072 
0073 /*
0074  * Constants needed for the sysctl interface.
0075  */
0076 static const unsigned long  nlm_grace_period_min = 0;
0077 static const unsigned long  nlm_grace_period_max = 240;
0078 static const unsigned long  nlm_timeout_min = 3;
0079 static const unsigned long  nlm_timeout_max = 20;
0080 static const int        nlm_port_min = 0, nlm_port_max = 65535;
0081 
0082 #ifdef CONFIG_SYSCTL
0083 static struct ctl_table_header * nlm_sysctl_table;
0084 #endif
0085 
0086 static unsigned long get_lockd_grace_period(void)
0087 {
0088     /* Note: nlm_timeout should always be nonzero */
0089     if (nlm_grace_period)
0090         return roundup(nlm_grace_period, nlm_timeout) * HZ;
0091     else
0092         return nlm_timeout * 5 * HZ;
0093 }
0094 
0095 static void grace_ender(struct work_struct *grace)
0096 {
0097     struct delayed_work *dwork = to_delayed_work(grace);
0098     struct lockd_net *ln = container_of(dwork, struct lockd_net,
0099                         grace_period_end);
0100 
0101     locks_end_grace(&ln->lockd_manager);
0102 }
0103 
0104 static void set_grace_period(struct net *net)
0105 {
0106     unsigned long grace_period = get_lockd_grace_period();
0107     struct lockd_net *ln = net_generic(net, lockd_net_id);
0108 
0109     locks_start_grace(net, &ln->lockd_manager);
0110     cancel_delayed_work_sync(&ln->grace_period_end);
0111     schedule_delayed_work(&ln->grace_period_end, grace_period);
0112 }
0113 
0114 static void restart_grace(void)
0115 {
0116     if (nlmsvc_ops) {
0117         struct net *net = &init_net;
0118         struct lockd_net *ln = net_generic(net, lockd_net_id);
0119 
0120         cancel_delayed_work_sync(&ln->grace_period_end);
0121         locks_end_grace(&ln->lockd_manager);
0122         nlmsvc_invalidate_all();
0123         set_grace_period(net);
0124     }
0125 }
0126 
0127 /*
0128  * This is the lockd kernel thread
0129  */
0130 static int
0131 lockd(void *vrqstp)
0132 {
0133     int     err = 0;
0134     struct svc_rqst *rqstp = vrqstp;
0135     struct net *net = &init_net;
0136     struct lockd_net *ln = net_generic(net, lockd_net_id);
0137 
0138     /* try_to_freeze() is called from svc_recv() */
0139     set_freezable();
0140 
0141     /* Allow SIGKILL to tell lockd to drop all of its locks */
0142     allow_signal(SIGKILL);
0143 
0144     dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
0145 
0146     /*
0147      * The main request loop. We don't terminate until the last
0148      * NFS mount or NFS daemon has gone away.
0149      */
0150     while (!kthread_should_stop()) {
0151         long timeout = MAX_SCHEDULE_TIMEOUT;
0152         RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
0153 
0154         /* update sv_maxconn if it has changed */
0155         rqstp->rq_server->sv_maxconn = nlm_max_connections;
0156 
0157         if (signalled()) {
0158             flush_signals(current);
0159             restart_grace();
0160             continue;
0161         }
0162 
0163         timeout = nlmsvc_retry_blocked();
0164 
0165         /*
0166          * Find a socket with data available and call its
0167          * recvfrom routine.
0168          */
0169         err = svc_recv(rqstp, timeout);
0170         if (err == -EAGAIN || err == -EINTR)
0171             continue;
0172         dprintk("lockd: request from %s\n",
0173                 svc_print_addr(rqstp, buf, sizeof(buf)));
0174 
0175         svc_process(rqstp);
0176     }
0177     flush_signals(current);
0178     if (nlmsvc_ops)
0179         nlmsvc_invalidate_all();
0180     nlm_shutdown_hosts();
0181     cancel_delayed_work_sync(&ln->grace_period_end);
0182     locks_end_grace(&ln->lockd_manager);
0183 
0184     dprintk("lockd_down: service stopped\n");
0185 
0186     svc_exit_thread(rqstp);
0187     return 0;
0188 }
0189 
0190 static int create_lockd_listener(struct svc_serv *serv, const char *name,
0191                  struct net *net, const int family,
0192                  const unsigned short port,
0193                  const struct cred *cred)
0194 {
0195     struct svc_xprt *xprt;
0196 
0197     xprt = svc_find_xprt(serv, name, net, family, 0);
0198     if (xprt == NULL)
0199         return svc_xprt_create(serv, name, net, family, port,
0200                        SVC_SOCK_DEFAULTS, cred);
0201     svc_xprt_put(xprt);
0202     return 0;
0203 }
0204 
0205 static int create_lockd_family(struct svc_serv *serv, struct net *net,
0206                    const int family, const struct cred *cred)
0207 {
0208     int err;
0209 
0210     err = create_lockd_listener(serv, "udp", net, family, nlm_udpport,
0211             cred);
0212     if (err < 0)
0213         return err;
0214 
0215     return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport,
0216             cred);
0217 }
0218 
0219 /*
0220  * Ensure there are active UDP and TCP listeners for lockd.
0221  *
0222  * Even if we have only TCP NFS mounts and/or TCP NFSDs, some
0223  * local services (such as rpc.statd) still require UDP, and
0224  * some NFS servers do not yet support NLM over TCP.
0225  *
0226  * Returns zero if all listeners are available; otherwise a
0227  * negative errno value is returned.
0228  */
0229 static int make_socks(struct svc_serv *serv, struct net *net,
0230         const struct cred *cred)
0231 {
0232     static int warned;
0233     int err;
0234 
0235     err = create_lockd_family(serv, net, PF_INET, cred);
0236     if (err < 0)
0237         goto out_err;
0238 
0239     err = create_lockd_family(serv, net, PF_INET6, cred);
0240     if (err < 0 && err != -EAFNOSUPPORT)
0241         goto out_err;
0242 
0243     warned = 0;
0244     return 0;
0245 
0246 out_err:
0247     if (warned++ == 0)
0248         printk(KERN_WARNING
0249             "lockd_up: makesock failed, error=%d\n", err);
0250     svc_xprt_destroy_all(serv, net);
0251     svc_rpcb_cleanup(serv, net);
0252     return err;
0253 }
0254 
0255 static int lockd_up_net(struct svc_serv *serv, struct net *net,
0256         const struct cred *cred)
0257 {
0258     struct lockd_net *ln = net_generic(net, lockd_net_id);
0259     int error;
0260 
0261     if (ln->nlmsvc_users++)
0262         return 0;
0263 
0264     error = svc_bind(serv, net);
0265     if (error)
0266         goto err_bind;
0267 
0268     error = make_socks(serv, net, cred);
0269     if (error < 0)
0270         goto err_bind;
0271     set_grace_period(net);
0272     dprintk("%s: per-net data created; net=%x\n", __func__, net->ns.inum);
0273     return 0;
0274 
0275 err_bind:
0276     ln->nlmsvc_users--;
0277     return error;
0278 }
0279 
0280 static void lockd_down_net(struct svc_serv *serv, struct net *net)
0281 {
0282     struct lockd_net *ln = net_generic(net, lockd_net_id);
0283 
0284     if (ln->nlmsvc_users) {
0285         if (--ln->nlmsvc_users == 0) {
0286             nlm_shutdown_hosts_net(net);
0287             cancel_delayed_work_sync(&ln->grace_period_end);
0288             locks_end_grace(&ln->lockd_manager);
0289             svc_xprt_destroy_all(serv, net);
0290             svc_rpcb_cleanup(serv, net);
0291         }
0292     } else {
0293         pr_err("%s: no users! net=%x\n",
0294             __func__, net->ns.inum);
0295         BUG();
0296     }
0297 }
0298 
0299 static int lockd_inetaddr_event(struct notifier_block *this,
0300     unsigned long event, void *ptr)
0301 {
0302     struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
0303     struct sockaddr_in sin;
0304 
0305     if (event != NETDEV_DOWN)
0306         goto out;
0307 
0308     if (nlmsvc_serv) {
0309         dprintk("lockd_inetaddr_event: removed %pI4\n",
0310             &ifa->ifa_local);
0311         sin.sin_family = AF_INET;
0312         sin.sin_addr.s_addr = ifa->ifa_local;
0313         svc_age_temp_xprts_now(nlmsvc_serv, (struct sockaddr *)&sin);
0314     }
0315 
0316 out:
0317     return NOTIFY_DONE;
0318 }
0319 
0320 static struct notifier_block lockd_inetaddr_notifier = {
0321     .notifier_call = lockd_inetaddr_event,
0322 };
0323 
0324 #if IS_ENABLED(CONFIG_IPV6)
0325 static int lockd_inet6addr_event(struct notifier_block *this,
0326     unsigned long event, void *ptr)
0327 {
0328     struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
0329     struct sockaddr_in6 sin6;
0330 
0331     if (event != NETDEV_DOWN)
0332         goto out;
0333 
0334     if (nlmsvc_serv) {
0335         dprintk("lockd_inet6addr_event: removed %pI6\n", &ifa->addr);
0336         sin6.sin6_family = AF_INET6;
0337         sin6.sin6_addr = ifa->addr;
0338         if (ipv6_addr_type(&sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
0339             sin6.sin6_scope_id = ifa->idev->dev->ifindex;
0340         svc_age_temp_xprts_now(nlmsvc_serv, (struct sockaddr *)&sin6);
0341     }
0342 
0343 out:
0344     return NOTIFY_DONE;
0345 }
0346 
0347 static struct notifier_block lockd_inet6addr_notifier = {
0348     .notifier_call = lockd_inet6addr_event,
0349 };
0350 #endif
0351 
0352 static int lockd_get(void)
0353 {
0354     struct svc_serv *serv;
0355     int error;
0356 
0357     if (nlmsvc_serv) {
0358         svc_get(nlmsvc_serv);
0359         nlmsvc_users++;
0360         return 0;
0361     }
0362 
0363     /*
0364      * Sanity check: if there's no pid,
0365      * we should be the first user ...
0366      */
0367     if (nlmsvc_users)
0368         printk(KERN_WARNING
0369             "lockd_up: no pid, %d users??\n", nlmsvc_users);
0370 
0371     if (!nlm_timeout)
0372         nlm_timeout = LOCKD_DFLT_TIMEO;
0373     nlmsvc_timeout = nlm_timeout * HZ;
0374 
0375     serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, lockd);
0376     if (!serv) {
0377         printk(KERN_WARNING "lockd_up: create service failed\n");
0378         return -ENOMEM;
0379     }
0380 
0381     serv->sv_maxconn = nlm_max_connections;
0382     error = svc_set_num_threads(serv, NULL, 1);
0383     /* The thread now holds the only reference */
0384     svc_put(serv);
0385     if (error < 0)
0386         return error;
0387 
0388     nlmsvc_serv = serv;
0389     register_inetaddr_notifier(&lockd_inetaddr_notifier);
0390 #if IS_ENABLED(CONFIG_IPV6)
0391     register_inet6addr_notifier(&lockd_inet6addr_notifier);
0392 #endif
0393     dprintk("lockd_up: service created\n");
0394     nlmsvc_users++;
0395     return 0;
0396 }
0397 
0398 static void lockd_put(void)
0399 {
0400     if (WARN(nlmsvc_users <= 0, "lockd_down: no users!\n"))
0401         return;
0402     if (--nlmsvc_users)
0403         return;
0404 
0405     unregister_inetaddr_notifier(&lockd_inetaddr_notifier);
0406 #if IS_ENABLED(CONFIG_IPV6)
0407     unregister_inet6addr_notifier(&lockd_inet6addr_notifier);
0408 #endif
0409 
0410     svc_set_num_threads(nlmsvc_serv, NULL, 0);
0411     nlmsvc_serv = NULL;
0412     dprintk("lockd_down: service destroyed\n");
0413 }
0414 
0415 /*
0416  * Bring up the lockd process if it's not already up.
0417  */
0418 int lockd_up(struct net *net, const struct cred *cred)
0419 {
0420     int error;
0421 
0422     mutex_lock(&nlmsvc_mutex);
0423 
0424     error = lockd_get();
0425     if (error)
0426         goto err;
0427 
0428     error = lockd_up_net(nlmsvc_serv, net, cred);
0429     if (error < 0) {
0430         lockd_put();
0431         goto err;
0432     }
0433 
0434 err:
0435     mutex_unlock(&nlmsvc_mutex);
0436     return error;
0437 }
0438 EXPORT_SYMBOL_GPL(lockd_up);
0439 
0440 /*
0441  * Decrement the user count and bring down lockd if we're the last.
0442  */
0443 void
0444 lockd_down(struct net *net)
0445 {
0446     mutex_lock(&nlmsvc_mutex);
0447     lockd_down_net(nlmsvc_serv, net);
0448     lockd_put();
0449     mutex_unlock(&nlmsvc_mutex);
0450 }
0451 EXPORT_SYMBOL_GPL(lockd_down);
0452 
0453 #ifdef CONFIG_SYSCTL
0454 
0455 /*
0456  * Sysctl parameters (same as module parameters, different interface).
0457  */
0458 
0459 static struct ctl_table nlm_sysctls[] = {
0460     {
0461         .procname   = "nlm_grace_period",
0462         .data       = &nlm_grace_period,
0463         .maxlen     = sizeof(unsigned long),
0464         .mode       = 0644,
0465         .proc_handler   = proc_doulongvec_minmax,
0466         .extra1     = (unsigned long *) &nlm_grace_period_min,
0467         .extra2     = (unsigned long *) &nlm_grace_period_max,
0468     },
0469     {
0470         .procname   = "nlm_timeout",
0471         .data       = &nlm_timeout,
0472         .maxlen     = sizeof(unsigned long),
0473         .mode       = 0644,
0474         .proc_handler   = proc_doulongvec_minmax,
0475         .extra1     = (unsigned long *) &nlm_timeout_min,
0476         .extra2     = (unsigned long *) &nlm_timeout_max,
0477     },
0478     {
0479         .procname   = "nlm_udpport",
0480         .data       = &nlm_udpport,
0481         .maxlen     = sizeof(int),
0482         .mode       = 0644,
0483         .proc_handler   = proc_dointvec_minmax,
0484         .extra1     = (int *) &nlm_port_min,
0485         .extra2     = (int *) &nlm_port_max,
0486     },
0487     {
0488         .procname   = "nlm_tcpport",
0489         .data       = &nlm_tcpport,
0490         .maxlen     = sizeof(int),
0491         .mode       = 0644,
0492         .proc_handler   = proc_dointvec_minmax,
0493         .extra1     = (int *) &nlm_port_min,
0494         .extra2     = (int *) &nlm_port_max,
0495     },
0496     {
0497         .procname   = "nsm_use_hostnames",
0498         .data       = &nsm_use_hostnames,
0499         .maxlen     = sizeof(int),
0500         .mode       = 0644,
0501         .proc_handler   = proc_dobool,
0502     },
0503     {
0504         .procname   = "nsm_local_state",
0505         .data       = &nsm_local_state,
0506         .maxlen     = sizeof(int),
0507         .mode       = 0644,
0508         .proc_handler   = proc_dointvec,
0509     },
0510     { }
0511 };
0512 
0513 static struct ctl_table nlm_sysctl_dir[] = {
0514     {
0515         .procname   = "nfs",
0516         .mode       = 0555,
0517         .child      = nlm_sysctls,
0518     },
0519     { }
0520 };
0521 
0522 static struct ctl_table nlm_sysctl_root[] = {
0523     {
0524         .procname   = "fs",
0525         .mode       = 0555,
0526         .child      = nlm_sysctl_dir,
0527     },
0528     { }
0529 };
0530 
0531 #endif  /* CONFIG_SYSCTL */
0532 
0533 /*
0534  * Module (and sysfs) parameters.
0535  */
0536 
0537 #define param_set_min_max(name, type, which_strtol, min, max)       \
0538 static int param_set_##name(const char *val, const struct kernel_param *kp) \
0539 {                                   \
0540     char *endp;                         \
0541     __typeof__(type) num = which_strtol(val, &endp, 0);     \
0542     if (endp == val || *endp || num < (min) || num > (max))     \
0543         return -EINVAL;                     \
0544     *((type *) kp->arg) = num;                  \
0545     return 0;                           \
0546 }
0547 
0548 static inline int is_callback(u32 proc)
0549 {
0550     return proc == NLMPROC_GRANTED
0551         || proc == NLMPROC_GRANTED_MSG
0552         || proc == NLMPROC_TEST_RES
0553         || proc == NLMPROC_LOCK_RES
0554         || proc == NLMPROC_CANCEL_RES
0555         || proc == NLMPROC_UNLOCK_RES
0556         || proc == NLMPROC_NSM_NOTIFY;
0557 }
0558 
0559 
0560 static int lockd_authenticate(struct svc_rqst *rqstp)
0561 {
0562     rqstp->rq_client = NULL;
0563     switch (rqstp->rq_authop->flavour) {
0564         case RPC_AUTH_NULL:
0565         case RPC_AUTH_UNIX:
0566             rqstp->rq_auth_stat = rpc_auth_ok;
0567             if (rqstp->rq_proc == 0)
0568                 return SVC_OK;
0569             if (is_callback(rqstp->rq_proc)) {
0570                 /* Leave it to individual procedures to
0571                  * call nlmsvc_lookup_host(rqstp)
0572                  */
0573                 return SVC_OK;
0574             }
0575             return svc_set_client(rqstp);
0576     }
0577     rqstp->rq_auth_stat = rpc_autherr_badcred;
0578     return SVC_DENIED;
0579 }
0580 
0581 
0582 param_set_min_max(port, int, simple_strtol, 0, 65535)
0583 param_set_min_max(grace_period, unsigned long, simple_strtoul,
0584           nlm_grace_period_min, nlm_grace_period_max)
0585 param_set_min_max(timeout, unsigned long, simple_strtoul,
0586           nlm_timeout_min, nlm_timeout_max)
0587 
0588 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
0589 MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION ".");
0590 MODULE_LICENSE("GPL");
0591 
0592 module_param_call(nlm_grace_period, param_set_grace_period, param_get_ulong,
0593           &nlm_grace_period, 0644);
0594 module_param_call(nlm_timeout, param_set_timeout, param_get_ulong,
0595           &nlm_timeout, 0644);
0596 module_param_call(nlm_udpport, param_set_port, param_get_int,
0597           &nlm_udpport, 0644);
0598 module_param_call(nlm_tcpport, param_set_port, param_get_int,
0599           &nlm_tcpport, 0644);
0600 module_param(nsm_use_hostnames, bool, 0644);
0601 module_param(nlm_max_connections, uint, 0644);
0602 
0603 static int lockd_init_net(struct net *net)
0604 {
0605     struct lockd_net *ln = net_generic(net, lockd_net_id);
0606 
0607     INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender);
0608     INIT_LIST_HEAD(&ln->lockd_manager.list);
0609     ln->lockd_manager.block_opens = false;
0610     INIT_LIST_HEAD(&ln->nsm_handles);
0611     return 0;
0612 }
0613 
0614 static void lockd_exit_net(struct net *net)
0615 {
0616     struct lockd_net *ln = net_generic(net, lockd_net_id);
0617 
0618     WARN_ONCE(!list_empty(&ln->lockd_manager.list),
0619           "net %x %s: lockd_manager.list is not empty\n",
0620           net->ns.inum, __func__);
0621     WARN_ONCE(!list_empty(&ln->nsm_handles),
0622           "net %x %s: nsm_handles list is not empty\n",
0623           net->ns.inum, __func__);
0624     WARN_ONCE(delayed_work_pending(&ln->grace_period_end),
0625           "net %x %s: grace_period_end was not cancelled\n",
0626           net->ns.inum, __func__);
0627 }
0628 
0629 static struct pernet_operations lockd_net_ops = {
0630     .init = lockd_init_net,
0631     .exit = lockd_exit_net,
0632     .id = &lockd_net_id,
0633     .size = sizeof(struct lockd_net),
0634 };
0635 
0636 
0637 /*
0638  * Initialising and terminating the module.
0639  */
0640 
0641 static int __init init_nlm(void)
0642 {
0643     int err;
0644 
0645 #ifdef CONFIG_SYSCTL
0646     err = -ENOMEM;
0647     nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root);
0648     if (nlm_sysctl_table == NULL)
0649         goto err_sysctl;
0650 #endif
0651     err = register_pernet_subsys(&lockd_net_ops);
0652     if (err)
0653         goto err_pernet;
0654 
0655     err = lockd_create_procfs();
0656     if (err)
0657         goto err_procfs;
0658 
0659     return 0;
0660 
0661 err_procfs:
0662     unregister_pernet_subsys(&lockd_net_ops);
0663 err_pernet:
0664 #ifdef CONFIG_SYSCTL
0665     unregister_sysctl_table(nlm_sysctl_table);
0666 err_sysctl:
0667 #endif
0668     return err;
0669 }
0670 
0671 static void __exit exit_nlm(void)
0672 {
0673     /* FIXME: delete all NLM clients */
0674     nlm_shutdown_hosts();
0675     lockd_remove_procfs();
0676     unregister_pernet_subsys(&lockd_net_ops);
0677 #ifdef CONFIG_SYSCTL
0678     unregister_sysctl_table(nlm_sysctl_table);
0679 #endif
0680 }
0681 
0682 module_init(init_nlm);
0683 module_exit(exit_nlm);
0684 
0685 /**
0686  * nlmsvc_dispatch - Process an NLM Request
0687  * @rqstp: incoming request
0688  * @statp: pointer to location of accept_stat field in RPC Reply buffer
0689  *
0690  * Return values:
0691  *  %0: Processing complete; do not send a Reply
0692  *  %1: Processing complete; send Reply in rqstp->rq_res
0693  */
0694 static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp)
0695 {
0696     const struct svc_procedure *procp = rqstp->rq_procinfo;
0697 
0698     svcxdr_init_decode(rqstp);
0699     if (!procp->pc_decode(rqstp, &rqstp->rq_arg_stream))
0700         goto out_decode_err;
0701 
0702     *statp = procp->pc_func(rqstp);
0703     if (*statp == rpc_drop_reply)
0704         return 0;
0705     if (*statp != rpc_success)
0706         return 1;
0707 
0708     svcxdr_init_encode(rqstp);
0709     if (!procp->pc_encode(rqstp, &rqstp->rq_res_stream))
0710         goto out_encode_err;
0711 
0712     return 1;
0713 
0714 out_decode_err:
0715     *statp = rpc_garbage_args;
0716     return 1;
0717 
0718 out_encode_err:
0719     *statp = rpc_system_err;
0720     return 1;
0721 }
0722 
0723 /*
0724  * Define NLM program and procedures
0725  */
0726 static unsigned int nlmsvc_version1_count[17];
0727 static const struct svc_version nlmsvc_version1 = {
0728     .vs_vers    = 1,
0729     .vs_nproc   = 17,
0730     .vs_proc    = nlmsvc_procedures,
0731     .vs_count   = nlmsvc_version1_count,
0732     .vs_dispatch    = nlmsvc_dispatch,
0733     .vs_xdrsize = NLMSVC_XDRSIZE,
0734 };
0735 static unsigned int nlmsvc_version3_count[24];
0736 static const struct svc_version nlmsvc_version3 = {
0737     .vs_vers    = 3,
0738     .vs_nproc   = 24,
0739     .vs_proc    = nlmsvc_procedures,
0740     .vs_count   = nlmsvc_version3_count,
0741     .vs_dispatch    = nlmsvc_dispatch,
0742     .vs_xdrsize = NLMSVC_XDRSIZE,
0743 };
0744 #ifdef CONFIG_LOCKD_V4
0745 static unsigned int nlmsvc_version4_count[24];
0746 static const struct svc_version nlmsvc_version4 = {
0747     .vs_vers    = 4,
0748     .vs_nproc   = 24,
0749     .vs_proc    = nlmsvc_procedures4,
0750     .vs_count   = nlmsvc_version4_count,
0751     .vs_dispatch    = nlmsvc_dispatch,
0752     .vs_xdrsize = NLMSVC_XDRSIZE,
0753 };
0754 #endif
0755 static const struct svc_version *nlmsvc_version[] = {
0756     [1] = &nlmsvc_version1,
0757     [3] = &nlmsvc_version3,
0758 #ifdef CONFIG_LOCKD_V4
0759     [4] = &nlmsvc_version4,
0760 #endif
0761 };
0762 
0763 static struct svc_stat      nlmsvc_stats;
0764 
0765 #define NLM_NRVERS  ARRAY_SIZE(nlmsvc_version)
0766 static struct svc_program   nlmsvc_program = {
0767     .pg_prog        = NLM_PROGRAM,      /* program number */
0768     .pg_nvers       = NLM_NRVERS,       /* number of entries in nlmsvc_version */
0769     .pg_vers        = nlmsvc_version,   /* version table */
0770     .pg_name        = "lockd",      /* service name */
0771     .pg_class       = "nfsd",       /* share authentication with nfsd */
0772     .pg_stats       = &nlmsvc_stats,    /* stats table */
0773     .pg_authenticate    = &lockd_authenticate,  /* export authentication */
0774     .pg_init_request    = svc_generic_init_request,
0775     .pg_rpcbind_set     = svc_generic_rpcbind_set,
0776 };