diff options
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 37 |
1 files changed, 18 insertions, 19 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 5252d6681960..f4116cf16595 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -3387,34 +3387,29 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
3387 | 3387 | ||
3388 | /* | 3388 | /* |
3389 | * Calculate the total amount of memory that the compound response has taken | 3389 | * Calculate the total amount of memory that the compound response has taken |
3390 | * after encoding the current operation. | 3390 | * after encoding the current operation with pad. |
3391 | * | 3391 | * |
3392 | * pad: add on 8 bytes for the next operation's op_code and status so that | 3392 | * pad: if operation is non-idempotent, pad was calculate by op_rsize_bop() |
3393 | * there is room to cache a failure on the next operation. | 3393 | * which was specified at nfsd4_operation, else pad is zero. |
3394 | * | 3394 | * |
3395 | * Compare this length to the session se_fmaxresp_cached. | 3395 | * Compare this length to the session se_fmaxresp_sz and se_fmaxresp_cached. |
3396 | * | 3396 | * |
3397 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so | 3397 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so |
3398 | * will be at least a page and will therefore hold the xdr_buf head. | 3398 | * will be at least a page and will therefore hold the xdr_buf head. |
3399 | */ | 3399 | */ |
3400 | static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) | 3400 | int nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) |
3401 | { | 3401 | { |
3402 | int status = 0; | ||
3403 | struct xdr_buf *xb = &resp->rqstp->rq_res; | 3402 | struct xdr_buf *xb = &resp->rqstp->rq_res; |
3404 | struct nfsd4_compoundargs *args = resp->rqstp->rq_argp; | ||
3405 | struct nfsd4_session *session = NULL; | 3403 | struct nfsd4_session *session = NULL; |
3406 | struct nfsd4_slot *slot = resp->cstate.slot; | 3404 | struct nfsd4_slot *slot = resp->cstate.slot; |
3407 | u32 length, tlen = 0, pad = 8; | 3405 | u32 length, tlen = 0; |
3408 | 3406 | ||
3409 | if (!nfsd4_has_session(&resp->cstate)) | 3407 | if (!nfsd4_has_session(&resp->cstate)) |
3410 | return status; | 3408 | return 0; |
3411 | 3409 | ||
3412 | session = resp->cstate.session; | 3410 | session = resp->cstate.session; |
3413 | if (session == NULL || slot->sl_cachethis == 0) | 3411 | if (session == NULL) |
3414 | return status; | 3412 | return 0; |
3415 | |||
3416 | if (resp->opcnt >= args->opcnt) | ||
3417 | pad = 0; /* this is the last operation */ | ||
3418 | 3413 | ||
3419 | if (xb->page_len == 0) { | 3414 | if (xb->page_len == 0) { |
3420 | length = (char *)resp->p - (char *)xb->head[0].iov_base + pad; | 3415 | length = (char *)resp->p - (char *)xb->head[0].iov_base + pad; |
@@ -3427,10 +3422,14 @@ static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) | |||
3427 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, | 3422 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, |
3428 | length, xb->page_len, tlen, pad); | 3423 | length, xb->page_len, tlen, pad); |
3429 | 3424 | ||
3430 | if (length <= session->se_fchannel.maxresp_cached) | 3425 | if (length > session->se_fchannel.maxresp_sz) |
3431 | return status; | 3426 | return nfserr_rep_too_big; |
3432 | else | 3427 | |
3428 | if (slot->sl_cachethis == 1 && | ||
3429 | length > session->se_fchannel.maxresp_cached) | ||
3433 | return nfserr_rep_too_big_to_cache; | 3430 | return nfserr_rep_too_big_to_cache; |
3431 | |||
3432 | return 0; | ||
3434 | } | 3433 | } |
3435 | 3434 | ||
3436 | void | 3435 | void |
@@ -3450,8 +3449,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | |||
3450 | !nfsd4_enc_ops[op->opnum]); | 3449 | !nfsd4_enc_ops[op->opnum]); |
3451 | op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); | 3450 | op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); |
3452 | /* nfsd4_check_drc_limit guarantees enough room for error status */ | 3451 | /* nfsd4_check_drc_limit guarantees enough room for error status */ |
3453 | if (!op->status && nfsd4_check_drc_limit(resp)) | 3452 | if (!op->status) |
3454 | op->status = nfserr_rep_too_big_to_cache; | 3453 | op->status = nfsd4_check_resp_size(resp, 0); |
3455 | status: | 3454 | status: |
3456 | /* | 3455 | /* |
3457 | * Note: We write the status directly, instead of using WRITE32(), | 3456 | * Note: We write the status directly, instead of using WRITE32(), |