Commit 58e7b33a authored by Mi Jinlong's avatar Mi Jinlong Committed by J. Bruce Fields

nfsd41: try to check reply size before operation

For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.

v3: using new method as Bruce said,

 "we could handle operations in two different ways:

	- For operations that actually change something (write, rename,
	  open, close, ...), do it the way we're doing it now: be
	  very careful to estimate the size of the response before even
	  processing the operation.
	- For operations that don't change anything (read, getattr, ...)
	  just go ahead and do the operation.  If you realize after the
	  fact that the response is too large, then return the error at
	  that point.

  So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING.  And for
  operations with OP_MODIFIES_SOMETHING set, we'd do the first thing.  For
  operations without it set, we'd do the second."
Signed-off-by: default avatarMi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 038c0159
This diff is collapsed.
...@@ -3387,34 +3387,29 @@ static nfsd4_enc nfsd4_enc_ops[] = { ...@@ -3387,34 +3387,29 @@ static nfsd4_enc nfsd4_enc_ops[] = {
/* /*
* Calculate the total amount of memory that the compound response has taken * Calculate the total amount of memory that the compound response has taken
* after encoding the current operation. * after encoding the current operation with pad.
* *
* pad: add on 8 bytes for the next operation's op_code and status so that * pad: if operation is non-idempotent, pad was calculate by op_rsize_bop()
* there is room to cache a failure on the next operation. * which was specified at nfsd4_operation, else pad is zero.
* *
* Compare this length to the session se_fmaxresp_cached. * Compare this length to the session se_fmaxresp_sz and se_fmaxresp_cached.
* *
* Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so * 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. * will be at least a page and will therefore hold the xdr_buf head.
*/ */
static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) int nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad)
{ {
int status = 0;
struct xdr_buf *xb = &resp->rqstp->rq_res; struct xdr_buf *xb = &resp->rqstp->rq_res;
struct nfsd4_compoundargs *args = resp->rqstp->rq_argp;
struct nfsd4_session *session = NULL; struct nfsd4_session *session = NULL;
struct nfsd4_slot *slot = resp->cstate.slot; struct nfsd4_slot *slot = resp->cstate.slot;
u32 length, tlen = 0, pad = 8; u32 length, tlen = 0;
if (!nfsd4_has_session(&resp->cstate)) if (!nfsd4_has_session(&resp->cstate))
return status; return 0;
session = resp->cstate.session; session = resp->cstate.session;
if (session == NULL || slot->sl_cachethis == 0) if (session == NULL)
return status; return 0;
if (resp->opcnt >= args->opcnt)
pad = 0; /* this is the last operation */
if (xb->page_len == 0) { if (xb->page_len == 0) {
length = (char *)resp->p - (char *)xb->head[0].iov_base + pad; 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,10 +3422,14 @@ static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp)
dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__,
length, xb->page_len, tlen, pad); length, xb->page_len, tlen, pad);
if (length <= session->se_fchannel.maxresp_cached) if (length > session->se_fchannel.maxresp_sz)
return status; return nfserr_rep_too_big;
else
if (slot->sl_cachethis == 1 &&
length > session->se_fchannel.maxresp_cached)
return nfserr_rep_too_big_to_cache; return nfserr_rep_too_big_to_cache;
return 0;
} }
void void
...@@ -3450,8 +3449,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) ...@@ -3450,8 +3449,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
!nfsd4_enc_ops[op->opnum]); !nfsd4_enc_ops[op->opnum]);
op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u);
/* nfsd4_check_drc_limit guarantees enough room for error status */ /* nfsd4_check_drc_limit guarantees enough room for error status */
if (!op->status && nfsd4_check_drc_limit(resp)) if (!op->status)
op->status = nfserr_rep_too_big_to_cache; op->status = nfsd4_check_resp_size(resp, 0);
status: status:
/* /*
* Note: We write the status directly, instead of using WRITE32(), * Note: We write the status directly, instead of using WRITE32(),
......
...@@ -524,6 +524,7 @@ int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *, ...@@ -524,6 +524,7 @@ int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *,
struct nfsd4_compoundargs *); struct nfsd4_compoundargs *);
int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *,
struct nfsd4_compoundres *); struct nfsd4_compoundres *);
int nfsd4_check_resp_size(struct nfsd4_compoundres *, u32);
void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment