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