diff options
| author | Andy Adamson <andros@netapp.com> | 2009-04-03 01:28:48 -0400 |
|---|---|---|
| committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-04-03 20:41:20 -0400 |
| commit | 496c262cf01106a546ffb7df6fea84b8b881ee19 (patch) | |
| tree | c1b609cd82d7f64a14eedfc308ce21bdf5b05431 | |
| parent | 6668958fac1d05f55420de702f3678d46c1e93a5 (diff) | |
nfsd41: check encode size for sessions maxresponse cached
Calculate the space the compound response has taken after encoding the current
operation.
pad: add on 8 bytes for the next operation's op_code and status so that
there is room to cache a failure on the next operation.
Compare this length to the session se_fmaxresp_cached and return
nfserr_rep_too_big_to_cache if the length is too large.
Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so
will be at least a page and will therefore hold the xdr_buf head.
Signed-off-by: Andy Adamson <andros@netapp.com>
[nfsd41: non-page DRC for solo sequence responses]
[fixed nfsd4_check_drc_limit cosmetics]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfsd41: use cstate session in nfsd4_check_drc_limit]
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
| -rw-r--r-- | fs/nfsd/nfs4xdr.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index dd81ac1a1c6c..7fdee828f44e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
| @@ -3078,6 +3078,54 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
| 3078 | [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop, | 3078 | [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop, |
| 3079 | }; | 3079 | }; |
| 3080 | 3080 | ||
| 3081 | /* | ||
| 3082 | * Calculate the total amount of memory that the compound response has taken | ||
| 3083 | * after encoding the current operation. | ||
| 3084 | * | ||
| 3085 | * pad: add on 8 bytes for the next operation's op_code and status so that | ||
| 3086 | * there is room to cache a failure on the next operation. | ||
| 3087 | * | ||
| 3088 | * Compare this length to the session se_fmaxresp_cached. | ||
| 3089 | * | ||
| 3090 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so | ||
| 3091 | * will be at least a page and will therefore hold the xdr_buf head. | ||
| 3092 | */ | ||
| 3093 | static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) | ||
| 3094 | { | ||
| 3095 | int status = 0; | ||
| 3096 | struct xdr_buf *xb = &resp->rqstp->rq_res; | ||
| 3097 | struct nfsd4_compoundargs *args = resp->rqstp->rq_argp; | ||
| 3098 | struct nfsd4_session *session = NULL; | ||
| 3099 | struct nfsd4_slot *slot = resp->cstate.slot; | ||
| 3100 | u32 length, tlen = 0, pad = 8; | ||
| 3101 | |||
| 3102 | if (!nfsd4_has_session(&resp->cstate)) | ||
| 3103 | return status; | ||
| 3104 | |||
| 3105 | session = resp->cstate.session; | ||
| 3106 | if (session == NULL || slot->sl_cache_entry.ce_cachethis == 0) | ||
| 3107 | return status; | ||
| 3108 | |||
| 3109 | if (resp->opcnt >= args->opcnt) | ||
| 3110 | pad = 0; /* this is the last operation */ | ||
| 3111 | |||
| 3112 | if (xb->page_len == 0) { | ||
| 3113 | length = (char *)resp->p - (char *)xb->head[0].iov_base + pad; | ||
| 3114 | } else { | ||
| 3115 | if (xb->tail[0].iov_base && xb->tail[0].iov_len > 0) | ||
| 3116 | tlen = (char *)resp->p - (char *)xb->tail[0].iov_base; | ||
| 3117 | |||
| 3118 | length = xb->head[0].iov_len + xb->page_len + tlen + pad; | ||
| 3119 | } | ||
| 3120 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, | ||
| 3121 | length, xb->page_len, tlen, pad); | ||
| 3122 | |||
| 3123 | if (length <= session->se_fmaxresp_cached) | ||
| 3124 | return status; | ||
| 3125 | else | ||
| 3126 | return nfserr_rep_too_big_to_cache; | ||
| 3127 | } | ||
| 3128 | |||
| 3081 | void | 3129 | void |
| 3082 | nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | 3130 | nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) |
| 3083 | { | 3131 | { |
| @@ -3094,6 +3142,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | |||
| 3094 | BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) || | 3142 | BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) || |
| 3095 | !nfsd4_enc_ops[op->opnum]); | 3143 | !nfsd4_enc_ops[op->opnum]); |
| 3096 | op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); | 3144 | op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); |
| 3145 | /* nfsd4_check_drc_limit guarantees enough room for error status */ | ||
| 3146 | if (!op->status && nfsd4_check_drc_limit(resp)) | ||
| 3147 | op->status = nfserr_rep_too_big_to_cache; | ||
| 3097 | status: | 3148 | status: |
| 3098 | /* | 3149 | /* |
| 3099 | * Note: We write the status directly, instead of using WRITE32(), | 3150 | * Note: We write the status directly, instead of using WRITE32(), |
