diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2017-06-30 12:03:54 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2017-07-12 15:54:55 -0400 |
commit | 8c6ae4980e70395cbdfdf605c29673c5a6a89d9a (patch) | |
tree | c334332505b52c05aeb441a83c0b384ebcfccea9 /net/sunrpc/svc_xprt.c | |
parent | 2d6491a56c76f2d6c22aaa710e2a4d04ad41529b (diff) |
sunrpc: Allocate up to RPCSVC_MAXPAGES per svc_rqst
svcrdma needs 259 pages allocated to receive 1MB NFSv4.0 WRITE requests:
- 1 page for the transport header and head iovec
- 256 pages for the data payload
- 1 page for the trailing GETATTR request (since NFSD XDR decoding
does not look for a tail iovec, the GETATTR is stuck at the end
of the rqstp->rq_arg.pages list)
- 1 page for building the reply xdr_buf
But RPCSVC_MAXPAGES is already 259 (on x86_64). The problem is that
svc_alloc_arg never allocates that many pages. To address this:
1. The final element of rq_pages always points to NULL. To
accommodate up to 259 pages in rq_pages, add an extra element
to rq_pages for the array termination sentinel.
2. Adjust the calculation of "pages" to match how RPCSVC_MAXPAGES
is calculated, so it can go up to 259. Bruce noted that the
calculation assumes sv_max_mesg is a multiple of PAGE_SIZE,
which might not always be true. I didn't change this assumption.
3. Change the loop boundaries to allow 259 pages to be allocated.
Additional clean-up: WARN_ON_ONCE adds an extra conditional branch,
which is basically never taken. And there's no need to dump the
stack here because svc_alloc_arg has only one caller.
Keeping that NULL "array termination sentinel"; there doesn't appear to
be any code that depends on it, only code in nfsd_splice_actor() which
needs the 259th element to be initialized to *something*. So it's
possible we could just keep the array at 259 elements and drop that
final NULL, but we're being conservative for now.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net/sunrpc/svc_xprt.c')
-rw-r--r-- | net/sunrpc/svc_xprt.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 7bfe1fb42add..d16a8b423c20 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
@@ -659,11 +659,13 @@ static int svc_alloc_arg(struct svc_rqst *rqstp) | |||
659 | int i; | 659 | int i; |
660 | 660 | ||
661 | /* now allocate needed pages. If we get a failure, sleep briefly */ | 661 | /* now allocate needed pages. If we get a failure, sleep briefly */ |
662 | pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE; | 662 | pages = (serv->sv_max_mesg + 2 * PAGE_SIZE) >> PAGE_SHIFT; |
663 | WARN_ON_ONCE(pages >= RPCSVC_MAXPAGES); | 663 | if (pages > RPCSVC_MAXPAGES) { |
664 | if (pages >= RPCSVC_MAXPAGES) | 664 | pr_warn_once("svc: warning: pages=%u > RPCSVC_MAXPAGES=%lu\n", |
665 | pages, RPCSVC_MAXPAGES); | ||
665 | /* use as many pages as possible */ | 666 | /* use as many pages as possible */ |
666 | pages = RPCSVC_MAXPAGES - 1; | 667 | pages = RPCSVC_MAXPAGES; |
668 | } | ||
667 | for (i = 0; i < pages ; i++) | 669 | for (i = 0; i < pages ; i++) |
668 | while (rqstp->rq_pages[i] == NULL) { | 670 | while (rqstp->rq_pages[i] == NULL) { |
669 | struct page *p = alloc_page(GFP_KERNEL); | 671 | struct page *p = alloc_page(GFP_KERNEL); |