nfsd4: more precise nfsd4_max_reply

It will turn out to be useful to have a more accurate estimate of reply
size; so, piggyback on the existing op reply-size estimators.

Also move nfsd4_max_reply to nfs4proc.c to get easier access to struct
nfsd4_operation and friends.  (Thanks to Christoph Hellwig for pointing
out that simplification.)

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
J. Bruce Fields 2014-03-11 15:39:13 -04:00
parent 8c7424cff6
commit 4f0cefbf38
3 changed files with 17 additions and 31 deletions

View file

@ -1854,6 +1854,18 @@ static struct nfsd4_operation nfsd4_ops[] = {
}, },
}; };
int nfsd4_max_reply(struct svc_rqst *rqstp, struct nfsd4_op *op)
{
struct nfsd4_operation *opdesc;
nfsd4op_rsize estimator;
if (op->opnum == OP_ILLEGAL)
return op_encode_hdr_size * sizeof(__be32);
opdesc = OPDESC(op);
estimator = opdesc->op_rsize_bop;
return estimator ? estimator(rqstp, op) : PAGE_SIZE;
}
void warn_on_nonidempotent_op(struct nfsd4_op *op) void warn_on_nonidempotent_op(struct nfsd4_op *op)
{ {
if (OPDESC(op)->op_flags & OP_MODIFIES_SOMETHING) { if (OPDESC(op)->op_flags & OP_MODIFIES_SOMETHING) {

View file

@ -1605,40 +1605,13 @@ nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op)
return true; return true;
} }
/*
* Return a rough estimate of the maximum possible reply size. Note the
* estimate includes rpc headers so is meant to be passed to
* svc_reserve, not svc_reserve_auth.
*
* Also note the current compound encoding permits only one operation to
* use pages beyond the first one, so the maximum possible length is the
* maximum over these values, not the sum.
*/
static int nfsd4_max_reply(u32 opnum)
{
switch (opnum) {
case OP_READLINK:
case OP_READDIR:
/*
* Both of these ops take a single page for data and put
* the head and tail in another page:
*/
return 2 * PAGE_SIZE;
case OP_GETATTR:
case OP_READ:
return INT_MAX;
default:
return PAGE_SIZE;
}
}
static __be32 static __be32
nfsd4_decode_compound(struct nfsd4_compoundargs *argp) nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
{ {
DECODE_HEAD; DECODE_HEAD;
struct nfsd4_op *op; struct nfsd4_op *op;
bool cachethis = false; bool cachethis = false;
int max_reply = PAGE_SIZE; int max_reply = 2 * RPC_MAX_AUTH_SIZE + 8; /* opcnt, status */
int i; int i;
READ_BUF(4); READ_BUF(4);
@ -1647,6 +1620,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
SAVEMEM(argp->tag, argp->taglen); SAVEMEM(argp->tag, argp->taglen);
READ32(argp->minorversion); READ32(argp->minorversion);
READ32(argp->opcnt); READ32(argp->opcnt);
max_reply += 4 + (XDR_QUADLEN(argp->taglen) << 2);
if (argp->taglen > NFSD4_MAX_TAGLEN) if (argp->taglen > NFSD4_MAX_TAGLEN)
goto xdr_error; goto xdr_error;
@ -1684,7 +1658,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
*/ */
cachethis |= nfsd4_cache_this_op(op); cachethis |= nfsd4_cache_this_op(op);
max_reply = max(max_reply, nfsd4_max_reply(op->opnum)); max_reply += nfsd4_max_reply(argp->rqstp, op);
if (op->status) { if (op->status) {
argp->opcnt = i+1; argp->opcnt = i+1;
@ -1694,8 +1668,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
/* Sessions make the DRC unnecessary: */ /* Sessions make the DRC unnecessary: */
if (argp->minorversion) if (argp->minorversion)
cachethis = false; cachethis = false;
if (max_reply != INT_MAX) svc_reserve(argp->rqstp, max_reply);
svc_reserve(argp->rqstp, max_reply);
argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
DECODE_TAIL; DECODE_TAIL;

View file

@ -536,6 +536,7 @@ static inline bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
return argp->opcnt == resp->opcnt; return argp->opcnt == resp->opcnt;
} }
int nfsd4_max_reply(struct svc_rqst *rqstp, struct nfsd4_op *op);
void warn_on_nonidempotent_op(struct nfsd4_op *op); void warn_on_nonidempotent_op(struct nfsd4_op *op);
#define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs)