xref: /OK3568_Linux_fs/kernel/fs/lockd/svc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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