linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/4] NFSD memory allocation optimizations
@ 2023-04-15  0:17 Chuck Lever
  2023-04-15  0:17 ` [PATCH v1 1/4] SUNRPC: Relocate svc_free_res_pages() Chuck Lever
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Chuck Lever @ 2023-04-15  0:17 UTC (permalink / raw)
  To: linux-nfs, linux-mm

I've found a few ways to optimize the release of pages in NFSD.
Please let me know if I'm abusing the release_pages() and pagevec
APIs.

---

Chuck Lever (4):
      SUNRPC: Relocate svc_free_res_pages()
      SUNRPC: Convert svc_xprt_release() to the release_pages() API
      SUNRPC: Convert svc_tcp_restore_pages() to the release_pages() API
      SUNRPC: Be even lazier about releasing pages


 include/linux/sunrpc/svc.h | 12 +-----------
 net/sunrpc/svc.c           | 21 +++++++++++++++++++++
 net/sunrpc/svc_xprt.c      |  5 +----
 net/sunrpc/svcsock.c       | 12 ++++++------
 4 files changed, 29 insertions(+), 21 deletions(-)

--
Chuck Lever



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v1 1/4] SUNRPC: Relocate svc_free_res_pages()
  2023-04-15  0:17 [PATCH v1 0/4] NFSD memory allocation optimizations Chuck Lever
@ 2023-04-15  0:17 ` Chuck Lever
  2023-04-15  0:18 ` [PATCH v1 2/4] SUNRPC: Convert svc_xprt_release() to the release_pages() API Chuck Lever
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Chuck Lever @ 2023-04-15  0:17 UTC (permalink / raw)
  To: linux-nfs, linux-mm

From: Chuck Lever <chuck.lever@oracle.com>

Clean-up: There doesn't seem to be a reason why this function is
stuck in a header. One thing it prevents is the convenient addition
of tracing. Moving it to a source file also makes the rq_respages
clean-up logic easier to find.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 include/linux/sunrpc/svc.h |   12 +-----------
 net/sunrpc/svc.c           |   19 +++++++++++++++++++
 net/sunrpc/svc_xprt.c      |    2 +-
 3 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 2d31121fc2e6..762d7231e574 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -309,17 +309,6 @@ static inline struct sockaddr *svc_daddr(const struct svc_rqst *rqst)
 	return (struct sockaddr *) &rqst->rq_daddr;
 }
 
-static inline void svc_free_res_pages(struct svc_rqst *rqstp)
-{
-	while (rqstp->rq_next_page != rqstp->rq_respages) {
-		struct page **pp = --rqstp->rq_next_page;
-		if (*pp) {
-			put_page(*pp);
-			*pp = NULL;
-		}
-	}
-}
-
 struct svc_deferred_req {
 	u32			prot;	/* protocol (UDP or TCP) */
 	struct svc_xprt		*xprt;
@@ -424,6 +413,7 @@ struct svc_rqst *svc_rqst_alloc(struct svc_serv *serv,
 					struct svc_pool *pool, int node);
 bool		   svc_rqst_replace_page(struct svc_rqst *rqstp,
 					 struct page *page);
+void		   svc_rqst_release_pages(struct svc_rqst *rqstp);
 void		   svc_rqst_free(struct svc_rqst *);
 void		   svc_exit_thread(struct svc_rqst *);
 struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 0aa8892fad63..0fc70cc405b2 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -869,6 +869,25 @@ bool svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page)
 }
 EXPORT_SYMBOL_GPL(svc_rqst_replace_page);
 
+/**
+ * svc_rqst_release_pages - Release Reply buffer pages
+ * @rqstp: RPC transaction context
+ *
+ * Release response pages that might still be in flight after
+ * svc_send, and any spliced filesystem-owned pages.
+ */
+void svc_rqst_release_pages(struct svc_rqst *rqstp)
+{
+	while (rqstp->rq_next_page != rqstp->rq_respages) {
+		struct page **pp = --rqstp->rq_next_page;
+
+		if (*pp) {
+			put_page(*pp);
+			*pp = NULL;
+		}
+	}
+}
+
 /*
  * Called from a server thread as it's exiting. Caller must hold the "service
  * mutex" for the service.
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 36c79b718323..533e08c4f319 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -542,7 +542,7 @@ static void svc_xprt_release(struct svc_rqst *rqstp)
 	rqstp->rq_deferred = NULL;
 
 	pagevec_release(&rqstp->rq_pvec);
-	svc_free_res_pages(rqstp);
+	svc_rqst_release_pages(rqstp);
 	rqstp->rq_res.page_len = 0;
 	rqstp->rq_res.page_base = 0;
 




^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v1 2/4] SUNRPC: Convert svc_xprt_release() to the release_pages() API
  2023-04-15  0:17 [PATCH v1 0/4] NFSD memory allocation optimizations Chuck Lever
  2023-04-15  0:17 ` [PATCH v1 1/4] SUNRPC: Relocate svc_free_res_pages() Chuck Lever
@ 2023-04-15  0:18 ` Chuck Lever
  2023-04-15  0:18 ` [PATCH v1 3/4] SUNRPC: Convert svc_tcp_restore_pages() " Chuck Lever
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Chuck Lever @ 2023-04-15  0:18 UTC (permalink / raw)
  To: linux-nfs, linux-mm

From: Chuck Lever <chuck.lever@oracle.com>

Instead of invoking put_page() one-at-a-time, pass the "response"
portion of rq_pages directly to release_pages() to reduce the number
of times each nfsd thread invokes a page allocator API.

Since svc_xprt_release() is not invoked while a client is waiting
for an RPC Reply, this is not expected to directly impact mean
request latencies on a lightly or moderately loaded server. However
as workload intensity increases, I expect somewhat better
scalability: the same number of server threads should be able to
handle more work.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 net/sunrpc/svc.c |   11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 0fc70cc405b2..b982f802f2a0 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -878,13 +878,12 @@ EXPORT_SYMBOL_GPL(svc_rqst_replace_page);
  */
 void svc_rqst_release_pages(struct svc_rqst *rqstp)
 {
-	while (rqstp->rq_next_page != rqstp->rq_respages) {
-		struct page **pp = --rqstp->rq_next_page;
+	int i, count = rqstp->rq_next_page - rqstp->rq_respages;
 
-		if (*pp) {
-			put_page(*pp);
-			*pp = NULL;
-		}
+	if (count) {
+		release_pages(rqstp->rq_respages, count);
+		for (i = 0; i < count; i++)
+			rqstp->rq_respages[i] = NULL;
 	}
 }
 




^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v1 3/4] SUNRPC: Convert svc_tcp_restore_pages() to the release_pages() API
  2023-04-15  0:17 [PATCH v1 0/4] NFSD memory allocation optimizations Chuck Lever
  2023-04-15  0:17 ` [PATCH v1 1/4] SUNRPC: Relocate svc_free_res_pages() Chuck Lever
  2023-04-15  0:18 ` [PATCH v1 2/4] SUNRPC: Convert svc_xprt_release() to the release_pages() API Chuck Lever
@ 2023-04-15  0:18 ` Chuck Lever
  2023-04-15  0:18 ` [PATCH v1 4/4] SUNRPC: Be even lazier about releasing pages Chuck Lever
  2023-04-15 17:24 ` [PATCH v1 0/4] NFSD memory allocation optimizations Calum Mackay
  4 siblings, 0 replies; 6+ messages in thread
From: Chuck Lever @ 2023-04-15  0:18 UTC (permalink / raw)
  To: linux-nfs, linux-mm

From: Chuck Lever <chuck.lever@oracle.com>

Instead of invoking put_page() one-at-a-time, pass the portion of
rq_pages to be released directly to release_pages() to reduce the
number of times each server thread invokes a page allocator API.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 net/sunrpc/svcsock.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 302a14dd7882..44f72b558a1c 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -812,12 +812,12 @@ static size_t svc_tcp_restore_pages(struct svc_sock *svsk,
 	if (!len)
 		return 0;
 	npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-	for (i = 0; i < npages; i++) {
-		if (rqstp->rq_pages[i] != NULL)
-			put_page(rqstp->rq_pages[i]);
-		BUG_ON(svsk->sk_pages[i] == NULL);
-		rqstp->rq_pages[i] = svsk->sk_pages[i];
-		svsk->sk_pages[i] = NULL;
+	if (npages) {
+		release_pages(rqstp->rq_pages, npages);
+		for (i = 0; i < npages; i++) {
+			rqstp->rq_pages[i] = svsk->sk_pages[i];
+			svsk->sk_pages[i] = NULL;
+		}
 	}
 	rqstp->rq_arg.head[0].iov_base = page_address(rqstp->rq_pages[0]);
 	return len;




^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v1 4/4] SUNRPC: Be even lazier about releasing pages
  2023-04-15  0:17 [PATCH v1 0/4] NFSD memory allocation optimizations Chuck Lever
                   ` (2 preceding siblings ...)
  2023-04-15  0:18 ` [PATCH v1 3/4] SUNRPC: Convert svc_tcp_restore_pages() " Chuck Lever
@ 2023-04-15  0:18 ` Chuck Lever
  2023-04-15 17:24 ` [PATCH v1 0/4] NFSD memory allocation optimizations Calum Mackay
  4 siblings, 0 replies; 6+ messages in thread
From: Chuck Lever @ 2023-04-15  0:18 UTC (permalink / raw)
  To: linux-nfs, linux-mm

From: Chuck Lever <chuck.lever@oracle.com>

A single RPC transaction that touches only a couple of pages means
rq_pvec will not be even close to full in svc_xpt_release(). This is
a common case.

Instead, just leave the pages in rq_pvec until it is completely
full. This improves the efficiency of the batch release mechanism
on workloads that involve small RPC messages.

The rq_pvec is also fully emptied just before thread exit.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 net/sunrpc/svc.c      |    3 +++
 net/sunrpc/svc_xprt.c |    3 ---
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index b982f802f2a0..26367cf4c17a 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -649,6 +649,8 @@ svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node)
 	if (!rqstp)
 		return rqstp;
 
+	pagevec_init(&rqstp->rq_pvec);
+
 	__set_bit(RQ_BUSY, &rqstp->rq_flags);
 	rqstp->rq_server = serv;
 	rqstp->rq_pool = pool;
@@ -894,6 +896,7 @@ void svc_rqst_release_pages(struct svc_rqst *rqstp)
 void
 svc_rqst_free(struct svc_rqst *rqstp)
 {
+	pagevec_release(&rqstp->rq_pvec);
 	svc_release_buffer(rqstp);
 	if (rqstp->rq_scratch_page)
 		put_page(rqstp->rq_scratch_page);
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 533e08c4f319..e3952b690f54 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -541,7 +541,6 @@ static void svc_xprt_release(struct svc_rqst *rqstp)
 	kfree(rqstp->rq_deferred);
 	rqstp->rq_deferred = NULL;
 
-	pagevec_release(&rqstp->rq_pvec);
 	svc_rqst_release_pages(rqstp);
 	rqstp->rq_res.page_len = 0;
 	rqstp->rq_res.page_base = 0;
@@ -667,8 +666,6 @@ static int svc_alloc_arg(struct svc_rqst *rqstp)
 	struct xdr_buf *arg = &rqstp->rq_arg;
 	unsigned long pages, filled, ret;
 
-	pagevec_init(&rqstp->rq_pvec);
-
 	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",




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v1 0/4] NFSD memory allocation optimizations
  2023-04-15  0:17 [PATCH v1 0/4] NFSD memory allocation optimizations Chuck Lever
                   ` (3 preceding siblings ...)
  2023-04-15  0:18 ` [PATCH v1 4/4] SUNRPC: Be even lazier about releasing pages Chuck Lever
@ 2023-04-15 17:24 ` Calum Mackay
  4 siblings, 0 replies; 6+ messages in thread
From: Calum Mackay @ 2023-04-15 17:24 UTC (permalink / raw)
  To: Chuck Lever, linux-nfs, linux-mm; +Cc: Calum Mackay


[-- Attachment #1.1: Type: text/plain, Size: 853 bytes --]

On 15/04/2023 1:17 am, Chuck Lever wrote:
> I've found a few ways to optimize the release of pages in NFSD.
> Please let me know if I'm abusing the release_pages() and pagevec
> APIs.
> 
> ---
> 
> Chuck Lever (4):
>        SUNRPC: Relocate svc_free_res_pages()
>        SUNRPC: Convert svc_xprt_release() to the release_pages() API
>        SUNRPC: Convert svc_tcp_restore_pages() to the release_pages() API
>        SUNRPC: Be even lazier about releasing pages
> 
> 
>   include/linux/sunrpc/svc.h | 12 +-----------
>   net/sunrpc/svc.c           | 21 +++++++++++++++++++++
>   net/sunrpc/svc_xprt.c      |  5 +----
>   net/sunrpc/svcsock.c       | 12 ++++++------
>   4 files changed, 29 insertions(+), 21 deletions(-)
> 
> --
> Chuck Lever
> 

Looks good to me, Chuck.

Reviewed-by: Calum Mackay <calum.mackay@oracle.com>

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-04-15 17:24 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-15  0:17 [PATCH v1 0/4] NFSD memory allocation optimizations Chuck Lever
2023-04-15  0:17 ` [PATCH v1 1/4] SUNRPC: Relocate svc_free_res_pages() Chuck Lever
2023-04-15  0:18 ` [PATCH v1 2/4] SUNRPC: Convert svc_xprt_release() to the release_pages() API Chuck Lever
2023-04-15  0:18 ` [PATCH v1 3/4] SUNRPC: Convert svc_tcp_restore_pages() " Chuck Lever
2023-04-15  0:18 ` [PATCH v1 4/4] SUNRPC: Be even lazier about releasing pages Chuck Lever
2023-04-15 17:24 ` [PATCH v1 0/4] NFSD memory allocation optimizations Calum Mackay

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox