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