diff options
-rw-r--r-- | fs/nfsd/nfs4state.c | 66 | ||||
-rw-r--r-- | include/linux/nfsd/state.h | 8 |
2 files changed, 54 insertions, 20 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b44a2cfde6f1..02b3ddd0bee3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -414,34 +414,64 @@ gen_sessionid(struct nfsd4_session *ses) | |||
414 | } | 414 | } |
415 | 415 | ||
416 | /* | 416 | /* |
417 | * Give the client the number of slots it requests bound by | 417 | * The protocol defines ca_maxresponssize_cached to include the size of |
418 | * NFSD_MAX_SLOTS_PER_SESSION and by nfsd_drc_max_mem. | 418 | * the rpc header, but all we need to cache is the data starting after |
419 | * the end of the initial SEQUENCE operation--the rest we regenerate | ||
420 | * each time. Therefore we can advertise a ca_maxresponssize_cached | ||
421 | * value that is the number of bytes in our cache plus a few additional | ||
422 | * bytes. In order to stay on the safe side, and not promise more than | ||
423 | * we can cache, those additional bytes must be the minimum possible: 24 | ||
424 | * bytes of rpc header (xid through accept state, with AUTH_NULL | ||
425 | * verifier), 12 for the compound header (with zero-length tag), and 44 | ||
426 | * for the SEQUENCE op response: | ||
427 | */ | ||
428 | #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) | ||
429 | |||
430 | /* | ||
431 | * Give the client the number of ca_maxresponsesize_cached slots it | ||
432 | * requests, of size bounded by NFSD_SLOT_CACHE_SIZE, | ||
433 | * NFSD_MAX_MEM_PER_SESSION, and nfsd_drc_max_mem. Do not allow more | ||
434 | * than NFSD_MAX_SLOTS_PER_SESSION. | ||
419 | * | 435 | * |
420 | * If we run out of reserved DRC memory we should (up to a point) re-negotiate | 436 | * If we run out of reserved DRC memory we should (up to a point) |
421 | * active sessions and reduce their slot usage to make rooom for new | 437 | * re-negotiate active sessions and reduce their slot usage to make |
422 | * connections. For now we just fail the create session. | 438 | * rooom for new connections. For now we just fail the create session. |
423 | */ | 439 | */ |
424 | static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan) | 440 | static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan) |
425 | { | 441 | { |
426 | int mem; | 442 | int mem, size = fchan->maxresp_cached; |
427 | 443 | ||
428 | if (fchan->maxreqs < 1) | 444 | if (fchan->maxreqs < 1) |
429 | return nfserr_inval; | 445 | return nfserr_inval; |
430 | else if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
431 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
432 | 446 | ||
433 | mem = fchan->maxreqs * NFSD_SLOT_CACHE_SIZE; | 447 | if (size < NFSD_MIN_HDR_SEQ_SZ) |
448 | size = NFSD_MIN_HDR_SEQ_SZ; | ||
449 | size -= NFSD_MIN_HDR_SEQ_SZ; | ||
450 | if (size > NFSD_SLOT_CACHE_SIZE) | ||
451 | size = NFSD_SLOT_CACHE_SIZE; | ||
452 | |||
453 | /* bound the maxreqs by NFSD_MAX_MEM_PER_SESSION */ | ||
454 | mem = fchan->maxreqs * size; | ||
455 | if (mem > NFSD_MAX_MEM_PER_SESSION) { | ||
456 | fchan->maxreqs = NFSD_MAX_MEM_PER_SESSION / size; | ||
457 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
458 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
459 | mem = fchan->maxreqs * size; | ||
460 | } | ||
434 | 461 | ||
435 | spin_lock(&nfsd_drc_lock); | 462 | spin_lock(&nfsd_drc_lock); |
436 | if (mem + nfsd_drc_mem_used > nfsd_drc_max_mem) | 463 | /* bound the total session drc memory ussage */ |
437 | mem = ((nfsd_drc_max_mem - nfsd_drc_mem_used) / | 464 | if (mem + nfsd_drc_mem_used > nfsd_drc_max_mem) { |
438 | NFSD_SLOT_CACHE_SIZE) * NFSD_SLOT_CACHE_SIZE; | 465 | fchan->maxreqs = (nfsd_drc_max_mem - nfsd_drc_mem_used) / size; |
466 | mem = fchan->maxreqs * size; | ||
467 | } | ||
439 | nfsd_drc_mem_used += mem; | 468 | nfsd_drc_mem_used += mem; |
440 | spin_unlock(&nfsd_drc_lock); | 469 | spin_unlock(&nfsd_drc_lock); |
441 | 470 | ||
442 | fchan->maxreqs = mem / NFSD_SLOT_CACHE_SIZE; | ||
443 | if (fchan->maxreqs == 0) | 471 | if (fchan->maxreqs == 0) |
444 | return nfserr_resource; | 472 | return nfserr_resource; |
473 | |||
474 | fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ; | ||
445 | return 0; | 475 | return 0; |
446 | } | 476 | } |
447 | 477 | ||
@@ -466,9 +496,6 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp, | |||
466 | fchan->maxresp_sz = maxcount; | 496 | fchan->maxresp_sz = maxcount; |
467 | session_fchan->maxresp_sz = fchan->maxresp_sz; | 497 | session_fchan->maxresp_sz = fchan->maxresp_sz; |
468 | 498 | ||
469 | session_fchan->maxresp_cached = NFSD_SLOT_CACHE_SIZE; | ||
470 | fchan->maxresp_cached = session_fchan->maxresp_cached; | ||
471 | |||
472 | /* Use the client's maxops if possible */ | 499 | /* Use the client's maxops if possible */ |
473 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) | 500 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) |
474 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; | 501 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; |
@@ -478,9 +505,12 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp, | |||
478 | * recover pages from existing sessions. For now fail session | 505 | * recover pages from existing sessions. For now fail session |
479 | * creation. | 506 | * creation. |
480 | */ | 507 | */ |
481 | status = set_forechannel_maxreqs(fchan); | 508 | status = set_forechannel_drc_size(fchan); |
482 | 509 | ||
510 | session_fchan->maxresp_cached = fchan->maxresp_cached; | ||
483 | session_fchan->maxreqs = fchan->maxreqs; | 511 | session_fchan->maxreqs = fchan->maxreqs; |
512 | |||
513 | dprintk("%s status %d\n", __func__, status); | ||
484 | return status; | 514 | return status; |
485 | } | 515 | } |
486 | 516 | ||
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index fb0c404c7c5c..ff0b771efde6 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h | |||
@@ -92,13 +92,17 @@ struct nfs4_cb_conn { | |||
92 | struct rpc_cred * cb_cred; | 92 | struct rpc_cred * cb_cred; |
93 | }; | 93 | }; |
94 | 94 | ||
95 | /* Maximum number of slots per session. 128 is useful for long haul TCP */ | 95 | /* Maximum number of slots per session. 160 is useful for long haul TCP */ |
96 | #define NFSD_MAX_SLOTS_PER_SESSION 128 | 96 | #define NFSD_MAX_SLOTS_PER_SESSION 160 |
97 | /* Maximum number of pages per slot cache entry */ | 97 | /* Maximum number of pages per slot cache entry */ |
98 | #define NFSD_PAGES_PER_SLOT 1 | 98 | #define NFSD_PAGES_PER_SLOT 1 |
99 | #define NFSD_SLOT_CACHE_SIZE PAGE_SIZE | 99 | #define NFSD_SLOT_CACHE_SIZE PAGE_SIZE |
100 | /* Maximum number of operations per session compound */ | 100 | /* Maximum number of operations per session compound */ |
101 | #define NFSD_MAX_OPS_PER_COMPOUND 16 | 101 | #define NFSD_MAX_OPS_PER_COMPOUND 16 |
102 | /* Maximum number of NFSD_SLOT_CACHE_SIZE slots per session */ | ||
103 | #define NFSD_CACHE_SIZE_SLOTS_PER_SESSION 32 | ||
104 | #define NFSD_MAX_MEM_PER_SESSION \ | ||
105 | (NFSD_CACHE_SIZE_SLOTS_PER_SESSION * NFSD_SLOT_CACHE_SIZE) | ||
102 | 106 | ||
103 | struct nfsd4_cache_entry { | 107 | struct nfsd4_cache_entry { |
104 | __be32 ce_status; | 108 | __be32 ce_status; |