diff options
-rw-r--r-- | fs/nfsd/nfsctl.c | 37 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 45 | ||||
-rw-r--r-- | include/linux/nfsd/nfsd.h | 1 | ||||
-rw-r--r-- | net/sunrpc/svc.c | 15 |
4 files changed, 65 insertions, 33 deletions
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 5ac00c4fee91..049d2a9c7715 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -450,22 +450,26 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) | |||
450 | int i; | 450 | int i; |
451 | int rv; | 451 | int rv; |
452 | int len; | 452 | int len; |
453 | int npools = nfsd_nrpools(); | 453 | int npools; |
454 | int *nthreads; | 454 | int *nthreads; |
455 | 455 | ||
456 | mutex_lock(&nfsd_mutex); | ||
457 | npools = nfsd_nrpools(); | ||
456 | if (npools == 0) { | 458 | if (npools == 0) { |
457 | /* | 459 | /* |
458 | * NFS is shut down. The admin can start it by | 460 | * NFS is shut down. The admin can start it by |
459 | * writing to the threads file but NOT the pool_threads | 461 | * writing to the threads file but NOT the pool_threads |
460 | * file, sorry. Report zero threads. | 462 | * file, sorry. Report zero threads. |
461 | */ | 463 | */ |
464 | mutex_unlock(&nfsd_mutex); | ||
462 | strcpy(buf, "0\n"); | 465 | strcpy(buf, "0\n"); |
463 | return strlen(buf); | 466 | return strlen(buf); |
464 | } | 467 | } |
465 | 468 | ||
466 | nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL); | 469 | nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL); |
470 | rv = -ENOMEM; | ||
467 | if (nthreads == NULL) | 471 | if (nthreads == NULL) |
468 | return -ENOMEM; | 472 | goto out_free; |
469 | 473 | ||
470 | if (size > 0) { | 474 | if (size > 0) { |
471 | for (i = 0; i < npools; i++) { | 475 | for (i = 0; i < npools; i++) { |
@@ -496,10 +500,12 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) | |||
496 | mesg += len; | 500 | mesg += len; |
497 | } | 501 | } |
498 | 502 | ||
503 | mutex_unlock(&nfsd_mutex); | ||
499 | return (mesg-buf); | 504 | return (mesg-buf); |
500 | 505 | ||
501 | out_free: | 506 | out_free: |
502 | kfree(nthreads); | 507 | kfree(nthreads); |
508 | mutex_unlock(&nfsd_mutex); | ||
503 | return rv; | 509 | return rv; |
504 | } | 510 | } |
505 | 511 | ||
@@ -566,14 +572,13 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) | |||
566 | return len; | 572 | return len; |
567 | } | 573 | } |
568 | 574 | ||
569 | static ssize_t write_ports(struct file *file, char *buf, size_t size) | 575 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) |
570 | { | 576 | { |
571 | if (size == 0) { | 577 | if (size == 0) { |
572 | int len = 0; | 578 | int len = 0; |
573 | lock_kernel(); | 579 | |
574 | if (nfsd_serv) | 580 | if (nfsd_serv) |
575 | len = svc_xprt_names(nfsd_serv, buf, 0); | 581 | len = svc_xprt_names(nfsd_serv, buf, 0); |
576 | unlock_kernel(); | ||
577 | return len; | 582 | return len; |
578 | } | 583 | } |
579 | /* Either a single 'fd' number is written, in which | 584 | /* Either a single 'fd' number is written, in which |
@@ -603,9 +608,7 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) | |||
603 | /* Decrease the count, but don't shutdown the | 608 | /* Decrease the count, but don't shutdown the |
604 | * the service | 609 | * the service |
605 | */ | 610 | */ |
606 | lock_kernel(); | ||
607 | nfsd_serv->sv_nrthreads--; | 611 | nfsd_serv->sv_nrthreads--; |
608 | unlock_kernel(); | ||
609 | } | 612 | } |
610 | return err < 0 ? err : 0; | 613 | return err < 0 ? err : 0; |
611 | } | 614 | } |
@@ -614,10 +617,8 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) | |||
614 | int len = 0; | 617 | int len = 0; |
615 | if (!toclose) | 618 | if (!toclose) |
616 | return -ENOMEM; | 619 | return -ENOMEM; |
617 | lock_kernel(); | ||
618 | if (nfsd_serv) | 620 | if (nfsd_serv) |
619 | len = svc_sock_names(buf, nfsd_serv, toclose); | 621 | len = svc_sock_names(buf, nfsd_serv, toclose); |
620 | unlock_kernel(); | ||
621 | if (len >= 0) | 622 | if (len >= 0) |
622 | lockd_down(); | 623 | lockd_down(); |
623 | kfree(toclose); | 624 | kfree(toclose); |
@@ -655,7 +656,6 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) | |||
655 | if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { | 656 | if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { |
656 | if (port == 0) | 657 | if (port == 0) |
657 | return -EINVAL; | 658 | return -EINVAL; |
658 | lock_kernel(); | ||
659 | if (nfsd_serv) { | 659 | if (nfsd_serv) { |
660 | xprt = svc_find_xprt(nfsd_serv, transport, | 660 | xprt = svc_find_xprt(nfsd_serv, transport, |
661 | AF_UNSPEC, port); | 661 | AF_UNSPEC, port); |
@@ -666,13 +666,22 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) | |||
666 | } else | 666 | } else |
667 | err = -ENOTCONN; | 667 | err = -ENOTCONN; |
668 | } | 668 | } |
669 | unlock_kernel(); | ||
670 | return err < 0 ? err : 0; | 669 | return err < 0 ? err : 0; |
671 | } | 670 | } |
672 | } | 671 | } |
673 | return -EINVAL; | 672 | return -EINVAL; |
674 | } | 673 | } |
675 | 674 | ||
675 | static ssize_t write_ports(struct file *file, char *buf, size_t size) | ||
676 | { | ||
677 | ssize_t rv; | ||
678 | mutex_lock(&nfsd_mutex); | ||
679 | rv = __write_ports(file, buf, size); | ||
680 | mutex_unlock(&nfsd_mutex); | ||
681 | return rv; | ||
682 | } | ||
683 | |||
684 | |||
676 | int nfsd_max_blksize; | 685 | int nfsd_max_blksize; |
677 | 686 | ||
678 | static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) | 687 | static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) |
@@ -691,13 +700,13 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) | |||
691 | if (bsize > NFSSVC_MAXBLKSIZE) | 700 | if (bsize > NFSSVC_MAXBLKSIZE) |
692 | bsize = NFSSVC_MAXBLKSIZE; | 701 | bsize = NFSSVC_MAXBLKSIZE; |
693 | bsize &= ~(1024-1); | 702 | bsize &= ~(1024-1); |
694 | lock_kernel(); | 703 | mutex_lock(&nfsd_mutex); |
695 | if (nfsd_serv && nfsd_serv->sv_nrthreads) { | 704 | if (nfsd_serv && nfsd_serv->sv_nrthreads) { |
696 | unlock_kernel(); | 705 | mutex_unlock(&nfsd_mutex); |
697 | return -EBUSY; | 706 | return -EBUSY; |
698 | } | 707 | } |
699 | nfsd_max_blksize = bsize; | 708 | nfsd_max_blksize = bsize; |
700 | unlock_kernel(); | 709 | mutex_unlock(&nfsd_mutex); |
701 | } | 710 | } |
702 | return sprintf(buf, "%d\n", nfsd_max_blksize); | 711 | return sprintf(buf, "%d\n", nfsd_max_blksize); |
703 | } | 712 | } |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 941041f4b136..512bd04c6dda 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -53,11 +53,27 @@ | |||
53 | extern struct svc_program nfsd_program; | 53 | extern struct svc_program nfsd_program; |
54 | static void nfsd(struct svc_rqst *rqstp); | 54 | static void nfsd(struct svc_rqst *rqstp); |
55 | struct timeval nfssvc_boot; | 55 | struct timeval nfssvc_boot; |
56 | struct svc_serv *nfsd_serv; | ||
57 | static atomic_t nfsd_busy; | 56 | static atomic_t nfsd_busy; |
58 | static unsigned long nfsd_last_call; | 57 | static unsigned long nfsd_last_call; |
59 | static DEFINE_SPINLOCK(nfsd_call_lock); | 58 | static DEFINE_SPINLOCK(nfsd_call_lock); |
60 | 59 | ||
60 | /* | ||
61 | * nfsd_mutex protects nfsd_serv -- both the pointer itself and the members | ||
62 | * of the svc_serv struct. In particular, ->sv_nrthreads but also to some | ||
63 | * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt | ||
64 | * | ||
65 | * If (out side the lock) nfsd_serv is non-NULL, then it must point to a | ||
66 | * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number | ||
67 | * of nfsd threads must exist and each must listed in ->sp_all_threads in each | ||
68 | * entry of ->sv_pools[]. | ||
69 | * | ||
70 | * Transitions of the thread count between zero and non-zero are of particular | ||
71 | * interest since the svc_serv needs to be created and initialized at that | ||
72 | * point, or freed. | ||
73 | */ | ||
74 | DEFINE_MUTEX(nfsd_mutex); | ||
75 | struct svc_serv *nfsd_serv; | ||
76 | |||
61 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 77 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
62 | static struct svc_stat nfsd_acl_svcstats; | 78 | static struct svc_stat nfsd_acl_svcstats; |
63 | static struct svc_version * nfsd_acl_version[] = { | 79 | static struct svc_version * nfsd_acl_version[] = { |
@@ -190,13 +206,14 @@ void nfsd_reset_versions(void) | |||
190 | } | 206 | } |
191 | } | 207 | } |
192 | 208 | ||
209 | |||
193 | int nfsd_create_serv(void) | 210 | int nfsd_create_serv(void) |
194 | { | 211 | { |
195 | int err = 0; | 212 | int err = 0; |
196 | lock_kernel(); | 213 | |
214 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | ||
197 | if (nfsd_serv) { | 215 | if (nfsd_serv) { |
198 | svc_get(nfsd_serv); | 216 | svc_get(nfsd_serv); |
199 | unlock_kernel(); | ||
200 | return 0; | 217 | return 0; |
201 | } | 218 | } |
202 | if (nfsd_max_blksize == 0) { | 219 | if (nfsd_max_blksize == 0) { |
@@ -223,7 +240,7 @@ int nfsd_create_serv(void) | |||
223 | nfsd, SIG_NOCLEAN, THIS_MODULE); | 240 | nfsd, SIG_NOCLEAN, THIS_MODULE); |
224 | if (nfsd_serv == NULL) | 241 | if (nfsd_serv == NULL) |
225 | err = -ENOMEM; | 242 | err = -ENOMEM; |
226 | unlock_kernel(); | 243 | |
227 | do_gettimeofday(&nfssvc_boot); /* record boot time */ | 244 | do_gettimeofday(&nfssvc_boot); /* record boot time */ |
228 | return err; | 245 | return err; |
229 | } | 246 | } |
@@ -282,6 +299,8 @@ int nfsd_set_nrthreads(int n, int *nthreads) | |||
282 | int tot = 0; | 299 | int tot = 0; |
283 | int err = 0; | 300 | int err = 0; |
284 | 301 | ||
302 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | ||
303 | |||
285 | if (nfsd_serv == NULL || n <= 0) | 304 | if (nfsd_serv == NULL || n <= 0) |
286 | return 0; | 305 | return 0; |
287 | 306 | ||
@@ -316,7 +335,6 @@ int nfsd_set_nrthreads(int n, int *nthreads) | |||
316 | nthreads[0] = 1; | 335 | nthreads[0] = 1; |
317 | 336 | ||
318 | /* apply the new numbers */ | 337 | /* apply the new numbers */ |
319 | lock_kernel(); | ||
320 | svc_get(nfsd_serv); | 338 | svc_get(nfsd_serv); |
321 | for (i = 0; i < n; i++) { | 339 | for (i = 0; i < n; i++) { |
322 | err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i], | 340 | err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i], |
@@ -325,7 +343,6 @@ int nfsd_set_nrthreads(int n, int *nthreads) | |||
325 | break; | 343 | break; |
326 | } | 344 | } |
327 | svc_destroy(nfsd_serv); | 345 | svc_destroy(nfsd_serv); |
328 | unlock_kernel(); | ||
329 | 346 | ||
330 | return err; | 347 | return err; |
331 | } | 348 | } |
@@ -334,8 +351,8 @@ int | |||
334 | nfsd_svc(unsigned short port, int nrservs) | 351 | nfsd_svc(unsigned short port, int nrservs) |
335 | { | 352 | { |
336 | int error; | 353 | int error; |
337 | 354 | ||
338 | lock_kernel(); | 355 | mutex_lock(&nfsd_mutex); |
339 | dprintk("nfsd: creating service\n"); | 356 | dprintk("nfsd: creating service\n"); |
340 | error = -EINVAL; | 357 | error = -EINVAL; |
341 | if (nrservs <= 0) | 358 | if (nrservs <= 0) |
@@ -363,7 +380,7 @@ nfsd_svc(unsigned short port, int nrservs) | |||
363 | failure: | 380 | failure: |
364 | svc_destroy(nfsd_serv); /* Release server */ | 381 | svc_destroy(nfsd_serv); /* Release server */ |
365 | out: | 382 | out: |
366 | unlock_kernel(); | 383 | mutex_unlock(&nfsd_mutex); |
367 | return error; | 384 | return error; |
368 | } | 385 | } |
369 | 386 | ||
@@ -399,7 +416,7 @@ nfsd(struct svc_rqst *rqstp) | |||
399 | sigset_t shutdown_mask, allowed_mask; | 416 | sigset_t shutdown_mask, allowed_mask; |
400 | 417 | ||
401 | /* Lock module and set up kernel thread */ | 418 | /* Lock module and set up kernel thread */ |
402 | lock_kernel(); | 419 | mutex_lock(&nfsd_mutex); |
403 | daemonize("nfsd"); | 420 | daemonize("nfsd"); |
404 | 421 | ||
405 | /* After daemonize() this kernel thread shares current->fs | 422 | /* After daemonize() this kernel thread shares current->fs |
@@ -417,11 +434,13 @@ nfsd(struct svc_rqst *rqstp) | |||
417 | siginitsetinv(&shutdown_mask, SHUTDOWN_SIGS); | 434 | siginitsetinv(&shutdown_mask, SHUTDOWN_SIGS); |
418 | siginitsetinv(&allowed_mask, ALLOWED_SIGS); | 435 | siginitsetinv(&allowed_mask, ALLOWED_SIGS); |
419 | 436 | ||
437 | |||
420 | nfsdstats.th_cnt++; | 438 | nfsdstats.th_cnt++; |
421 | 439 | ||
422 | rqstp->rq_task = current; | 440 | rqstp->rq_task = current; |
423 | 441 | ||
424 | unlock_kernel(); | 442 | mutex_unlock(&nfsd_mutex); |
443 | |||
425 | 444 | ||
426 | /* | 445 | /* |
427 | * We want less throttling in balance_dirty_pages() so that nfs to | 446 | * We want less throttling in balance_dirty_pages() so that nfs to |
@@ -477,7 +496,7 @@ nfsd(struct svc_rqst *rqstp) | |||
477 | /* Clear signals before calling svc_exit_thread() */ | 496 | /* Clear signals before calling svc_exit_thread() */ |
478 | flush_signals(current); | 497 | flush_signals(current); |
479 | 498 | ||
480 | lock_kernel(); | 499 | mutex_lock(&nfsd_mutex); |
481 | 500 | ||
482 | nfsdstats.th_cnt --; | 501 | nfsdstats.th_cnt --; |
483 | 502 | ||
@@ -486,7 +505,7 @@ out: | |||
486 | svc_exit_thread(rqstp); | 505 | svc_exit_thread(rqstp); |
487 | 506 | ||
488 | /* Release module */ | 507 | /* Release module */ |
489 | unlock_kernel(); | 508 | mutex_unlock(&nfsd_mutex); |
490 | module_put_and_exit(0); | 509 | module_put_and_exit(0); |
491 | } | 510 | } |
492 | 511 | ||
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 41d30c9c9de6..88d85b964429 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h | |||
@@ -54,6 +54,7 @@ typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int); | |||
54 | extern struct svc_program nfsd_program; | 54 | extern struct svc_program nfsd_program; |
55 | extern struct svc_version nfsd_version2, nfsd_version3, | 55 | extern struct svc_version nfsd_version2, nfsd_version3, |
56 | nfsd_version4; | 56 | nfsd_version4; |
57 | extern struct mutex nfsd_mutex; | ||
57 | extern struct svc_serv *nfsd_serv; | 58 | extern struct svc_serv *nfsd_serv; |
58 | 59 | ||
59 | extern struct seq_operations nfs_exports_op; | 60 | extern struct seq_operations nfs_exports_op; |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 01c7e311b904..7bffaff2a3ab 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
@@ -461,7 +461,8 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize, | |||
461 | EXPORT_SYMBOL(svc_create_pooled); | 461 | EXPORT_SYMBOL(svc_create_pooled); |
462 | 462 | ||
463 | /* | 463 | /* |
464 | * Destroy an RPC service. Should be called with the BKL held | 464 | * Destroy an RPC service. Should be called with appropriate locking to |
465 | * protect the sv_nrthreads, sv_permsocks and sv_tempsocks. | ||
465 | */ | 466 | */ |
466 | void | 467 | void |
467 | svc_destroy(struct svc_serv *serv) | 468 | svc_destroy(struct svc_serv *serv) |
@@ -578,9 +579,10 @@ out_enomem: | |||
578 | EXPORT_SYMBOL(svc_prepare_thread); | 579 | EXPORT_SYMBOL(svc_prepare_thread); |
579 | 580 | ||
580 | /* | 581 | /* |
581 | * Create a thread in the given pool. Caller must hold BKL. | 582 | * Create a thread in the given pool. Caller must hold BKL or another lock to |
582 | * On a NUMA or SMP machine, with a multi-pool serv, the thread | 583 | * serialize access to the svc_serv struct. On a NUMA or SMP machine, with a |
583 | * will be restricted to run on the cpus belonging to the pool. | 584 | * multi-pool serv, the thread will be restricted to run on the cpus belonging |
585 | * to the pool. | ||
584 | */ | 586 | */ |
585 | static int | 587 | static int |
586 | __svc_create_thread(svc_thread_fn func, struct svc_serv *serv, | 588 | __svc_create_thread(svc_thread_fn func, struct svc_serv *serv, |
@@ -674,7 +676,7 @@ found_pool: | |||
674 | * of threads the given number. If `pool' is non-NULL, applies | 676 | * of threads the given number. If `pool' is non-NULL, applies |
675 | * only to threads in that pool, otherwise round-robins between | 677 | * only to threads in that pool, otherwise round-robins between |
676 | * all pools. Must be called with a svc_get() reference and | 678 | * all pools. Must be called with a svc_get() reference and |
677 | * the BKL held. | 679 | * the BKL or another lock to protect access to svc_serv fields. |
678 | * | 680 | * |
679 | * Destroying threads relies on the service threads filling in | 681 | * Destroying threads relies on the service threads filling in |
680 | * rqstp->rq_task, which only the nfs ones do. Assumes the serv | 682 | * rqstp->rq_task, which only the nfs ones do. Assumes the serv |
@@ -722,7 +724,8 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) | |||
722 | EXPORT_SYMBOL(svc_set_num_threads); | 724 | EXPORT_SYMBOL(svc_set_num_threads); |
723 | 725 | ||
724 | /* | 726 | /* |
725 | * Called from a server thread as it's exiting. Caller must hold BKL. | 727 | * Called from a server thread as it's exiting. Caller must hold the BKL or |
728 | * the "service mutex", whichever is appropriate for the service. | ||
726 | */ | 729 | */ |
727 | void | 730 | void |
728 | svc_exit_thread(struct svc_rqst *rqstp) | 731 | svc_exit_thread(struct svc_rqst *rqstp) |