diff options
| author | Chuck Lever <cel@kernel.org> | 2026-06-10 21:58:53 -0400 |
|---|---|---|
| committer | Chuck Lever <cel@kernel.org> | 2026-07-12 22:22:39 -0400 |
| commit | c9be9f8e5fa249f6cd5de40ab41b2e64ea4a05fa (patch) | |
| tree | 29c3f211c6d542527b95e9b063062012b8d3d810 | |
| parent | 458610970cad36c5e6b0dee351b9cf97afb33328 (diff) | |
| download | linux-next-c9be9f8e5fa249f6cd5de40ab41b2e64ea4a05fa.tar.gz linux-next-c9be9f8e5fa249f6cd5de40ab41b2e64ea4a05fa.zip | |
SUNRPC: Add svc_serv_maxthreads() to report the thread ceiling
A pooled RPC service sizes its threads dynamically, growing and
shrinking each pool between its minimum and maximum bounds as load
varies. The count of running threads therefore reflects recent
demand, not the service's capacity. A consumer that sizes a data
structure against the concurrency the service can sustain -- NFSD's
NFSv4 session slot tables, for one -- needs that stable ceiling, and
computing it means summing sp_nrthrmax across every pool.
Add svc_serv_maxthreads() so the summation, and its dependence
on the layout of struct svc_serv and struct svc_pool, stays within
sunrpc. The read is lock-free: pool maxima change only when a service
is reconfigured, a path callers already serialize against startup and
shutdown, so a racing reader observes at worst a transient value. This
is acceptable for the sizing heuristics that will consume it.
nfsd_nrthreads() already sums sp_nrthrmax across pools by hand; convert
it to svc_serv_maxthreads(), giving the new export an in-tree consumer
and removing a copy of the dependence on svc_serv internals.
Reviewed-by: NeilBrown <neil@brown.name>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Benjamin Coddington <bcodding@hammerspace.com>
Link: https://patch.msgid.link/20260610-nfsd-slot-growth-clamp-v1-1-7b966700df0b@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
| -rw-r--r-- | fs/nfsd/nfssvc.c | 12 | ||||
| -rw-r--r-- | include/linux/sunrpc/svc.h | 1 | ||||
| -rw-r--r-- | net/sunrpc/svc.c | 23 |
3 files changed, 33 insertions, 3 deletions
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index e45d46089959..0d3838dd59c1 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -237,15 +237,21 @@ static void nfsd_net_free(struct percpu_ref *ref) */ #define NFSD_MAXSERVS 8192 +/** + * nfsd_nrthreads - report a namespace's configured nfsd thread count + * @net: network namespace to query + * + * Return: the configured thread ceiling, or 0 when no service runs. + */ int nfsd_nrthreads(struct net *net) { - int i, rv = 0; + int rv = 0; struct nfsd_net *nn = net_generic(net, nfsd_net_id); + /* nfsd_mutex keeps nn->nfsd_serv valid across the read. */ mutex_lock(&nfsd_mutex); if (nn->nfsd_serv) - for (i = 0; i < nn->nfsd_serv->sv_nrpools; ++i) - rv += nn->nfsd_serv->sv_pools[i].sp_nrthrmax; + rv = svc_serv_maxthreads(nn->nfsd_serv); mutex_unlock(&nfsd_mutex); return rv; } diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 4be6204f6630..3a0152d926fb 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -469,6 +469,7 @@ int svc_set_pool_threads(struct svc_serv *serv, struct svc_pool *pool, unsigned int min_threads, unsigned int max_threads); int svc_set_num_threads(struct svc_serv *serv, unsigned int min_threads, unsigned int nrservs); +unsigned int svc_serv_maxthreads(const struct svc_serv *serv); int svc_pool_stats_open(struct svc_info *si, struct file *file); void svc_process(struct svc_rqst *rqstp); void svc_process_bc(struct rpc_rqst *req, struct svc_rqst *rqstp); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 009373737ea9..86d39610cf0a 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -988,6 +988,29 @@ svc_set_num_threads(struct svc_serv *serv, unsigned int min_threads, EXPORT_SYMBOL_GPL(svc_set_num_threads); /** + * svc_serv_maxthreads - report a service's configured thread ceiling + * @serv: RPC service to query + * + * A pooled service sizes its threads dynamically, so the number of + * threads running at any moment tracks recent load rather than the + * service's capacity. The per-pool maximum is the stable figure a + * consumer should size against. + * + * The caller must keep @serv valid for the duration of the call. + * + * Return: the sum of every pool's maximum thread count. + */ +unsigned int svc_serv_maxthreads(const struct svc_serv *serv) +{ + unsigned int i, max = 0; + + for (i = 0; i < serv->sv_nrpools; i++) + max += data_race(serv->sv_pools[i].sp_nrthrmax); + return max; +} +EXPORT_SYMBOL_GPL(svc_serv_maxthreads); + +/** * svc_rqst_replace_page - Replace one page in rq_respages[] * @rqstp: svc_rqst with pages to replace * @page: replacement page |
