[PATCH RFC 1/4] sunrpc: add a per-transport fairness key to svc_xprt
Benjamin Coddington <ben.coddington-F/[email protected]>
| Newsgroups | gmane.linux.nfs |
|---|---|
| Message-ID | <bd45e015132b2d8beaeb0e4013d0bc4e5061932b.1780498019.git.bcodding@hammerspace.com> |
The server dispatches ready transports from a single per-pool FIFO (svc_pool.sp_xprts), so a client's share of the service threads scales with the number of connections it holds: a client with K connections is served roughly K times as often as a single-connection client. The unit of fairness is the transport, not the client. As the first step toward per-client fair queueing, give every transport an opaque fairness key. sunrpc supplies a default derived from the peer's source address; the source port is deliberately excluded so that a client's several connections (nconnect, or a fan of data movers) share one key. An upper layer that knows a better identity may overwrite xpt_fairq_key, and a nonzero value takes precedence over the default. Also union a list_head (xpt_fairq) over xpt_ready for linking a transport into a fair-queue bucket; a transport is only ever on one of the two ready structures. Nothing uses either yet, so there is no functional change. Signed-off-by: Benjamin Coddington <bcodding-F/[email protected]> Co-Authored-By: Claude Opus 4.8 <noreply-IarDGxEC4Up8UrSeD/[email protected]> --- include/linux/sunrpc/svc_xprt.h | 46 ++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index da2a2531e110..67d0c5d9b92c 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -55,7 +55,13 @@ struct svc_xprt { struct kref xpt_ref; ktime_t xpt_qtime; struct list_head xpt_list; - struct lwq_node xpt_ready; + union { + struct lwq_node xpt_ready; /* lockless FIFO (default) */ + struct list_head xpt_fairq; /* fair-queue bucket link */ + }; + unsigned long xpt_fairq_key; /* opaque per-client fairness + * identity; 0 => derive from + * source address (xpt_remote) */ unsigned long xpt_flags; struct svc_serv *xpt_server; /* service for transport */ @@ -157,6 +163,44 @@ static inline bool svc_xprt_is_dead(const struct svc_xprt *xprt) (test_bit(XPT_CLOSE, &xprt->xpt_flags) != 0); } +/* + * Per-transport fairness key. The fair-queue dispatcher groups ready + * transports by this key and round-robins across keys, so that service is + * shared per client rather than per transport. + * + * sunrpc supplies a default derived from the peer's source *address*; the + * source port is deliberately excluded so that a client's several connections + * (e.g. nconnect, or a fan of data movers) share a single key. An upper layer + * that knows a better identity -- e.g. nfsd stamping an NFSv4.1 clientid in + * nfsd4_init_conn() -- may set xpt_fairq_key directly; a nonzero value + * overrides the default. + */ +static inline unsigned long svc_xprt_fairq_default_key(const struct svc_xprt *xprt) +{ + const struct sockaddr *sa = (const struct sockaddr *)&xprt->xpt_remote; + + switch (sa->sa_family) { + case AF_INET: + return (unsigned long) + ((const struct sockaddr_in *)sa)->sin_addr.s_addr; + case AF_INET6: { + const struct in6_addr *a = + &((const struct sockaddr_in6 *)sa)->sin6_addr; + + return (unsigned long)(a->s6_addr32[0] ^ a->s6_addr32[1] ^ + a->s6_addr32[2] ^ a->s6_addr32[3]); + } + default: + return (unsigned long)sa->sa_family; + } +} + +static inline unsigned long svc_xprt_fairq_key(const struct svc_xprt *xprt) +{ + return xprt->xpt_fairq_key ? xprt->xpt_fairq_key + : svc_xprt_fairq_default_key(xprt); +} + int svc_reg_xprt_class(struct svc_xprt_class *); void svc_unreg_xprt_class(struct svc_xprt_class *); void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *, -- 2.53.0