1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * linux/fs/lockd/svc.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This is the central lockd service.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * FIXME: Separate the lockd NFS server functionality from the lockd NFS
8*4882a593Smuzhiyun * client functionality. Oh why didn't Sun create two separate
9*4882a593Smuzhiyun * services in the first place?
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Authors: Olaf Kirch (okir@monad.swb.de)
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
14*4882a593Smuzhiyun */
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include <linux/init.h>
18*4882a593Smuzhiyun #include <linux/sysctl.h>
19*4882a593Smuzhiyun #include <linux/moduleparam.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <linux/sched/signal.h>
22*4882a593Smuzhiyun #include <linux/errno.h>
23*4882a593Smuzhiyun #include <linux/in.h>
24*4882a593Smuzhiyun #include <linux/uio.h>
25*4882a593Smuzhiyun #include <linux/smp.h>
26*4882a593Smuzhiyun #include <linux/mutex.h>
27*4882a593Smuzhiyun #include <linux/kthread.h>
28*4882a593Smuzhiyun #include <linux/freezer.h>
29*4882a593Smuzhiyun #include <linux/inetdevice.h>
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include <linux/sunrpc/types.h>
32*4882a593Smuzhiyun #include <linux/sunrpc/stats.h>
33*4882a593Smuzhiyun #include <linux/sunrpc/clnt.h>
34*4882a593Smuzhiyun #include <linux/sunrpc/svc.h>
35*4882a593Smuzhiyun #include <linux/sunrpc/svcsock.h>
36*4882a593Smuzhiyun #include <linux/sunrpc/svc_xprt.h>
37*4882a593Smuzhiyun #include <net/ip.h>
38*4882a593Smuzhiyun #include <net/addrconf.h>
39*4882a593Smuzhiyun #include <net/ipv6.h>
40*4882a593Smuzhiyun #include <linux/lockd/lockd.h>
41*4882a593Smuzhiyun #include <linux/nfs.h>
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #include "netns.h"
44*4882a593Smuzhiyun #include "procfs.h"
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun #define NLMDBG_FACILITY NLMDBG_SVC
47*4882a593Smuzhiyun #define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE)
48*4882a593Smuzhiyun #define ALLOWED_SIGS (sigmask(SIGKILL))
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun static struct svc_program nlmsvc_program;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun const struct nlmsvc_binding *nlmsvc_ops;
53*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(nlmsvc_ops);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun static DEFINE_MUTEX(nlmsvc_mutex);
56*4882a593Smuzhiyun static unsigned int nlmsvc_users;
57*4882a593Smuzhiyun static struct task_struct *nlmsvc_task;
58*4882a593Smuzhiyun static struct svc_rqst *nlmsvc_rqst;
59*4882a593Smuzhiyun unsigned long nlmsvc_timeout;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun static atomic_t nlm_ntf_refcnt = ATOMIC_INIT(0);
62*4882a593Smuzhiyun static DECLARE_WAIT_QUEUE_HEAD(nlm_ntf_wq);
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun unsigned int lockd_net_id;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun /*
67*4882a593Smuzhiyun * These can be set at insmod time (useful for NFS as root filesystem),
68*4882a593Smuzhiyun * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003
69*4882a593Smuzhiyun */
70*4882a593Smuzhiyun static unsigned long nlm_grace_period;
71*4882a593Smuzhiyun static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO;
72*4882a593Smuzhiyun static int nlm_udpport, nlm_tcpport;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /* RLIM_NOFILE defaults to 1024. That seems like a reasonable default here. */
75*4882a593Smuzhiyun static unsigned int nlm_max_connections = 1024;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /*
78*4882a593Smuzhiyun * Constants needed for the sysctl interface.
79*4882a593Smuzhiyun */
80*4882a593Smuzhiyun static const unsigned long nlm_grace_period_min = 0;
81*4882a593Smuzhiyun static const unsigned long nlm_grace_period_max = 240;
82*4882a593Smuzhiyun static const unsigned long nlm_timeout_min = 3;
83*4882a593Smuzhiyun static const unsigned long nlm_timeout_max = 20;
84*4882a593Smuzhiyun static const int nlm_port_min = 0, nlm_port_max = 65535;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun #ifdef CONFIG_SYSCTL
87*4882a593Smuzhiyun static struct ctl_table_header * nlm_sysctl_table;
88*4882a593Smuzhiyun #endif
89*4882a593Smuzhiyun
get_lockd_grace_period(void)90*4882a593Smuzhiyun static unsigned long get_lockd_grace_period(void)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun /* Note: nlm_timeout should always be nonzero */
93*4882a593Smuzhiyun if (nlm_grace_period)
94*4882a593Smuzhiyun return roundup(nlm_grace_period, nlm_timeout) * HZ;
95*4882a593Smuzhiyun else
96*4882a593Smuzhiyun return nlm_timeout * 5 * HZ;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
grace_ender(struct work_struct * grace)99*4882a593Smuzhiyun static void grace_ender(struct work_struct *grace)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun struct delayed_work *dwork = to_delayed_work(grace);
102*4882a593Smuzhiyun struct lockd_net *ln = container_of(dwork, struct lockd_net,
103*4882a593Smuzhiyun grace_period_end);
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun locks_end_grace(&ln->lockd_manager);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
set_grace_period(struct net * net)108*4882a593Smuzhiyun static void set_grace_period(struct net *net)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun unsigned long grace_period = get_lockd_grace_period();
111*4882a593Smuzhiyun struct lockd_net *ln = net_generic(net, lockd_net_id);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun locks_start_grace(net, &ln->lockd_manager);
114*4882a593Smuzhiyun cancel_delayed_work_sync(&ln->grace_period_end);
115*4882a593Smuzhiyun schedule_delayed_work(&ln->grace_period_end, grace_period);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun
restart_grace(void)118*4882a593Smuzhiyun static void restart_grace(void)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun if (nlmsvc_ops) {
121*4882a593Smuzhiyun struct net *net = &init_net;
122*4882a593Smuzhiyun struct lockd_net *ln = net_generic(net, lockd_net_id);
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun cancel_delayed_work_sync(&ln->grace_period_end);
125*4882a593Smuzhiyun locks_end_grace(&ln->lockd_manager);
126*4882a593Smuzhiyun nlmsvc_invalidate_all();
127*4882a593Smuzhiyun set_grace_period(net);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun /*
132*4882a593Smuzhiyun * This is the lockd kernel thread
133*4882a593Smuzhiyun */
134*4882a593Smuzhiyun static int
lockd(void * vrqstp)135*4882a593Smuzhiyun lockd(void *vrqstp)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun int err = 0;
138*4882a593Smuzhiyun struct svc_rqst *rqstp = vrqstp;
139*4882a593Smuzhiyun struct net *net = &init_net;
140*4882a593Smuzhiyun struct lockd_net *ln = net_generic(net, lockd_net_id);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun /* try_to_freeze() is called from svc_recv() */
143*4882a593Smuzhiyun set_freezable();
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun /* Allow SIGKILL to tell lockd to drop all of its locks */
146*4882a593Smuzhiyun allow_signal(SIGKILL);
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /*
151*4882a593Smuzhiyun * The main request loop. We don't terminate until the last
152*4882a593Smuzhiyun * NFS mount or NFS daemon has gone away.
153*4882a593Smuzhiyun */
154*4882a593Smuzhiyun while (!kthread_should_stop()) {
155*4882a593Smuzhiyun long timeout = MAX_SCHEDULE_TIMEOUT;
156*4882a593Smuzhiyun RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /* update sv_maxconn if it has changed */
159*4882a593Smuzhiyun rqstp->rq_server->sv_maxconn = nlm_max_connections;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun if (signalled()) {
162*4882a593Smuzhiyun flush_signals(current);
163*4882a593Smuzhiyun restart_grace();
164*4882a593Smuzhiyun continue;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun timeout = nlmsvc_retry_blocked();
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun /*
170*4882a593Smuzhiyun * Find a socket with data available and call its
171*4882a593Smuzhiyun * recvfrom routine.
172*4882a593Smuzhiyun */
173*4882a593Smuzhiyun err = svc_recv(rqstp, timeout);
174*4882a593Smuzhiyun if (err == -EAGAIN || err == -EINTR)
175*4882a593Smuzhiyun continue;
176*4882a593Smuzhiyun dprintk("lockd: request from %s\n",
177*4882a593Smuzhiyun svc_print_addr(rqstp, buf, sizeof(buf)));
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun svc_process(rqstp);
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun flush_signals(current);
182*4882a593Smuzhiyun if (nlmsvc_ops)
183*4882a593Smuzhiyun nlmsvc_invalidate_all();
184*4882a593Smuzhiyun nlm_shutdown_hosts();
185*4882a593Smuzhiyun cancel_delayed_work_sync(&ln->grace_period_end);
186*4882a593Smuzhiyun locks_end_grace(&ln->lockd_manager);
187*4882a593Smuzhiyun return 0;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
create_lockd_listener(struct svc_serv * serv,const char * name,struct net * net,const int family,const unsigned short port,const struct cred * cred)190*4882a593Smuzhiyun static int create_lockd_listener(struct svc_serv *serv, const char *name,
191*4882a593Smuzhiyun struct net *net, const int family,
192*4882a593Smuzhiyun const unsigned short port,
193*4882a593Smuzhiyun const struct cred *cred)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun struct svc_xprt *xprt;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun xprt = svc_find_xprt(serv, name, net, family, 0);
198*4882a593Smuzhiyun if (xprt == NULL)
199*4882a593Smuzhiyun return svc_create_xprt(serv, name, net, family, port,
200*4882a593Smuzhiyun SVC_SOCK_DEFAULTS, cred);
201*4882a593Smuzhiyun svc_xprt_put(xprt);
202*4882a593Smuzhiyun return 0;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
create_lockd_family(struct svc_serv * serv,struct net * net,const int family,const struct cred * cred)205*4882a593Smuzhiyun static int create_lockd_family(struct svc_serv *serv, struct net *net,
206*4882a593Smuzhiyun const int family, const struct cred *cred)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun int err;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun err = create_lockd_listener(serv, "udp", net, family, nlm_udpport,
211*4882a593Smuzhiyun cred);
212*4882a593Smuzhiyun if (err < 0)
213*4882a593Smuzhiyun return err;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport,
216*4882a593Smuzhiyun cred);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /*
220*4882a593Smuzhiyun * Ensure there are active UDP and TCP listeners for lockd.
221*4882a593Smuzhiyun *
222*4882a593Smuzhiyun * Even if we have only TCP NFS mounts and/or TCP NFSDs, some
223*4882a593Smuzhiyun * local services (such as rpc.statd) still require UDP, and
224*4882a593Smuzhiyun * some NFS servers do not yet support NLM over TCP.
225*4882a593Smuzhiyun *
226*4882a593Smuzhiyun * Returns zero if all listeners are available; otherwise a
227*4882a593Smuzhiyun * negative errno value is returned.
228*4882a593Smuzhiyun */
make_socks(struct svc_serv * serv,struct net * net,const struct cred * cred)229*4882a593Smuzhiyun static int make_socks(struct svc_serv *serv, struct net *net,
230*4882a593Smuzhiyun const struct cred *cred)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun static int warned;
233*4882a593Smuzhiyun int err;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun err = create_lockd_family(serv, net, PF_INET, cred);
236*4882a593Smuzhiyun if (err < 0)
237*4882a593Smuzhiyun goto out_err;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun err = create_lockd_family(serv, net, PF_INET6, cred);
240*4882a593Smuzhiyun if (err < 0 && err != -EAFNOSUPPORT)
241*4882a593Smuzhiyun goto out_err;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun warned = 0;
244*4882a593Smuzhiyun return 0;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun out_err:
247*4882a593Smuzhiyun if (warned++ == 0)
248*4882a593Smuzhiyun printk(KERN_WARNING
249*4882a593Smuzhiyun "lockd_up: makesock failed, error=%d\n", err);
250*4882a593Smuzhiyun svc_shutdown_net(serv, net);
251*4882a593Smuzhiyun return err;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
lockd_up_net(struct svc_serv * serv,struct net * net,const struct cred * cred)254*4882a593Smuzhiyun static int lockd_up_net(struct svc_serv *serv, struct net *net,
255*4882a593Smuzhiyun const struct cred *cred)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun struct lockd_net *ln = net_generic(net, lockd_net_id);
258*4882a593Smuzhiyun int error;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (ln->nlmsvc_users++)
261*4882a593Smuzhiyun return 0;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun error = svc_bind(serv, net);
264*4882a593Smuzhiyun if (error)
265*4882a593Smuzhiyun goto err_bind;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun error = make_socks(serv, net, cred);
268*4882a593Smuzhiyun if (error < 0)
269*4882a593Smuzhiyun goto err_bind;
270*4882a593Smuzhiyun set_grace_period(net);
271*4882a593Smuzhiyun dprintk("%s: per-net data created; net=%x\n", __func__, net->ns.inum);
272*4882a593Smuzhiyun return 0;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun err_bind:
275*4882a593Smuzhiyun ln->nlmsvc_users--;
276*4882a593Smuzhiyun return error;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
lockd_down_net(struct svc_serv * serv,struct net * net)279*4882a593Smuzhiyun static void lockd_down_net(struct svc_serv *serv, struct net *net)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun struct lockd_net *ln = net_generic(net, lockd_net_id);
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun if (ln->nlmsvc_users) {
284*4882a593Smuzhiyun if (--ln->nlmsvc_users == 0) {
285*4882a593Smuzhiyun nlm_shutdown_hosts_net(net);
286*4882a593Smuzhiyun cancel_delayed_work_sync(&ln->grace_period_end);
287*4882a593Smuzhiyun locks_end_grace(&ln->lockd_manager);
288*4882a593Smuzhiyun svc_shutdown_net(serv, net);
289*4882a593Smuzhiyun dprintk("%s: per-net data destroyed; net=%x\n",
290*4882a593Smuzhiyun __func__, net->ns.inum);
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun } else {
293*4882a593Smuzhiyun pr_err("%s: no users! task=%p, net=%x\n",
294*4882a593Smuzhiyun __func__, nlmsvc_task, net->ns.inum);
295*4882a593Smuzhiyun BUG();
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
lockd_inetaddr_event(struct notifier_block * this,unsigned long event,void * ptr)299*4882a593Smuzhiyun static int lockd_inetaddr_event(struct notifier_block *this,
300*4882a593Smuzhiyun unsigned long event, void *ptr)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
303*4882a593Smuzhiyun struct sockaddr_in sin;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun if ((event != NETDEV_DOWN) ||
306*4882a593Smuzhiyun !atomic_inc_not_zero(&nlm_ntf_refcnt))
307*4882a593Smuzhiyun goto out;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun if (nlmsvc_rqst) {
310*4882a593Smuzhiyun dprintk("lockd_inetaddr_event: removed %pI4\n",
311*4882a593Smuzhiyun &ifa->ifa_local);
312*4882a593Smuzhiyun sin.sin_family = AF_INET;
313*4882a593Smuzhiyun sin.sin_addr.s_addr = ifa->ifa_local;
314*4882a593Smuzhiyun svc_age_temp_xprts_now(nlmsvc_rqst->rq_server,
315*4882a593Smuzhiyun (struct sockaddr *)&sin);
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun atomic_dec(&nlm_ntf_refcnt);
318*4882a593Smuzhiyun wake_up(&nlm_ntf_wq);
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun out:
321*4882a593Smuzhiyun return NOTIFY_DONE;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun static struct notifier_block lockd_inetaddr_notifier = {
325*4882a593Smuzhiyun .notifier_call = lockd_inetaddr_event,
326*4882a593Smuzhiyun };
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
lockd_inet6addr_event(struct notifier_block * this,unsigned long event,void * ptr)329*4882a593Smuzhiyun static int lockd_inet6addr_event(struct notifier_block *this,
330*4882a593Smuzhiyun unsigned long event, void *ptr)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
333*4882a593Smuzhiyun struct sockaddr_in6 sin6;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun if ((event != NETDEV_DOWN) ||
336*4882a593Smuzhiyun !atomic_inc_not_zero(&nlm_ntf_refcnt))
337*4882a593Smuzhiyun goto out;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun if (nlmsvc_rqst) {
340*4882a593Smuzhiyun dprintk("lockd_inet6addr_event: removed %pI6\n", &ifa->addr);
341*4882a593Smuzhiyun sin6.sin6_family = AF_INET6;
342*4882a593Smuzhiyun sin6.sin6_addr = ifa->addr;
343*4882a593Smuzhiyun if (ipv6_addr_type(&sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
344*4882a593Smuzhiyun sin6.sin6_scope_id = ifa->idev->dev->ifindex;
345*4882a593Smuzhiyun svc_age_temp_xprts_now(nlmsvc_rqst->rq_server,
346*4882a593Smuzhiyun (struct sockaddr *)&sin6);
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun atomic_dec(&nlm_ntf_refcnt);
349*4882a593Smuzhiyun wake_up(&nlm_ntf_wq);
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun out:
352*4882a593Smuzhiyun return NOTIFY_DONE;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun static struct notifier_block lockd_inet6addr_notifier = {
356*4882a593Smuzhiyun .notifier_call = lockd_inet6addr_event,
357*4882a593Smuzhiyun };
358*4882a593Smuzhiyun #endif
359*4882a593Smuzhiyun
lockd_unregister_notifiers(void)360*4882a593Smuzhiyun static void lockd_unregister_notifiers(void)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun unregister_inetaddr_notifier(&lockd_inetaddr_notifier);
363*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
364*4882a593Smuzhiyun unregister_inet6addr_notifier(&lockd_inet6addr_notifier);
365*4882a593Smuzhiyun #endif
366*4882a593Smuzhiyun wait_event(nlm_ntf_wq, atomic_read(&nlm_ntf_refcnt) == 0);
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
lockd_svc_exit_thread(void)369*4882a593Smuzhiyun static void lockd_svc_exit_thread(void)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun atomic_dec(&nlm_ntf_refcnt);
372*4882a593Smuzhiyun lockd_unregister_notifiers();
373*4882a593Smuzhiyun svc_exit_thread(nlmsvc_rqst);
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
lockd_start_svc(struct svc_serv * serv)376*4882a593Smuzhiyun static int lockd_start_svc(struct svc_serv *serv)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun int error;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun if (nlmsvc_rqst)
381*4882a593Smuzhiyun return 0;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun /*
384*4882a593Smuzhiyun * Create the kernel thread and wait for it to start.
385*4882a593Smuzhiyun */
386*4882a593Smuzhiyun nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE);
387*4882a593Smuzhiyun if (IS_ERR(nlmsvc_rqst)) {
388*4882a593Smuzhiyun error = PTR_ERR(nlmsvc_rqst);
389*4882a593Smuzhiyun printk(KERN_WARNING
390*4882a593Smuzhiyun "lockd_up: svc_rqst allocation failed, error=%d\n",
391*4882a593Smuzhiyun error);
392*4882a593Smuzhiyun lockd_unregister_notifiers();
393*4882a593Smuzhiyun goto out_rqst;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun atomic_inc(&nlm_ntf_refcnt);
397*4882a593Smuzhiyun svc_sock_update_bufs(serv);
398*4882a593Smuzhiyun serv->sv_maxconn = nlm_max_connections;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun nlmsvc_task = kthread_create(lockd, nlmsvc_rqst, "%s", serv->sv_name);
401*4882a593Smuzhiyun if (IS_ERR(nlmsvc_task)) {
402*4882a593Smuzhiyun error = PTR_ERR(nlmsvc_task);
403*4882a593Smuzhiyun printk(KERN_WARNING
404*4882a593Smuzhiyun "lockd_up: kthread_run failed, error=%d\n", error);
405*4882a593Smuzhiyun goto out_task;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun nlmsvc_rqst->rq_task = nlmsvc_task;
408*4882a593Smuzhiyun wake_up_process(nlmsvc_task);
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun dprintk("lockd_up: service started\n");
411*4882a593Smuzhiyun return 0;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun out_task:
414*4882a593Smuzhiyun lockd_svc_exit_thread();
415*4882a593Smuzhiyun nlmsvc_task = NULL;
416*4882a593Smuzhiyun out_rqst:
417*4882a593Smuzhiyun nlmsvc_rqst = NULL;
418*4882a593Smuzhiyun return error;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun static const struct svc_serv_ops lockd_sv_ops = {
422*4882a593Smuzhiyun .svo_shutdown = svc_rpcb_cleanup,
423*4882a593Smuzhiyun .svo_enqueue_xprt = svc_xprt_do_enqueue,
424*4882a593Smuzhiyun };
425*4882a593Smuzhiyun
lockd_create_svc(void)426*4882a593Smuzhiyun static struct svc_serv *lockd_create_svc(void)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun struct svc_serv *serv;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun /*
431*4882a593Smuzhiyun * Check whether we're already up and running.
432*4882a593Smuzhiyun */
433*4882a593Smuzhiyun if (nlmsvc_rqst) {
434*4882a593Smuzhiyun /*
435*4882a593Smuzhiyun * Note: increase service usage, because later in case of error
436*4882a593Smuzhiyun * svc_destroy() will be called.
437*4882a593Smuzhiyun */
438*4882a593Smuzhiyun svc_get(nlmsvc_rqst->rq_server);
439*4882a593Smuzhiyun return nlmsvc_rqst->rq_server;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun /*
443*4882a593Smuzhiyun * Sanity check: if there's no pid,
444*4882a593Smuzhiyun * we should be the first user ...
445*4882a593Smuzhiyun */
446*4882a593Smuzhiyun if (nlmsvc_users)
447*4882a593Smuzhiyun printk(KERN_WARNING
448*4882a593Smuzhiyun "lockd_up: no pid, %d users??\n", nlmsvc_users);
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun if (!nlm_timeout)
451*4882a593Smuzhiyun nlm_timeout = LOCKD_DFLT_TIMEO;
452*4882a593Smuzhiyun nlmsvc_timeout = nlm_timeout * HZ;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, &lockd_sv_ops);
455*4882a593Smuzhiyun if (!serv) {
456*4882a593Smuzhiyun printk(KERN_WARNING "lockd_up: create service failed\n");
457*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun register_inetaddr_notifier(&lockd_inetaddr_notifier);
460*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
461*4882a593Smuzhiyun register_inet6addr_notifier(&lockd_inet6addr_notifier);
462*4882a593Smuzhiyun #endif
463*4882a593Smuzhiyun dprintk("lockd_up: service created\n");
464*4882a593Smuzhiyun return serv;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /*
468*4882a593Smuzhiyun * Bring up the lockd process if it's not already up.
469*4882a593Smuzhiyun */
lockd_up(struct net * net,const struct cred * cred)470*4882a593Smuzhiyun int lockd_up(struct net *net, const struct cred *cred)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun struct svc_serv *serv;
473*4882a593Smuzhiyun int error;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun mutex_lock(&nlmsvc_mutex);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun serv = lockd_create_svc();
478*4882a593Smuzhiyun if (IS_ERR(serv)) {
479*4882a593Smuzhiyun error = PTR_ERR(serv);
480*4882a593Smuzhiyun goto err_create;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun error = lockd_up_net(serv, net, cred);
484*4882a593Smuzhiyun if (error < 0) {
485*4882a593Smuzhiyun lockd_unregister_notifiers();
486*4882a593Smuzhiyun goto err_put;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun error = lockd_start_svc(serv);
490*4882a593Smuzhiyun if (error < 0) {
491*4882a593Smuzhiyun lockd_down_net(serv, net);
492*4882a593Smuzhiyun goto err_put;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun nlmsvc_users++;
495*4882a593Smuzhiyun /*
496*4882a593Smuzhiyun * Note: svc_serv structures have an initial use count of 1,
497*4882a593Smuzhiyun * so we exit through here on both success and failure.
498*4882a593Smuzhiyun */
499*4882a593Smuzhiyun err_put:
500*4882a593Smuzhiyun svc_destroy(serv);
501*4882a593Smuzhiyun err_create:
502*4882a593Smuzhiyun mutex_unlock(&nlmsvc_mutex);
503*4882a593Smuzhiyun return error;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(lockd_up);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun /*
508*4882a593Smuzhiyun * Decrement the user count and bring down lockd if we're the last.
509*4882a593Smuzhiyun */
510*4882a593Smuzhiyun void
lockd_down(struct net * net)511*4882a593Smuzhiyun lockd_down(struct net *net)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun mutex_lock(&nlmsvc_mutex);
514*4882a593Smuzhiyun lockd_down_net(nlmsvc_rqst->rq_server, net);
515*4882a593Smuzhiyun if (nlmsvc_users) {
516*4882a593Smuzhiyun if (--nlmsvc_users)
517*4882a593Smuzhiyun goto out;
518*4882a593Smuzhiyun } else {
519*4882a593Smuzhiyun printk(KERN_ERR "lockd_down: no users! task=%p\n",
520*4882a593Smuzhiyun nlmsvc_task);
521*4882a593Smuzhiyun BUG();
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun if (!nlmsvc_task) {
525*4882a593Smuzhiyun printk(KERN_ERR "lockd_down: no lockd running.\n");
526*4882a593Smuzhiyun BUG();
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun kthread_stop(nlmsvc_task);
529*4882a593Smuzhiyun dprintk("lockd_down: service stopped\n");
530*4882a593Smuzhiyun lockd_svc_exit_thread();
531*4882a593Smuzhiyun dprintk("lockd_down: service destroyed\n");
532*4882a593Smuzhiyun nlmsvc_task = NULL;
533*4882a593Smuzhiyun nlmsvc_rqst = NULL;
534*4882a593Smuzhiyun out:
535*4882a593Smuzhiyun mutex_unlock(&nlmsvc_mutex);
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(lockd_down);
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun #ifdef CONFIG_SYSCTL
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun /*
542*4882a593Smuzhiyun * Sysctl parameters (same as module parameters, different interface).
543*4882a593Smuzhiyun */
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun static struct ctl_table nlm_sysctls[] = {
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun .procname = "nlm_grace_period",
548*4882a593Smuzhiyun .data = &nlm_grace_period,
549*4882a593Smuzhiyun .maxlen = sizeof(unsigned long),
550*4882a593Smuzhiyun .mode = 0644,
551*4882a593Smuzhiyun .proc_handler = proc_doulongvec_minmax,
552*4882a593Smuzhiyun .extra1 = (unsigned long *) &nlm_grace_period_min,
553*4882a593Smuzhiyun .extra2 = (unsigned long *) &nlm_grace_period_max,
554*4882a593Smuzhiyun },
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun .procname = "nlm_timeout",
557*4882a593Smuzhiyun .data = &nlm_timeout,
558*4882a593Smuzhiyun .maxlen = sizeof(unsigned long),
559*4882a593Smuzhiyun .mode = 0644,
560*4882a593Smuzhiyun .proc_handler = proc_doulongvec_minmax,
561*4882a593Smuzhiyun .extra1 = (unsigned long *) &nlm_timeout_min,
562*4882a593Smuzhiyun .extra2 = (unsigned long *) &nlm_timeout_max,
563*4882a593Smuzhiyun },
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun .procname = "nlm_udpport",
566*4882a593Smuzhiyun .data = &nlm_udpport,
567*4882a593Smuzhiyun .maxlen = sizeof(int),
568*4882a593Smuzhiyun .mode = 0644,
569*4882a593Smuzhiyun .proc_handler = proc_dointvec_minmax,
570*4882a593Smuzhiyun .extra1 = (int *) &nlm_port_min,
571*4882a593Smuzhiyun .extra2 = (int *) &nlm_port_max,
572*4882a593Smuzhiyun },
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun .procname = "nlm_tcpport",
575*4882a593Smuzhiyun .data = &nlm_tcpport,
576*4882a593Smuzhiyun .maxlen = sizeof(int),
577*4882a593Smuzhiyun .mode = 0644,
578*4882a593Smuzhiyun .proc_handler = proc_dointvec_minmax,
579*4882a593Smuzhiyun .extra1 = (int *) &nlm_port_min,
580*4882a593Smuzhiyun .extra2 = (int *) &nlm_port_max,
581*4882a593Smuzhiyun },
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun .procname = "nsm_use_hostnames",
584*4882a593Smuzhiyun .data = &nsm_use_hostnames,
585*4882a593Smuzhiyun .maxlen = sizeof(int),
586*4882a593Smuzhiyun .mode = 0644,
587*4882a593Smuzhiyun .proc_handler = proc_dointvec,
588*4882a593Smuzhiyun },
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun .procname = "nsm_local_state",
591*4882a593Smuzhiyun .data = &nsm_local_state,
592*4882a593Smuzhiyun .maxlen = sizeof(int),
593*4882a593Smuzhiyun .mode = 0644,
594*4882a593Smuzhiyun .proc_handler = proc_dointvec,
595*4882a593Smuzhiyun },
596*4882a593Smuzhiyun { }
597*4882a593Smuzhiyun };
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun static struct ctl_table nlm_sysctl_dir[] = {
600*4882a593Smuzhiyun {
601*4882a593Smuzhiyun .procname = "nfs",
602*4882a593Smuzhiyun .mode = 0555,
603*4882a593Smuzhiyun .child = nlm_sysctls,
604*4882a593Smuzhiyun },
605*4882a593Smuzhiyun { }
606*4882a593Smuzhiyun };
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun static struct ctl_table nlm_sysctl_root[] = {
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun .procname = "fs",
611*4882a593Smuzhiyun .mode = 0555,
612*4882a593Smuzhiyun .child = nlm_sysctl_dir,
613*4882a593Smuzhiyun },
614*4882a593Smuzhiyun { }
615*4882a593Smuzhiyun };
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun #endif /* CONFIG_SYSCTL */
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun /*
620*4882a593Smuzhiyun * Module (and sysfs) parameters.
621*4882a593Smuzhiyun */
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun #define param_set_min_max(name, type, which_strtol, min, max) \
624*4882a593Smuzhiyun static int param_set_##name(const char *val, const struct kernel_param *kp) \
625*4882a593Smuzhiyun { \
626*4882a593Smuzhiyun char *endp; \
627*4882a593Smuzhiyun __typeof__(type) num = which_strtol(val, &endp, 0); \
628*4882a593Smuzhiyun if (endp == val || *endp || num < (min) || num > (max)) \
629*4882a593Smuzhiyun return -EINVAL; \
630*4882a593Smuzhiyun *((type *) kp->arg) = num; \
631*4882a593Smuzhiyun return 0; \
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun
is_callback(u32 proc)634*4882a593Smuzhiyun static inline int is_callback(u32 proc)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun return proc == NLMPROC_GRANTED
637*4882a593Smuzhiyun || proc == NLMPROC_GRANTED_MSG
638*4882a593Smuzhiyun || proc == NLMPROC_TEST_RES
639*4882a593Smuzhiyun || proc == NLMPROC_LOCK_RES
640*4882a593Smuzhiyun || proc == NLMPROC_CANCEL_RES
641*4882a593Smuzhiyun || proc == NLMPROC_UNLOCK_RES
642*4882a593Smuzhiyun || proc == NLMPROC_NSM_NOTIFY;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun
lockd_authenticate(struct svc_rqst * rqstp)646*4882a593Smuzhiyun static int lockd_authenticate(struct svc_rqst *rqstp)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun rqstp->rq_client = NULL;
649*4882a593Smuzhiyun switch (rqstp->rq_authop->flavour) {
650*4882a593Smuzhiyun case RPC_AUTH_NULL:
651*4882a593Smuzhiyun case RPC_AUTH_UNIX:
652*4882a593Smuzhiyun if (rqstp->rq_proc == 0)
653*4882a593Smuzhiyun return SVC_OK;
654*4882a593Smuzhiyun if (is_callback(rqstp->rq_proc)) {
655*4882a593Smuzhiyun /* Leave it to individual procedures to
656*4882a593Smuzhiyun * call nlmsvc_lookup_host(rqstp)
657*4882a593Smuzhiyun */
658*4882a593Smuzhiyun return SVC_OK;
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun return svc_set_client(rqstp);
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun return SVC_DENIED;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun param_set_min_max(port, int, simple_strtol, 0, 65535)
667*4882a593Smuzhiyun param_set_min_max(grace_period, unsigned long, simple_strtoul,
668*4882a593Smuzhiyun nlm_grace_period_min, nlm_grace_period_max)
669*4882a593Smuzhiyun param_set_min_max(timeout, unsigned long, simple_strtoul,
670*4882a593Smuzhiyun nlm_timeout_min, nlm_timeout_max)
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
673*4882a593Smuzhiyun MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION ".");
674*4882a593Smuzhiyun MODULE_LICENSE("GPL");
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun module_param_call(nlm_grace_period, param_set_grace_period, param_get_ulong,
677*4882a593Smuzhiyun &nlm_grace_period, 0644);
678*4882a593Smuzhiyun module_param_call(nlm_timeout, param_set_timeout, param_get_ulong,
679*4882a593Smuzhiyun &nlm_timeout, 0644);
680*4882a593Smuzhiyun module_param_call(nlm_udpport, param_set_port, param_get_int,
681*4882a593Smuzhiyun &nlm_udpport, 0644);
682*4882a593Smuzhiyun module_param_call(nlm_tcpport, param_set_port, param_get_int,
683*4882a593Smuzhiyun &nlm_tcpport, 0644);
684*4882a593Smuzhiyun module_param(nsm_use_hostnames, bool, 0644);
685*4882a593Smuzhiyun module_param(nlm_max_connections, uint, 0644);
686*4882a593Smuzhiyun
lockd_init_net(struct net * net)687*4882a593Smuzhiyun static int lockd_init_net(struct net *net)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun struct lockd_net *ln = net_generic(net, lockd_net_id);
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender);
692*4882a593Smuzhiyun INIT_LIST_HEAD(&ln->lockd_manager.list);
693*4882a593Smuzhiyun ln->lockd_manager.block_opens = false;
694*4882a593Smuzhiyun INIT_LIST_HEAD(&ln->nsm_handles);
695*4882a593Smuzhiyun return 0;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun
lockd_exit_net(struct net * net)698*4882a593Smuzhiyun static void lockd_exit_net(struct net *net)
699*4882a593Smuzhiyun {
700*4882a593Smuzhiyun struct lockd_net *ln = net_generic(net, lockd_net_id);
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun WARN_ONCE(!list_empty(&ln->lockd_manager.list),
703*4882a593Smuzhiyun "net %x %s: lockd_manager.list is not empty\n",
704*4882a593Smuzhiyun net->ns.inum, __func__);
705*4882a593Smuzhiyun WARN_ONCE(!list_empty(&ln->nsm_handles),
706*4882a593Smuzhiyun "net %x %s: nsm_handles list is not empty\n",
707*4882a593Smuzhiyun net->ns.inum, __func__);
708*4882a593Smuzhiyun WARN_ONCE(delayed_work_pending(&ln->grace_period_end),
709*4882a593Smuzhiyun "net %x %s: grace_period_end was not cancelled\n",
710*4882a593Smuzhiyun net->ns.inum, __func__);
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun static struct pernet_operations lockd_net_ops = {
714*4882a593Smuzhiyun .init = lockd_init_net,
715*4882a593Smuzhiyun .exit = lockd_exit_net,
716*4882a593Smuzhiyun .id = &lockd_net_id,
717*4882a593Smuzhiyun .size = sizeof(struct lockd_net),
718*4882a593Smuzhiyun };
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun /*
722*4882a593Smuzhiyun * Initialising and terminating the module.
723*4882a593Smuzhiyun */
724*4882a593Smuzhiyun
init_nlm(void)725*4882a593Smuzhiyun static int __init init_nlm(void)
726*4882a593Smuzhiyun {
727*4882a593Smuzhiyun int err;
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun #ifdef CONFIG_SYSCTL
730*4882a593Smuzhiyun err = -ENOMEM;
731*4882a593Smuzhiyun nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root);
732*4882a593Smuzhiyun if (nlm_sysctl_table == NULL)
733*4882a593Smuzhiyun goto err_sysctl;
734*4882a593Smuzhiyun #endif
735*4882a593Smuzhiyun err = register_pernet_subsys(&lockd_net_ops);
736*4882a593Smuzhiyun if (err)
737*4882a593Smuzhiyun goto err_pernet;
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun err = lockd_create_procfs();
740*4882a593Smuzhiyun if (err)
741*4882a593Smuzhiyun goto err_procfs;
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun return 0;
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun err_procfs:
746*4882a593Smuzhiyun unregister_pernet_subsys(&lockd_net_ops);
747*4882a593Smuzhiyun err_pernet:
748*4882a593Smuzhiyun #ifdef CONFIG_SYSCTL
749*4882a593Smuzhiyun unregister_sysctl_table(nlm_sysctl_table);
750*4882a593Smuzhiyun err_sysctl:
751*4882a593Smuzhiyun #endif
752*4882a593Smuzhiyun return err;
753*4882a593Smuzhiyun }
754*4882a593Smuzhiyun
exit_nlm(void)755*4882a593Smuzhiyun static void __exit exit_nlm(void)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun /* FIXME: delete all NLM clients */
758*4882a593Smuzhiyun nlm_shutdown_hosts();
759*4882a593Smuzhiyun lockd_remove_procfs();
760*4882a593Smuzhiyun unregister_pernet_subsys(&lockd_net_ops);
761*4882a593Smuzhiyun #ifdef CONFIG_SYSCTL
762*4882a593Smuzhiyun unregister_sysctl_table(nlm_sysctl_table);
763*4882a593Smuzhiyun #endif
764*4882a593Smuzhiyun }
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun module_init(init_nlm);
767*4882a593Smuzhiyun module_exit(exit_nlm);
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun /*
770*4882a593Smuzhiyun * Define NLM program and procedures
771*4882a593Smuzhiyun */
772*4882a593Smuzhiyun static unsigned int nlmsvc_version1_count[17];
773*4882a593Smuzhiyun static const struct svc_version nlmsvc_version1 = {
774*4882a593Smuzhiyun .vs_vers = 1,
775*4882a593Smuzhiyun .vs_nproc = 17,
776*4882a593Smuzhiyun .vs_proc = nlmsvc_procedures,
777*4882a593Smuzhiyun .vs_count = nlmsvc_version1_count,
778*4882a593Smuzhiyun .vs_xdrsize = NLMSVC_XDRSIZE,
779*4882a593Smuzhiyun };
780*4882a593Smuzhiyun static unsigned int nlmsvc_version3_count[24];
781*4882a593Smuzhiyun static const struct svc_version nlmsvc_version3 = {
782*4882a593Smuzhiyun .vs_vers = 3,
783*4882a593Smuzhiyun .vs_nproc = 24,
784*4882a593Smuzhiyun .vs_proc = nlmsvc_procedures,
785*4882a593Smuzhiyun .vs_count = nlmsvc_version3_count,
786*4882a593Smuzhiyun .vs_xdrsize = NLMSVC_XDRSIZE,
787*4882a593Smuzhiyun };
788*4882a593Smuzhiyun #ifdef CONFIG_LOCKD_V4
789*4882a593Smuzhiyun static unsigned int nlmsvc_version4_count[24];
790*4882a593Smuzhiyun static const struct svc_version nlmsvc_version4 = {
791*4882a593Smuzhiyun .vs_vers = 4,
792*4882a593Smuzhiyun .vs_nproc = 24,
793*4882a593Smuzhiyun .vs_proc = nlmsvc_procedures4,
794*4882a593Smuzhiyun .vs_count = nlmsvc_version4_count,
795*4882a593Smuzhiyun .vs_xdrsize = NLMSVC_XDRSIZE,
796*4882a593Smuzhiyun };
797*4882a593Smuzhiyun #endif
798*4882a593Smuzhiyun static const struct svc_version *nlmsvc_version[] = {
799*4882a593Smuzhiyun [1] = &nlmsvc_version1,
800*4882a593Smuzhiyun [3] = &nlmsvc_version3,
801*4882a593Smuzhiyun #ifdef CONFIG_LOCKD_V4
802*4882a593Smuzhiyun [4] = &nlmsvc_version4,
803*4882a593Smuzhiyun #endif
804*4882a593Smuzhiyun };
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun static struct svc_stat nlmsvc_stats;
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun #define NLM_NRVERS ARRAY_SIZE(nlmsvc_version)
809*4882a593Smuzhiyun static struct svc_program nlmsvc_program = {
810*4882a593Smuzhiyun .pg_prog = NLM_PROGRAM, /* program number */
811*4882a593Smuzhiyun .pg_nvers = NLM_NRVERS, /* number of entries in nlmsvc_version */
812*4882a593Smuzhiyun .pg_vers = nlmsvc_version, /* version table */
813*4882a593Smuzhiyun .pg_name = "lockd", /* service name */
814*4882a593Smuzhiyun .pg_class = "nfsd", /* share authentication with nfsd */
815*4882a593Smuzhiyun .pg_stats = &nlmsvc_stats, /* stats table */
816*4882a593Smuzhiyun .pg_authenticate = &lockd_authenticate, /* export authentication */
817*4882a593Smuzhiyun .pg_init_request = svc_generic_init_request,
818*4882a593Smuzhiyun .pg_rpcbind_set = svc_generic_rpcbind_set,
819*4882a593Smuzhiyun };
820