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