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