aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Brown <neilb@suse.de>2008-06-10 08:40:35 -0400
committerJ. Bruce Fields <bfields@citi.umich.edu>2008-06-23 13:02:49 -0400
commitbedbdd8bada194a690d2901801bf8451965086b3 (patch)
treedc7ea15dd52370429bd63cd6803d6402cebbd50b
parent0d169ca136357d51a65d686f3c84866a8ba20ae9 (diff)
knfsd: Replace lock_kernel with a mutex for nfsd thread startup/shutdown locking.
This removes the BKL from the RPC service creation codepath. The BKL really isn't adequate for this job since some of this info needs protection across sleeps. Also, add some comments to try and clarify how the locking should work and to make it clear that the BKL isn't necessary as long as there is adequate locking between tasks when touching the svc_serv fields. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r--fs/nfsd/nfsctl.c37
-rw-r--r--fs/nfsd/nfssvc.c45
-rw-r--r--include/linux/nfsd/nfsd.h1
-rw-r--r--net/sunrpc/svc.c15
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
501out_free: 506out_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
569static ssize_t write_ports(struct file *file, char *buf, size_t size) 575static 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
675static 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
676int nfsd_max_blksize; 685int nfsd_max_blksize;
677 686
678static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) 687static 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 @@
53extern struct svc_program nfsd_program; 53extern struct svc_program nfsd_program;
54static void nfsd(struct svc_rqst *rqstp); 54static void nfsd(struct svc_rqst *rqstp);
55struct timeval nfssvc_boot; 55struct timeval nfssvc_boot;
56 struct svc_serv *nfsd_serv;
57static atomic_t nfsd_busy; 56static atomic_t nfsd_busy;
58static unsigned long nfsd_last_call; 57static unsigned long nfsd_last_call;
59static DEFINE_SPINLOCK(nfsd_call_lock); 58static 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 */
74DEFINE_MUTEX(nfsd_mutex);
75struct 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)
62static struct svc_stat nfsd_acl_svcstats; 78static struct svc_stat nfsd_acl_svcstats;
63static struct svc_version * nfsd_acl_version[] = { 79static struct svc_version * nfsd_acl_version[] = {
@@ -190,13 +206,14 @@ void nfsd_reset_versions(void)
190 } 206 }
191} 207}
192 208
209
193int nfsd_create_serv(void) 210int 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
334nfsd_svc(unsigned short port, int nrservs) 351nfsd_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);
54extern struct svc_program nfsd_program; 54extern struct svc_program nfsd_program;
55extern struct svc_version nfsd_version2, nfsd_version3, 55extern struct svc_version nfsd_version2, nfsd_version3,
56 nfsd_version4; 56 nfsd_version4;
57extern struct mutex nfsd_mutex;
57extern struct svc_serv *nfsd_serv; 58extern struct svc_serv *nfsd_serv;
58 59
59extern struct seq_operations nfs_exports_op; 60extern 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,
461EXPORT_SYMBOL(svc_create_pooled); 461EXPORT_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 */
466void 467void
467svc_destroy(struct svc_serv *serv) 468svc_destroy(struct svc_serv *serv)
@@ -578,9 +579,10 @@ out_enomem:
578EXPORT_SYMBOL(svc_prepare_thread); 579EXPORT_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 */
585static int 587static 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)
722EXPORT_SYMBOL(svc_set_num_threads); 724EXPORT_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 */
727void 730void
728svc_exit_thread(struct svc_rqst *rqstp) 731svc_exit_thread(struct svc_rqst *rqstp)