]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
sunrpc: Replace the rq_pages array with dynamically-allocated memory
authorChuck Lever <chuck.lever@oracle.com>
Mon, 28 Apr 2025 19:36:52 +0000 (15:36 -0400)
committerChuck Lever <chuck.lever@oracle.com>
Thu, 15 May 2025 20:16:22 +0000 (16:16 -0400)
As a step towards making NFSD's maximum rsize and wsize variable at
run-time, replace the fixed-size rq_vec[] array in struct svc_rqst
with a chunk of dynamically-allocated memory.

On a system with 8-byte pointers and 4KB pages, pahole reports that
the rq_pages[] array is 2080 bytes. This patch replaces that with
a single 8-byte pointer field.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: NeilBrown <neil@brown.name>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
include/linux/sunrpc/svc.h
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/xprtrdma/svc_rdma_rw.c

index 749f8e53e8a61052653044ecfa19d76303e2232a..57be6953988866a05874e28afe52bdc013001b5e 100644 (file)
@@ -205,7 +205,8 @@ struct svc_rqst {
        struct xdr_stream       rq_res_stream;
        struct page             *rq_scratch_page;
        struct xdr_buf          rq_res;
-       struct page             *rq_pages[RPCSVC_MAXPAGES + 1];
+       unsigned long           rq_maxpages;    /* num of entries in rq_pages */
+       struct page *           *rq_pages;
        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 8ce3e6b3df6a10fbf1ae3d97e4432e4f92a7c3a4..d320837e09f03280bcf1cd6b5128e62ff1200048 100644 (file)
@@ -636,20 +636,22 @@ svc_destroy(struct svc_serv **servp)
 EXPORT_SYMBOL_GPL(svc_destroy);
 
 static bool
-svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node)
+svc_init_buffer(struct svc_rqst *rqstp, const struct svc_serv *serv, int node)
 {
-       unsigned long pages, ret;
+       unsigned long ret;
 
-       pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
-                                      * We assume one is at most one page
-                                      */
-       WARN_ON_ONCE(pages > RPCSVC_MAXPAGES);
-       if (pages > RPCSVC_MAXPAGES)
-               pages = RPCSVC_MAXPAGES;
+       rqstp->rq_maxpages = svc_serv_maxpages(serv);
 
-       ret = alloc_pages_bulk_node(GFP_KERNEL, node, pages,
+       /* rq_pages' last entry is NULL for historical reasons. */
+       rqstp->rq_pages = kcalloc_node(rqstp->rq_maxpages + 1,
+                                      sizeof(struct page *),
+                                      GFP_KERNEL, node);
+       if (!rqstp->rq_pages)
+               return false;
+
+       ret = alloc_pages_bulk_node(GFP_KERNEL, node, rqstp->rq_maxpages,
                                    rqstp->rq_pages);
-       return ret == pages;
+       return ret == rqstp->rq_maxpages;
 }
 
 /*
@@ -658,11 +660,12 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node)
 static void
 svc_release_buffer(struct svc_rqst *rqstp)
 {
-       unsigned int i;
+       unsigned long i;
 
-       for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++)
+       for (i = 0; i < rqstp->rq_maxpages; i++)
                if (rqstp->rq_pages[i])
                        put_page(rqstp->rq_pages[i]);
+       kfree(rqstp->rq_pages);
 }
 
 static void
@@ -704,7 +707,7 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node)
        if (!rqstp->rq_resp)
                goto out_enomem;
 
-       if (!svc_init_buffer(rqstp, serv->sv_max_mesg, node))
+       if (!svc_init_buffer(rqstp, serv, node))
                goto out_enomem;
 
        rqstp->rq_err = -EAGAIN; /* No error yet */
@@ -896,7 +899,7 @@ EXPORT_SYMBOL_GPL(svc_set_num_threads);
 bool svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page)
 {
        struct page **begin = rqstp->rq_pages;
-       struct page **end = &rqstp->rq_pages[RPCSVC_MAXPAGES];
+       struct page **end = &rqstp->rq_pages[rqstp->rq_maxpages];
 
        if (unlikely(rqstp->rq_next_page < begin || rqstp->rq_next_page > end)) {
                trace_svc_replace_page_err(rqstp);
index 32018557797b1f683d8b7259f5fccd029aebcd71..cb14d6ddac6c4b9b659784684f9c13dde537ae3d 100644 (file)
@@ -652,18 +652,10 @@ static void svc_check_conn_limits(struct svc_serv *serv)
 
 static bool svc_alloc_arg(struct svc_rqst *rqstp)
 {
-       struct svc_serv *serv = rqstp->rq_server;
        struct xdr_buf *arg = &rqstp->rq_arg;
        unsigned long pages, filled, ret;
 
-       pages = (serv->sv_max_mesg + 2 * PAGE_SIZE) >> PAGE_SHIFT;
-       if (pages > RPCSVC_MAXPAGES) {
-               pr_warn_once("svc: warning: pages=%lu > RPCSVC_MAXPAGES=%lu\n",
-                            pages, RPCSVC_MAXPAGES);
-               /* use as many pages as possible */
-               pages = RPCSVC_MAXPAGES;
-       }
-
+       pages = rqstp->rq_maxpages;
        for (filled = 0; filled < pages; filled = ret) {
                ret = alloc_pages_bulk(GFP_KERNEL, pages, rqstp->rq_pages);
                if (ret > filled)
index 40797114d50a49a4e10cb30c182f094fc8e7313d..661b3fe2779f0c0e5a2c751c1fb552532d5aec78 100644 (file)
@@ -765,7 +765,7 @@ static int svc_rdma_build_read_segment(struct svc_rqst *rqstp,
                }
                len -= seg_len;
 
-               if (len && ((head->rc_curpage + 1) > ARRAY_SIZE(rqstp->rq_pages)))
+               if (len && ((head->rc_curpage + 1) > rqstp->rq_maxpages))
                        goto out_overrun;
        }