Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f0cefbf authored by J. Bruce Fields's avatar J. Bruce Fields
Browse files

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: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 8c7424cf
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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)
{
	if (OPDESC(op)->op_flags & OP_MODIFIES_SOMETHING) {
+4 −31
Original line number Diff line number Diff line
@@ -1605,40 +1605,13 @@ nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op)
	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
nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
{
	DECODE_HEAD;
	struct nfsd4_op *op;
	bool cachethis = false;
	int max_reply = PAGE_SIZE;
	int max_reply = 2 * RPC_MAX_AUTH_SIZE + 8; /* opcnt, status */
	int i;

	READ_BUF(4);
@@ -1647,6 +1620,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
	SAVEMEM(argp->tag, argp->taglen);
	READ32(argp->minorversion);
	READ32(argp->opcnt);
	max_reply += 4 + (XDR_QUADLEN(argp->taglen) << 2);

	if (argp->taglen > NFSD4_MAX_TAGLEN)
		goto xdr_error;
@@ -1684,7 +1658,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
		 */
		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) {
			argp->opcnt = i+1;
@@ -1694,7 +1668,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
	/* Sessions make the DRC unnecessary: */
	if (argp->minorversion)
		cachethis = false;
	if (max_reply != INT_MAX)
	svc_reserve(argp->rqstp, max_reply);
	argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;

+1 −0
Original line number Diff line number Diff line
@@ -536,6 +536,7 @@ static inline bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
	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);

#define NFS4_SVC_XDRSIZE		sizeof(struct nfsd4_compoundargs)