aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2014-03-11 15:39:13 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-05-30 17:31:57 -0400
commit4f0cefbf389c28b0a2be34960797adb0c84ee43d (patch)
tree8ef1923fa15d4e2372e73e48df203facc4085c7c /fs/nfsd
parent8c7424cff6bd33459945646cfcbf6dc6c899ab24 (diff)
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>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4proc.c12
-rw-r--r--fs/nfsd/nfs4xdr.c35
-rw-r--r--fs/nfsd/xdr4.h1
3 files changed, 17 insertions, 31 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 20aad5a3005f..59c319528cf9 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1854,6 +1854,18 @@ static struct nfsd4_operation nfsd4_ops[] = {
1854 }, 1854 },
1855}; 1855};
1856 1856
1857int nfsd4_max_reply(struct svc_rqst *rqstp, struct nfsd4_op *op)
1858{
1859 struct nfsd4_operation *opdesc;
1860 nfsd4op_rsize estimator;
1861
1862 if (op->opnum == OP_ILLEGAL)
1863 return op_encode_hdr_size * sizeof(__be32);
1864 opdesc = OPDESC(op);
1865 estimator = opdesc->op_rsize_bop;
1866 return estimator ? estimator(rqstp, op) : PAGE_SIZE;
1867}
1868
1857void warn_on_nonidempotent_op(struct nfsd4_op *op) 1869void warn_on_nonidempotent_op(struct nfsd4_op *op)
1858{ 1870{
1859 if (OPDESC(op)->op_flags & OP_MODIFIES_SOMETHING) { 1871 if (OPDESC(op)->op_flags & OP_MODIFIES_SOMETHING) {
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 2f0ea20edb23..8b3d24de9cac 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1605,40 +1605,13 @@ nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op)
1605 return true; 1605 return true;
1606} 1606}
1607 1607
1608/*
1609 * Return a rough estimate of the maximum possible reply size. Note the
1610 * estimate includes rpc headers so is meant to be passed to
1611 * svc_reserve, not svc_reserve_auth.
1612 *
1613 * Also note the current compound encoding permits only one operation to
1614 * use pages beyond the first one, so the maximum possible length is the
1615 * maximum over these values, not the sum.
1616 */
1617static int nfsd4_max_reply(u32 opnum)
1618{
1619 switch (opnum) {
1620 case OP_READLINK:
1621 case OP_READDIR:
1622 /*
1623 * Both of these ops take a single page for data and put
1624 * the head and tail in another page:
1625 */
1626 return 2 * PAGE_SIZE;
1627 case OP_GETATTR:
1628 case OP_READ:
1629 return INT_MAX;
1630 default:
1631 return PAGE_SIZE;
1632 }
1633}
1634
1635static __be32 1608static __be32
1636nfsd4_decode_compound(struct nfsd4_compoundargs *argp) 1609nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1637{ 1610{
1638 DECODE_HEAD; 1611 DECODE_HEAD;
1639 struct nfsd4_op *op; 1612 struct nfsd4_op *op;
1640 bool cachethis = false; 1613 bool cachethis = false;
1641 int max_reply = PAGE_SIZE; 1614 int max_reply = 2 * RPC_MAX_AUTH_SIZE + 8; /* opcnt, status */
1642 int i; 1615 int i;
1643 1616
1644 READ_BUF(4); 1617 READ_BUF(4);
@@ -1647,6 +1620,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1647 SAVEMEM(argp->tag, argp->taglen); 1620 SAVEMEM(argp->tag, argp->taglen);
1648 READ32(argp->minorversion); 1621 READ32(argp->minorversion);
1649 READ32(argp->opcnt); 1622 READ32(argp->opcnt);
1623 max_reply += 4 + (XDR_QUADLEN(argp->taglen) << 2);
1650 1624
1651 if (argp->taglen > NFSD4_MAX_TAGLEN) 1625 if (argp->taglen > NFSD4_MAX_TAGLEN)
1652 goto xdr_error; 1626 goto xdr_error;
@@ -1684,7 +1658,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1684 */ 1658 */
1685 cachethis |= nfsd4_cache_this_op(op); 1659 cachethis |= nfsd4_cache_this_op(op);
1686 1660
1687 max_reply = max(max_reply, nfsd4_max_reply(op->opnum)); 1661 max_reply += nfsd4_max_reply(argp->rqstp, op);
1688 1662
1689 if (op->status) { 1663 if (op->status) {
1690 argp->opcnt = i+1; 1664 argp->opcnt = i+1;
@@ -1694,8 +1668,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1694 /* Sessions make the DRC unnecessary: */ 1668 /* Sessions make the DRC unnecessary: */
1695 if (argp->minorversion) 1669 if (argp->minorversion)
1696 cachethis = false; 1670 cachethis = false;
1697 if (max_reply != INT_MAX) 1671 svc_reserve(argp->rqstp, max_reply);
1698 svc_reserve(argp->rqstp, max_reply);
1699 argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; 1672 argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
1700 1673
1701 DECODE_TAIL; 1674 DECODE_TAIL;
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index ee9ffdc8a0cb..41e522993d94 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -536,6 +536,7 @@ static inline bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
536 return argp->opcnt == resp->opcnt; 536 return argp->opcnt == resp->opcnt;
537} 537}
538 538
539int nfsd4_max_reply(struct svc_rqst *rqstp, struct nfsd4_op *op);
539void warn_on_nonidempotent_op(struct nfsd4_op *op); 540void warn_on_nonidempotent_op(struct nfsd4_op *op);
540 541
541#define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) 542#define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs)