[PATCH RFC 3/3] SUNRPC: grant an idle flow a burst allowance on the high-priority queue

Benjamin Coddington <ben.coddington-F/[email protected]>
Newsgroups gmane.linux.nfs
Message-ID <fdd0e8541cdf8a37cbb97e5c33730593a1649eb6.1782314746.git.bcodding@hammerspace.com>
Routing only the leading request of a flow to the high-priority queue
protects single, isolated round trips but not interactive work: one
client request -- a syscall, a page fault against an NFS-backed file --
fans out into many correlated RPCs.  With a budget of one, the first
jumps the queue and the rest fall to the bulk queue and finish at the
aggressor's rate, so the command completes no sooner than before.

Grant a transport a budget of SVC_XPRT_HI_BURST high-priority dispatches
when it becomes active after idling (xpt_nr_rqsts == 0 at enqueue),
spending one credit per dispatch and falling back to the bulk queue once
the budget is gone.  The whole burst a request fans out into is now
serviced ahead of backlogged flows, not just its leading edge.

The budget refills only on an idle-to-active transition, so a flow that
stays continuously backlogged spends its budget once and then lives in
the bulk queue: a client cannot hold the high-priority queue by keeping
its connections busy or by opening more of them.  xpt_hi_credit is
touched only under the XPT_BUSY serialisation in svc_xprt_enqueue, so it
needs no atomic or lock.

SVC_XPRT_HI_BURST is a fixed 64 for now -- generous enough to cover a
typical request's RPC fan-out, and cheap to over-provision since a
backlogged flow rides the high-priority queue for at most that many
dispatches per idle period.

Signed-off-by: Benjamin Coddington <bcodding-F/[email protected]>
---
 include/linux/sunrpc/svc_xprt.h |  1 +
 net/sunrpc/svc_xprt.c           | 14 +++++++++++---
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index da2a2531e110..18b2c4237f1f 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -61,6 +61,7 @@ struct svc_xprt {
 	struct svc_serv		*xpt_server;	/* service for transport */
 	atomic_t    	    	xpt_reserved;	/* space on outq that is rsvd */
 	atomic_t		xpt_nr_rqsts;	/* Number of requests */
+	int			xpt_hi_credit;	/* high-priority dispatch budget */
 	struct mutex		xpt_mutex;	/* to serialize sending data */
 	spinlock_t		xpt_lock;	/* protects sk_deferred
 						 * and xpt_auth_cache */
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index ec4c05094e9a..6b0da45aede6 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -499,6 +499,10 @@ static bool svc_xprt_ready(struct svc_xprt *xprt)
 	return false;
 }
 
+/* High-priority dispatch budget granted to a flow when it becomes active
+ * after idling -- sized to cover an interactive request's burst of RPCs. */
+#define SVC_XPRT_HI_BURST	64
+
 /**
  * svc_xprt_enqueue - Queue a transport on an idle nfsd thread
  * @xprt: transport with data pending
@@ -523,10 +527,14 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
 
 	percpu_counter_inc(&pool->sp_sockets_queued);
 	xprt->xpt_qtime = ktime_get();
-	if (atomic_read(&xprt->xpt_nr_rqsts))
-		lwq_enqueue(&xprt->xpt_ready, &pool->sp_xprts);
-	else
+	if (atomic_read(&xprt->xpt_nr_rqsts) == 0)
+		xprt->xpt_hi_credit = SVC_XPRT_HI_BURST;
+	if (xprt->xpt_hi_credit > 0) {
+		xprt->xpt_hi_credit--;
 		lwq_enqueue(&xprt->xpt_ready, &pool->sp_xprts_hi);
+	} else {
+		lwq_enqueue(&xprt->xpt_ready, &pool->sp_xprts);
+	}
 
 	svc_pool_wake_idle_thread(pool);
 }
-- 
2.53.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.