[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