From: Jeff Layton <jlayton@kernel.org>
To: cel@kernel.org, NeilBrown <neil@brown.name>,
Olga Kornievskaia <okorniev@redhat.com>,
Dai Ngo <dai.ngo@oracle.com>, Tom Talpey <tom@talpey.com>
Cc: linux-nfs@vger.kernel.org, Chuck Lever <chuck.lever@oracle.com>
Subject: Re: [PATCH v2 03/10] sunrpc: Replace the rq_pages array with dynamically-allocated memory
Date: Mon, 21 Apr 2025 08:19:49 -0400 [thread overview]
Message-ID: <8c89fc483efdb0b5eab660781416cba500e54b64.camel@kernel.org> (raw)
In-Reply-To: <20250419172818.6945-4-cel@kernel.org>
On Sat, 2025-04-19 at 13:28 -0400, cel@kernel.org wrote:
> From: Chuck Lever <chuck.lever@oracle.com>
>
> 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. Replacing it with a single
> pointer reduces the size of struct svc_rqst to just over 9500 bytes.
>
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
> include/linux/sunrpc/svc.h | 3 ++-
> net/sunrpc/svc.c | 34 ++++++++++++++++++-------------
> net/sunrpc/svc_xprt.c | 10 +--------
> net/sunrpc/xprtrdma/svc_rdma_rw.c | 2 +-
> 4 files changed, 24 insertions(+), 25 deletions(-)
>
> diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
> index 5b879c31d7b8..96ac12dbb04d 100644
> --- a/include/linux/sunrpc/svc.h
> +++ b/include/linux/sunrpc/svc.h
> @@ -200,7 +200,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 */
> diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
> index 8ce3e6b3df6a..682e11c9be36 100644
> --- a/net/sunrpc/svc.c
> +++ b/net/sunrpc/svc.c
> @@ -636,20 +636,25 @@ 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;
> + /* Add an extra page, as rq_pages holds both request and reply.
> + * We assume one of those is at most one page.
> + */
> + rqstp->rq_maxpages = svc_serv_maxpages(serv) + 1;
>
> - 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 +663,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 +710,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 +902,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);
> diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
> index ae25405d8bd2..23547ed25269 100644
> --- a/net/sunrpc/svc_xprt.c
> +++ b/net/sunrpc/svc_xprt.c
> @@ -651,18 +651,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)
> diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c
> index 40797114d50a..661b3fe2779f 100644
> --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c
> +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c
> @@ -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;
> }
>
nit: I'd probably squash 2 and 3 together, but they both look right:
Reviewed-by: Jeff Layton <jlayton@kernel.org>
next prev parent reply other threads:[~2025-04-21 12:19 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-19 17:28 [PATCH v2 00/10] Allocate payload arrays dynamically cel
2025-04-19 17:28 ` [PATCH v2 01/10] sunrpc: Remove backchannel check in svc_init_buffer() cel
2025-04-21 12:16 ` Jeff Layton
2025-04-21 14:59 ` Chuck Lever
2025-04-19 17:28 ` [PATCH v2 02/10] sunrpc: Add a helper to derive maxpages from sv_max_mesg cel
2025-04-22 20:48 ` NeilBrown
2025-04-23 13:16 ` Chuck Lever
2025-04-19 17:28 ` [PATCH v2 03/10] sunrpc: Replace the rq_pages array with dynamically-allocated memory cel
2025-04-21 12:19 ` Jeff Layton [this message]
2025-04-19 17:28 ` [PATCH v2 04/10] sunrpc: Replace the rq_vec " cel
2025-04-21 12:22 ` Jeff Layton
2025-04-21 15:05 ` Chuck Lever
2025-04-19 17:28 ` [PATCH v2 05/10] sunrpc: Replace the rq_bvec " cel
2025-04-19 17:28 ` [PATCH v2 06/10] sunrpc: Adjust size of socket's receive page array dynamically cel
2025-04-19 17:28 ` [PATCH v2 07/10] svcrdma: Adjust the number of RDMA contexts per transport cel
2025-04-19 17:28 ` [PATCH v2 08/10] svcrdma: Adjust the number of entries in svc_rdma_recv_ctxt::rc_pages cel
2025-04-19 17:28 ` [PATCH v2 09/10] svcrdma: Adjust the number of entries in svc_rdma_send_ctxt::sc_pages cel
2025-04-19 17:28 ` [PATCH v2 10/10] sunrpc: Remove the RPCSVC_MAXPAGES macro cel
2025-04-19 17:54 ` [PATCH v2 00/10] Allocate payload arrays dynamically Chuck Lever
2025-04-21 12:28 ` Jeff Layton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8c89fc483efdb0b5eab660781416cba500e54b64.camel@kernel.org \
--to=jlayton@kernel.org \
--cc=cel@kernel.org \
--cc=chuck.lever@oracle.com \
--cc=dai.ngo@oracle.com \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--cc=tom@talpey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox