aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2009-06-15 21:03:07 -0400
committerJ. Bruce Fields <bfields@citi.umich.edu>2009-06-18 12:40:31 -0400
commit82e12fe9244ff653f703722a8937b595e10e71f4 (patch)
treeaacafeb07d90c9453c31cc6771324e7960c52477
parent5d77ddfbcb062f2617ea79d7a371b4bc78f28417 (diff)
nfsd: don't take nfsd_mutex twice when setting number of threads.
Currently when we write a number to 'threads' in nfsdfs, we take the nfsd_mutex, update the number of threads, then take the mutex again to read the number of threads. Mostly this isn't a big deal. However if we are write '0', and portmap happens to be dead, then we can get unpredictable behaviour. If the nfsd threads all got killed quickly and the last thread is waiting for portmap to respond, then the second time we take the mutex we will block waiting for the last thread. However if the nfsd threads didn't die quite that fast, then there will be no contention when we try to take the mutex again. Unpredictability isn't fun, and waiting for the last thread to exit is pointless, so avoid taking the lock twice. To achieve this, get nfsd_svc return a non-negative number of active threads when not returning a negative error. Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r--fs/nfsd/nfsctl.c14
-rw-r--r--fs/nfsd/nfssvc.c6
2 files changed, 15 insertions, 5 deletions
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 877e713a0fd6..1250fb978ac1 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -207,10 +207,14 @@ static struct file_operations pool_stats_operations = {
207static ssize_t write_svc(struct file *file, char *buf, size_t size) 207static ssize_t write_svc(struct file *file, char *buf, size_t size)
208{ 208{
209 struct nfsctl_svc *data; 209 struct nfsctl_svc *data;
210 int err;
210 if (size < sizeof(*data)) 211 if (size < sizeof(*data))
211 return -EINVAL; 212 return -EINVAL;
212 data = (struct nfsctl_svc*) buf; 213 data = (struct nfsctl_svc*) buf;
213 return nfsd_svc(data->svc_port, data->svc_nthreads); 214 err = nfsd_svc(data->svc_port, data->svc_nthreads);
215 if (err < 0)
216 return err;
217 return 0;
214} 218}
215 219
216/** 220/**
@@ -692,12 +696,12 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
692 if (newthreads < 0) 696 if (newthreads < 0)
693 return -EINVAL; 697 return -EINVAL;
694 rv = nfsd_svc(NFS_PORT, newthreads); 698 rv = nfsd_svc(NFS_PORT, newthreads);
695 if (rv) 699 if (rv < 0)
696 return rv; 700 return rv;
697 } 701 } else
702 rv = nfsd_nrthreads();
698 703
699 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", 704 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
700 nfsd_nrthreads());
701} 705}
702 706
703/** 707/**
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index cbba4a935786..209eaa0885d1 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -413,6 +413,12 @@ nfsd_svc(unsigned short port, int nrservs)
413 goto failure; 413 goto failure;
414 414
415 error = svc_set_num_threads(nfsd_serv, NULL, nrservs); 415 error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
416 if (error == 0)
417 /* We are holding a reference to nfsd_serv which
418 * we don't want to count in the return value,
419 * so subtract 1
420 */
421 error = nfsd_serv->sv_nrthreads - 1;
416 failure: 422 failure:
417 svc_destroy(nfsd_serv); /* Release server */ 423 svc_destroy(nfsd_serv); /* Release server */
418 out: 424 out: