diff options
Diffstat (limited to 'fs/lockd/svc.c')
-rw-r--r-- | fs/lockd/svc.c | 117 |
1 files changed, 102 insertions, 15 deletions
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index c061b9aa7ddb..2774e1013b34 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -35,6 +35,8 @@ | |||
35 | #include <linux/lockd/lockd.h> | 35 | #include <linux/lockd/lockd.h> |
36 | #include <linux/nfs.h> | 36 | #include <linux/nfs.h> |
37 | 37 | ||
38 | #include "netns.h" | ||
39 | |||
38 | #define NLMDBG_FACILITY NLMDBG_SVC | 40 | #define NLMDBG_FACILITY NLMDBG_SVC |
39 | #define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE) | 41 | #define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE) |
40 | #define ALLOWED_SIGS (sigmask(SIGKILL)) | 42 | #define ALLOWED_SIGS (sigmask(SIGKILL)) |
@@ -50,6 +52,8 @@ static struct task_struct *nlmsvc_task; | |||
50 | static struct svc_rqst *nlmsvc_rqst; | 52 | static struct svc_rqst *nlmsvc_rqst; |
51 | unsigned long nlmsvc_timeout; | 53 | unsigned long nlmsvc_timeout; |
52 | 54 | ||
55 | int lockd_net_id; | ||
56 | |||
53 | /* | 57 | /* |
54 | * These can be set at insmod time (useful for NFS as root filesystem), | 58 | * These can be set at insmod time (useful for NFS as root filesystem), |
55 | * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 | 59 | * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 |
@@ -189,27 +193,29 @@ lockd(void *vrqstp) | |||
189 | } | 193 | } |
190 | 194 | ||
191 | static int create_lockd_listener(struct svc_serv *serv, const char *name, | 195 | static int create_lockd_listener(struct svc_serv *serv, const char *name, |
192 | const int family, const unsigned short port) | 196 | struct net *net, const int family, |
197 | const unsigned short port) | ||
193 | { | 198 | { |
194 | struct svc_xprt *xprt; | 199 | struct svc_xprt *xprt; |
195 | 200 | ||
196 | xprt = svc_find_xprt(serv, name, family, 0); | 201 | xprt = svc_find_xprt(serv, name, net, family, 0); |
197 | if (xprt == NULL) | 202 | if (xprt == NULL) |
198 | return svc_create_xprt(serv, name, &init_net, family, port, | 203 | return svc_create_xprt(serv, name, net, family, port, |
199 | SVC_SOCK_DEFAULTS); | 204 | SVC_SOCK_DEFAULTS); |
200 | svc_xprt_put(xprt); | 205 | svc_xprt_put(xprt); |
201 | return 0; | 206 | return 0; |
202 | } | 207 | } |
203 | 208 | ||
204 | static int create_lockd_family(struct svc_serv *serv, const int family) | 209 | static int create_lockd_family(struct svc_serv *serv, struct net *net, |
210 | const int family) | ||
205 | { | 211 | { |
206 | int err; | 212 | int err; |
207 | 213 | ||
208 | err = create_lockd_listener(serv, "udp", family, nlm_udpport); | 214 | err = create_lockd_listener(serv, "udp", net, family, nlm_udpport); |
209 | if (err < 0) | 215 | if (err < 0) |
210 | return err; | 216 | return err; |
211 | 217 | ||
212 | return create_lockd_listener(serv, "tcp", family, nlm_tcpport); | 218 | return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport); |
213 | } | 219 | } |
214 | 220 | ||
215 | /* | 221 | /* |
@@ -222,16 +228,16 @@ static int create_lockd_family(struct svc_serv *serv, const int family) | |||
222 | * Returns zero if all listeners are available; otherwise a | 228 | * Returns zero if all listeners are available; otherwise a |
223 | * negative errno value is returned. | 229 | * negative errno value is returned. |
224 | */ | 230 | */ |
225 | static int make_socks(struct svc_serv *serv) | 231 | static int make_socks(struct svc_serv *serv, struct net *net) |
226 | { | 232 | { |
227 | static int warned; | 233 | static int warned; |
228 | int err; | 234 | int err; |
229 | 235 | ||
230 | err = create_lockd_family(serv, PF_INET); | 236 | err = create_lockd_family(serv, net, PF_INET); |
231 | if (err < 0) | 237 | if (err < 0) |
232 | goto out_err; | 238 | goto out_err; |
233 | 239 | ||
234 | err = create_lockd_family(serv, PF_INET6); | 240 | err = create_lockd_family(serv, net, PF_INET6); |
235 | if (err < 0 && err != -EAFNOSUPPORT) | 241 | if (err < 0 && err != -EAFNOSUPPORT) |
236 | goto out_err; | 242 | goto out_err; |
237 | 243 | ||
@@ -245,6 +251,47 @@ out_err: | |||
245 | return err; | 251 | return err; |
246 | } | 252 | } |
247 | 253 | ||
254 | static int lockd_up_net(struct net *net) | ||
255 | { | ||
256 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
257 | struct svc_serv *serv = nlmsvc_rqst->rq_server; | ||
258 | int error; | ||
259 | |||
260 | if (ln->nlmsvc_users) | ||
261 | return 0; | ||
262 | |||
263 | error = svc_rpcb_setup(serv, net); | ||
264 | if (error) | ||
265 | goto err_rpcb; | ||
266 | |||
267 | error = make_socks(serv, net); | ||
268 | if (error < 0) | ||
269 | goto err_socks; | ||
270 | return 0; | ||
271 | |||
272 | err_socks: | ||
273 | svc_rpcb_cleanup(serv, net); | ||
274 | err_rpcb: | ||
275 | return error; | ||
276 | } | ||
277 | |||
278 | static void lockd_down_net(struct net *net) | ||
279 | { | ||
280 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
281 | struct svc_serv *serv = nlmsvc_rqst->rq_server; | ||
282 | |||
283 | if (ln->nlmsvc_users) { | ||
284 | if (--ln->nlmsvc_users == 0) { | ||
285 | nlm_shutdown_hosts_net(net); | ||
286 | svc_shutdown_net(serv, net); | ||
287 | } | ||
288 | } else { | ||
289 | printk(KERN_ERR "lockd_down_net: no users! task=%p, net=%p\n", | ||
290 | nlmsvc_task, net); | ||
291 | BUG(); | ||
292 | } | ||
293 | } | ||
294 | |||
248 | /* | 295 | /* |
249 | * Bring up the lockd process if it's not already up. | 296 | * Bring up the lockd process if it's not already up. |
250 | */ | 297 | */ |
@@ -252,13 +299,16 @@ int lockd_up(void) | |||
252 | { | 299 | { |
253 | struct svc_serv *serv; | 300 | struct svc_serv *serv; |
254 | int error = 0; | 301 | int error = 0; |
302 | struct net *net = current->nsproxy->net_ns; | ||
255 | 303 | ||
256 | mutex_lock(&nlmsvc_mutex); | 304 | mutex_lock(&nlmsvc_mutex); |
257 | /* | 305 | /* |
258 | * Check whether we're already up and running. | 306 | * Check whether we're already up and running. |
259 | */ | 307 | */ |
260 | if (nlmsvc_rqst) | 308 | if (nlmsvc_rqst) { |
309 | error = lockd_up_net(net); | ||
261 | goto out; | 310 | goto out; |
311 | } | ||
262 | 312 | ||
263 | /* | 313 | /* |
264 | * Sanity check: if there's no pid, | 314 | * Sanity check: if there's no pid, |
@@ -275,7 +325,7 @@ int lockd_up(void) | |||
275 | goto out; | 325 | goto out; |
276 | } | 326 | } |
277 | 327 | ||
278 | error = make_socks(serv); | 328 | error = make_socks(serv, net); |
279 | if (error < 0) | 329 | if (error < 0) |
280 | goto destroy_and_out; | 330 | goto destroy_and_out; |
281 | 331 | ||
@@ -313,8 +363,12 @@ int lockd_up(void) | |||
313 | destroy_and_out: | 363 | destroy_and_out: |
314 | svc_destroy(serv); | 364 | svc_destroy(serv); |
315 | out: | 365 | out: |
316 | if (!error) | 366 | if (!error) { |
367 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
368 | |||
369 | ln->nlmsvc_users++; | ||
317 | nlmsvc_users++; | 370 | nlmsvc_users++; |
371 | } | ||
318 | mutex_unlock(&nlmsvc_mutex); | 372 | mutex_unlock(&nlmsvc_mutex); |
319 | return error; | 373 | return error; |
320 | } | 374 | } |
@@ -328,8 +382,10 @@ lockd_down(void) | |||
328 | { | 382 | { |
329 | mutex_lock(&nlmsvc_mutex); | 383 | mutex_lock(&nlmsvc_mutex); |
330 | if (nlmsvc_users) { | 384 | if (nlmsvc_users) { |
331 | if (--nlmsvc_users) | 385 | if (--nlmsvc_users) { |
386 | lockd_down_net(current->nsproxy->net_ns); | ||
332 | goto out; | 387 | goto out; |
388 | } | ||
333 | } else { | 389 | } else { |
334 | printk(KERN_ERR "lockd_down: no users! task=%p\n", | 390 | printk(KERN_ERR "lockd_down: no users! task=%p\n", |
335 | nlmsvc_task); | 391 | nlmsvc_task); |
@@ -497,24 +553,55 @@ module_param_call(nlm_tcpport, param_set_port, param_get_int, | |||
497 | module_param(nsm_use_hostnames, bool, 0644); | 553 | module_param(nsm_use_hostnames, bool, 0644); |
498 | module_param(nlm_max_connections, uint, 0644); | 554 | module_param(nlm_max_connections, uint, 0644); |
499 | 555 | ||
556 | static int lockd_init_net(struct net *net) | ||
557 | { | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static void lockd_exit_net(struct net *net) | ||
562 | { | ||
563 | } | ||
564 | |||
565 | static struct pernet_operations lockd_net_ops = { | ||
566 | .init = lockd_init_net, | ||
567 | .exit = lockd_exit_net, | ||
568 | .id = &lockd_net_id, | ||
569 | .size = sizeof(struct lockd_net), | ||
570 | }; | ||
571 | |||
572 | |||
500 | /* | 573 | /* |
501 | * Initialising and terminating the module. | 574 | * Initialising and terminating the module. |
502 | */ | 575 | */ |
503 | 576 | ||
504 | static int __init init_nlm(void) | 577 | static int __init init_nlm(void) |
505 | { | 578 | { |
579 | int err; | ||
580 | |||
506 | #ifdef CONFIG_SYSCTL | 581 | #ifdef CONFIG_SYSCTL |
582 | err = -ENOMEM; | ||
507 | nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); | 583 | nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); |
508 | return nlm_sysctl_table ? 0 : -ENOMEM; | 584 | if (nlm_sysctl_table == NULL) |
509 | #else | 585 | goto err_sysctl; |
586 | #endif | ||
587 | err = register_pernet_subsys(&lockd_net_ops); | ||
588 | if (err) | ||
589 | goto err_pernet; | ||
510 | return 0; | 590 | return 0; |
591 | |||
592 | err_pernet: | ||
593 | #ifdef CONFIG_SYSCTL | ||
594 | unregister_sysctl_table(nlm_sysctl_table); | ||
511 | #endif | 595 | #endif |
596 | err_sysctl: | ||
597 | return err; | ||
512 | } | 598 | } |
513 | 599 | ||
514 | static void __exit exit_nlm(void) | 600 | static void __exit exit_nlm(void) |
515 | { | 601 | { |
516 | /* FIXME: delete all NLM clients */ | 602 | /* FIXME: delete all NLM clients */ |
517 | nlm_shutdown_hosts(); | 603 | nlm_shutdown_hosts(); |
604 | unregister_pernet_subsys(&lockd_net_ops); | ||
518 | #ifdef CONFIG_SYSCTL | 605 | #ifdef CONFIG_SYSCTL |
519 | unregister_sysctl_table(nlm_sysctl_table); | 606 | unregister_sysctl_table(nlm_sysctl_table); |
520 | #endif | 607 | #endif |