diff options
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index d9d7fa94967f..9d76ee311ddc 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1597,12 +1597,39 @@ nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op) | |||
1597 | return true; | 1597 | return true; |
1598 | } | 1598 | } |
1599 | 1599 | ||
1600 | /* | ||
1601 | * Return a rough estimate of the maximum possible reply size. Note the | ||
1602 | * estimate includes rpc headers so is meant to be passed to | ||
1603 | * svc_reserve, not svc_reserve_auth. | ||
1604 | * | ||
1605 | * Also note the current compound encoding permits only one operation to | ||
1606 | * use pages beyond the first one, so the maximum possible length is the | ||
1607 | * maximum over these values, not the sum. | ||
1608 | */ | ||
1609 | static int nfsd4_max_reply(u32 opnum) | ||
1610 | { | ||
1611 | switch (opnum) { | ||
1612 | case OP_READLINK: | ||
1613 | case OP_READDIR: | ||
1614 | /* | ||
1615 | * Both of these ops take a single page for data and put | ||
1616 | * the head and tail in another page: | ||
1617 | */ | ||
1618 | return 2 * PAGE_SIZE; | ||
1619 | case OP_READ: | ||
1620 | return INT_MAX; | ||
1621 | default: | ||
1622 | return PAGE_SIZE; | ||
1623 | } | ||
1624 | } | ||
1625 | |||
1600 | static __be32 | 1626 | static __be32 |
1601 | nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | 1627 | nfsd4_decode_compound(struct nfsd4_compoundargs *argp) |
1602 | { | 1628 | { |
1603 | DECODE_HEAD; | 1629 | DECODE_HEAD; |
1604 | struct nfsd4_op *op; | 1630 | struct nfsd4_op *op; |
1605 | bool cachethis = false; | 1631 | bool cachethis = false; |
1632 | int max_reply = PAGE_SIZE; | ||
1606 | int i; | 1633 | int i; |
1607 | 1634 | ||
1608 | READ_BUF(4); | 1635 | READ_BUF(4); |
@@ -1652,10 +1679,14 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1652 | * op in the compound wants to be cached: | 1679 | * op in the compound wants to be cached: |
1653 | */ | 1680 | */ |
1654 | cachethis |= nfsd4_cache_this_op(op); | 1681 | cachethis |= nfsd4_cache_this_op(op); |
1682 | |||
1683 | max_reply = max(max_reply, nfsd4_max_reply(op->opnum)); | ||
1655 | } | 1684 | } |
1656 | /* Sessions make the DRC unnecessary: */ | 1685 | /* Sessions make the DRC unnecessary: */ |
1657 | if (argp->minorversion) | 1686 | if (argp->minorversion) |
1658 | cachethis = false; | 1687 | cachethis = false; |
1688 | if (max_reply != INT_MAX) | ||
1689 | svc_reserve(argp->rqstp, max_reply); | ||
1659 | argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; | 1690 | argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; |
1660 | 1691 | ||
1661 | DECODE_TAIL; | 1692 | DECODE_TAIL; |