sunrpc: Allocate up to RPCSVC_MAXPAGES per svc_rqst
authorChuck Lever <chuck.lever@oracle.com>
Fri, 30 Jun 2017 16:03:54 +0000 (12:03 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Wed, 12 Jul 2017 19:54:55 +0000 (15:54 -0400)
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>
include/linux/sunrpc/svc.h
net/sunrpc/svc_xprt.c

index eec04982a7ea355dcefebeeb7d8488aa56c4e2e8..a3f8af9bd543e4c117f95178662f971363df16e3 100644 (file)
@@ -246,7 +246,7 @@ struct svc_rqst {
        size_t                  rq_xprt_hlen;   /* xprt header len */
        struct xdr_buf          rq_arg;
        struct xdr_buf          rq_res;
-       struct page *           rq_pages[RPCSVC_MAXPAGES];
+       struct page             *rq_pages[RPCSVC_MAXPAGES + 1];
        struct page *           *rq_respages;   /* points into rq_pages */
        struct page *           *rq_next_page; /* next reply page to use */
        struct page *           *rq_page_end;  /* one past the last page */
index 7bfe1fb42addcd41b00d297b85e2009d711b6f15..d16a8b423c20b613fa2bf8b8fbbd87b5ecb95033 100644 (file)
@@ -659,11 +659,13 @@ static int svc_alloc_arg(struct svc_rqst *rqstp)
        int i;
 
        /* now allocate needed pages.  If we get a failure, sleep briefly */
-       pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
-       WARN_ON_ONCE(pages >= RPCSVC_MAXPAGES);
-       if (pages >= RPCSVC_MAXPAGES)
+       pages = (serv->sv_max_mesg + 2 * PAGE_SIZE) >> PAGE_SHIFT;
+       if (pages > RPCSVC_MAXPAGES) {
+               pr_warn_once("svc: warning: pages=%u > RPCSVC_MAXPAGES=%lu\n",
+                            pages, RPCSVC_MAXPAGES);
                /* use as many pages as possible */
-               pages = RPCSVC_MAXPAGES - 1;
+               pages = RPCSVC_MAXPAGES;
+       }
        for (i = 0; i < pages ; i++)
                while (rqstp->rq_pages[i] == NULL) {
                        struct page *p = alloc_page(GFP_KERNEL);