diff options
-rw-r--r-- | fs/nfsd/nfsctl.c | 70 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 74 |
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); | |||
78 | static ssize_t write_getfs(struct file *file, char *buf, size_t size); | 79 | static ssize_t write_getfs(struct file *file, char *buf, size_t size); |
79 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); | 80 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); |
80 | static ssize_t write_threads(struct file *file, char *buf, size_t size); | 81 | static ssize_t write_threads(struct file *file, char *buf, size_t size); |
82 | static ssize_t write_pool_threads(struct file *file, char *buf, size_t size); | ||
81 | static ssize_t write_versions(struct file *file, char *buf, size_t size); | 83 | static ssize_t write_versions(struct file *file, char *buf, size_t size); |
82 | static ssize_t write_ports(struct file *file, char *buf, size_t size); | 84 | static 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 | ||
369 | extern int nfsd_nrpools(void); | ||
370 | extern int nfsd_get_nrthreads(int n, int *); | ||
371 | extern int nfsd_set_nrthreads(int n, int *); | ||
372 | |||
373 | static 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 | |||
430 | out_free: | ||
431 | kfree(nthreads); | ||
432 | return rv; | ||
433 | } | ||
434 | |||
366 | static ssize_t write_versions(struct file *file, char *buf, size_t size) | 435 | static 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 | ||
241 | int nfsd_nrpools(void) | ||
242 | { | ||
243 | if (nfsd_serv == NULL) | ||
244 | return 0; | ||
245 | else | ||
246 | return nfsd_serv->sv_nrpools; | ||
247 | } | ||
248 | |||
249 | int 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 | |||
261 | int 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 | |||
241 | int | 315 | int |
242 | nfsd_svc(unsigned short port, int nrservs) | 316 | nfsd_svc(unsigned short port, int nrservs) |
243 | { | 317 | { |