aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Banks <gnb@melbourne.sgi.com>2006-10-02 05:18:02 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-02 10:57:20 -0400
commiteed2965af1bae30f746e936d80ad4fabb9e208c8 (patch)
treebcb8d2f435f612f6b0d3cc6eac8b39e8dd22f45b
parentbfd241600a3b0db4fe43c859f1460d0a958d924a (diff)
[PATCH] knfsd: allow admin to set nthreads per node
Add /proc/fs/nfsd/pool_threads which allows the sysadmin (or a userspace daemon) to read and change the number of nfsd threads in each pool. The format is a list of space-separated integers, one per pool. Signed-off-by: Greg Banks <gnb@melbourne.sgi.com> Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/nfsd/nfsctl.c70
-rw-r--r--fs/nfsd/nfssvc.c74
2 files changed, 144 insertions, 0 deletions
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 36e8e135d5a6..5c6a477c20ec 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -54,6 +54,7 @@ enum {
54 NFSD_List, 54 NFSD_List,
55 NFSD_Fh, 55 NFSD_Fh,
56 NFSD_Threads, 56 NFSD_Threads,
57 NFSD_Pool_Threads,
57 NFSD_Versions, 58 NFSD_Versions,
58 NFSD_Ports, 59 NFSD_Ports,
59 /* 60 /*
@@ -78,6 +79,7 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size);
78static ssize_t write_getfs(struct file *file, char *buf, size_t size); 79static ssize_t write_getfs(struct file *file, char *buf, size_t size);
79static ssize_t write_filehandle(struct file *file, char *buf, size_t size); 80static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
80static ssize_t write_threads(struct file *file, char *buf, size_t size); 81static ssize_t write_threads(struct file *file, char *buf, size_t size);
82static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
81static ssize_t write_versions(struct file *file, char *buf, size_t size); 83static ssize_t write_versions(struct file *file, char *buf, size_t size);
82static ssize_t write_ports(struct file *file, char *buf, size_t size); 84static ssize_t write_ports(struct file *file, char *buf, size_t size);
83#ifdef CONFIG_NFSD_V4 85#ifdef CONFIG_NFSD_V4
@@ -95,6 +97,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
95 [NFSD_Getfs] = write_getfs, 97 [NFSD_Getfs] = write_getfs,
96 [NFSD_Fh] = write_filehandle, 98 [NFSD_Fh] = write_filehandle,
97 [NFSD_Threads] = write_threads, 99 [NFSD_Threads] = write_threads,
100 [NFSD_Pool_Threads] = write_pool_threads,
98 [NFSD_Versions] = write_versions, 101 [NFSD_Versions] = write_versions,
99 [NFSD_Ports] = write_ports, 102 [NFSD_Ports] = write_ports,
100#ifdef CONFIG_NFSD_V4 103#ifdef CONFIG_NFSD_V4
@@ -363,6 +366,72 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
363 return strlen(buf); 366 return strlen(buf);
364} 367}
365 368
369extern int nfsd_nrpools(void);
370extern int nfsd_get_nrthreads(int n, int *);
371extern int nfsd_set_nrthreads(int n, int *);
372
373static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
374{
375 /* if size > 0, look for an array of number of threads per node
376 * and apply them then write out number of threads per node as reply
377 */
378 char *mesg = buf;
379 int i;
380 int rv;
381 int len;
382 int npools = nfsd_nrpools();
383 int *nthreads;
384
385 if (npools == 0) {
386 /*
387 * NFS is shut down. The admin can start it by
388 * writing to the threads file but NOT the pool_threads
389 * file, sorry. Report zero threads.
390 */
391 strcpy(buf, "0\n");
392 return strlen(buf);
393 }
394
395 nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
396 if (nthreads == NULL)
397 return -ENOMEM;
398
399 if (size > 0) {
400 for (i = 0; i < npools; i++) {
401 rv = get_int(&mesg, &nthreads[i]);
402 if (rv == -ENOENT)
403 break; /* fewer numbers than pools */
404 if (rv)
405 goto out_free; /* syntax error */
406 rv = -EINVAL;
407 if (nthreads[i] < 0)
408 goto out_free;
409 }
410 rv = nfsd_set_nrthreads(i, nthreads);
411 if (rv)
412 goto out_free;
413 }
414
415 rv = nfsd_get_nrthreads(npools, nthreads);
416 if (rv)
417 goto out_free;
418
419 mesg = buf;
420 size = SIMPLE_TRANSACTION_LIMIT;
421 for (i = 0; i < npools && size > 0; i++) {
422 snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
423 len = strlen(mesg);
424 size -= len;
425 mesg += len;
426 }
427
428 return (mesg-buf);
429
430out_free:
431 kfree(nthreads);
432 return rv;
433}
434
366static ssize_t write_versions(struct file *file, char *buf, size_t size) 435static ssize_t write_versions(struct file *file, char *buf, size_t size)
367{ 436{
368 /* 437 /*
@@ -544,6 +613,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
544 [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, 613 [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
545 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, 614 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
546 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, 615 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
616 [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
547 [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, 617 [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
548 [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, 618 [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
549#ifdef CONFIG_NFSD_V4 619#ifdef CONFIG_NFSD_V4
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 0029cb290f18..19443056ec30 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -238,6 +238,80 @@ static int nfsd_init_socks(int port)
238 return 0; 238 return 0;
239} 239}
240 240
241int nfsd_nrpools(void)
242{
243 if (nfsd_serv == NULL)
244 return 0;
245 else
246 return nfsd_serv->sv_nrpools;
247}
248
249int nfsd_get_nrthreads(int n, int *nthreads)
250{
251 int i = 0;
252
253 if (nfsd_serv != NULL) {
254 for (i = 0; i < nfsd_serv->sv_nrpools && i < n; i++)
255 nthreads[i] = nfsd_serv->sv_pools[i].sp_nrthreads;
256 }
257
258 return 0;
259}
260
261int nfsd_set_nrthreads(int n, int *nthreads)
262{
263 int i = 0;
264 int tot = 0;
265 int err = 0;
266
267 if (nfsd_serv == NULL || n <= 0)
268 return 0;
269
270 if (n > nfsd_serv->sv_nrpools)
271 n = nfsd_serv->sv_nrpools;
272
273 /* enforce a global maximum number of threads */
274 tot = 0;
275 for (i = 0; i < n; i++) {
276 if (nthreads[i] > NFSD_MAXSERVS)
277 nthreads[i] = NFSD_MAXSERVS;
278 tot += nthreads[i];
279 }
280 if (tot > NFSD_MAXSERVS) {
281 /* total too large: scale down requested numbers */
282 for (i = 0; i < n && tot > 0; i++) {
283 int new = nthreads[i] * NFSD_MAXSERVS / tot;
284 tot -= (nthreads[i] - new);
285 nthreads[i] = new;
286 }
287 for (i = 0; i < n && tot > 0; i++) {
288 nthreads[i]--;
289 tot--;
290 }
291 }
292
293 /*
294 * There must always be a thread in pool 0; the admin
295 * can't shut down NFS completely using pool_threads.
296 */
297 if (nthreads[0] == 0)
298 nthreads[0] = 1;
299
300 /* apply the new numbers */
301 lock_kernel();
302 svc_get(nfsd_serv);
303 for (i = 0; i < n; i++) {
304 err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i],
305 nthreads[i]);
306 if (err)
307 break;
308 }
309 svc_destroy(nfsd_serv);
310 unlock_kernel();
311
312 return err;
313}
314
241int 315int
242nfsd_svc(unsigned short port, int nrservs) 316nfsd_svc(unsigned short port, int nrservs)
243{ 317{