diff options
author | Andy Adamson <andros@netapp.com> | 2009-08-28 08:45:01 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-09-01 22:24:05 -0400 |
commit | a649637c73a36174287a403cdda7607177d64523 (patch) | |
tree | 8aec8e30b2f4cceaee9fa5ddaa88e694ea3e09dd /fs/nfsd | |
parent | a06b1261bdb580b35967d0e055d1ab131b332254 (diff) |
nfsd41: bound forechannel drc size by memory usage
By using the requested ca_maxresponsesize_cached * ca_maxresponses to bound
a forechannel drc request size, clients can tailor a session to usage.
For example, an I/O session (READ/WRITE only) can have a much smaller
ca_maxresponsesize_cached (for only WRITE compound responses) and a lot larger
ca_maxresponses to service a large in-flight data window.
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4state.c | 66 |
1 files changed, 48 insertions, 18 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 | ||