aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)