[PATCH 3/5] SUNRPC: Flush a received record's pages once it is complete

Chuck Lever <[email protected]>
Newsgroups org.kernel.vger.linux-nfs,org.kernel.vger.netdev
Message-ID <[email protected]>
svc_tcp_read_msg() flushes the destination pages after every
receive. A record that arrives in several pieces is therefore
flushed once per piece. A page spanning two pieces is flushed
twice. Nothing reads the message body before the record is
complete, so no reader needs the intermediate flushes.

Flush every page of the record in one pass from svc_tcp_recvfrom(),
once the last fragment has arrived. Remove svc_flush_bvec() and its
ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE guard. The guard avoided setting
up a bvec iterator, and a plain walk of rq_pages compiles away on
its own where flush_dcache_page() is an empty inline.

Signed-off-by: Chuck Lever <[email protected]>
---
 net/sunrpc/svcsock.c | 36 +++++++++++++++---------------------
 1 file changed, 15 insertions(+), 21 deletions(-)

diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index ae1f3c474f8b..c7b94bd1898b 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -334,25 +334,6 @@ svc_tcp_sock_recvmsg(struct svc_sock *svsk, struct msghdr *msg)
 	return ret;
 }
 
-#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
-static void svc_flush_bvec(const struct bio_vec *bvec, size_t size, size_t seek)
-{
-	struct bvec_iter bi = {
-		.bi_size	= size + seek,
-	};
-	struct bio_vec bv;
-
-	bvec_iter_advance(bvec, &bi, seek & PAGE_MASK);
-	for_each_bvec(bv, bvec, bi, bi)
-		flush_dcache_page(bv.bv_page);
-}
-#else
-static inline void svc_flush_bvec(const struct bio_vec *bvec, size_t size,
-				  size_t seek)
-{
-}
-#endif
-
 /*
  * Read from @rqstp's transport socket. The incoming message fills whole
  * pages in @rqstp's rq_pages array until the last page of the message
@@ -380,8 +361,6 @@ static ssize_t svc_tcp_read_msg(struct svc_rqst *rqstp, size_t buflen,
 		buflen -= seek;
 	}
 	len = svc_tcp_sock_recvmsg(svsk, &msg);
-	if (len > 0)
-		svc_flush_bvec(bvec, len, seek);
 
 	/* If we read a full record, then assume there may be more
 	 * data to read (stream based sockets only!)
@@ -1156,6 +1135,19 @@ static void svc_tcp_fragment_received(struct svc_sock *svsk)
 	svsk->sk_marker = xdr_zero;
 }
 
+/*
+ * Nothing reads the message body before the record is complete, so
+ * a single flush after the last fragment is enough.
+ */
+static void svc_tcp_flush_pages(struct svc_sock *svsk,
+				struct svc_rqst *rqstp)
+{
+	unsigned int pg, pages = DIV_ROUND_UP(svsk->sk_datalen, PAGE_SIZE);
+
+	for (pg = 0; pg < pages; pg++)
+		flush_dcache_page(rqstp->rq_pages[pg]);
+}
+
 /**
  * svc_tcp_recvfrom - Receive data from a TCP socket
  * @rqstp: request structure into which to receive an RPC Call
@@ -1202,6 +1194,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
 	if (svsk->sk_datalen < 8)
 		goto err_nuts;
 
+	svc_tcp_flush_pages(svsk, rqstp);
+
 	rqstp->rq_arg.len = svsk->sk_datalen;
 	rqstp->rq_arg.page_base = 0;
 	if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) {

-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.