File Index
Files and directories
Sign in
FILE

svc.c

File preview with syntax highlighting.

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