sunrpc: add per-netns per-procedure call counts to svc_stat

The existing per-procedure call counts live in global
svc_version->vs_count[] arrays which are not network-namespace-aware.
Add per-netns equivalents in struct svc_stat so the upcoming netlink
stats interface can return namespace-scoped statistics.

Add a vs_count pointer array to struct svc_stat, along with
svc_stat_alloc_counts() and svc_stat_free_counts() helpers to manage
per-version percpu call count arrays.

Increment the per-net counter alongside the global one in
svc_generic_init_request(). Call the alloc/free helpers from
nfsd_net_init() and nfsd_net_exit().

Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260717-exportd-netlink-v7-1-b7ce17b83b60@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
This commit is contained in:
Jeff Layton 2026-07-17 07:08:53 -04:00 committed by Chuck Lever
parent 284a474e94
commit f1775ed34e
3 changed files with 75 additions and 1 deletions

View File

@ -2516,9 +2516,12 @@ static __net_init int nfsd_net_init(struct net *net)
memset(&nn->nfsd_svcstats, 0, sizeof(nn->nfsd_svcstats));
nn->nfsd_svcstats.program = &nfsd_programs[0];
retval = svc_stat_alloc_counts(&nn->nfsd_svcstats);
if (retval)
goto out_proc_error;
if (!nfsd_proc_stat_init(net)) {
retval = -ENOMEM;
goto out_proc_error;
goto out_svcstats_error;
}
for (i = 0; i < sizeof(nn->nfsd_versions); i++)
@ -2536,6 +2539,8 @@ static __net_init int nfsd_net_init(struct net *net)
#endif
return 0;
out_svcstats_error:
svc_stat_free_counts(&nn->nfsd_svcstats);
out_proc_error:
percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM);
out_repcache_error:
@ -2576,6 +2581,7 @@ static __net_exit void nfsd_net_exit(struct net *net)
kfree_sensitive(nn->fh_key);
nfsd_net_cb_shutdown(nn);
nfsd_proc_stat_shutdown(net);
svc_stat_free_counts(&nn->nfsd_svcstats);
percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM);
nfsd_idmap_shutdown(net);
nfsd_export_shutdown(net);

View File

@ -37,9 +37,15 @@ struct svc_stat {
rpcbadfmt,
rpcbadauth,
rpcbadclnt;
/* Per-version per-procedure call counts (per-cpu, per-netns) */
unsigned long __percpu **vs_count;
};
struct net;
int svc_stat_alloc_counts(struct svc_stat *statp);
void svc_stat_free_counts(struct svc_stat *statp);
#ifdef CONFIG_PROC_FS
int rpc_proc_init(struct net *);
void rpc_proc_exit(struct net *);

View File

@ -1347,6 +1347,14 @@ svc_generic_init_request(struct svc_rqst *rqstp,
/* Bump per-procedure stats counter */
this_cpu_inc(versp->vs_count[rqstp->rq_proc]);
/* Bump per-net per-procedure stats counter */
if (rqstp->rq_server->sv_stats &&
rqstp->rq_server->sv_stats->program == progp &&
rqstp->rq_server->sv_stats->vs_count &&
rqstp->rq_server->sv_stats->vs_count[rqstp->rq_vers])
this_cpu_inc(rqstp->rq_server->sv_stats->vs_count
[rqstp->rq_vers][rqstp->rq_proc]);
ret->dispatch = versp->vs_dispatch;
return rpc_success;
err_bad_vers:
@ -1358,6 +1366,60 @@ svc_generic_init_request(struct svc_rqst *rqstp,
}
EXPORT_SYMBOL_GPL(svc_generic_init_request);
/**
* svc_stat_alloc_counts - allocate per-netns per-version call count arrays
* @statp: svc_stat whose vs_count arrays should be allocated
*
* statp->program must be set before calling this.
*
* Returns zero on success, or a negative errno otherwise.
*/
int svc_stat_alloc_counts(struct svc_stat *statp)
{
struct svc_program *prog = statp->program;
unsigned int i;
statp->vs_count = kcalloc(prog->pg_nvers,
sizeof(unsigned long __percpu *),
GFP_KERNEL);
if (!statp->vs_count)
return -ENOMEM;
for (i = 0; i < prog->pg_nvers; i++) {
if (!prog->pg_vers[i])
continue;
statp->vs_count[i] = __alloc_percpu(prog->pg_vers[i]->vs_nproc *
sizeof(unsigned long),
sizeof(unsigned long));
if (!statp->vs_count[i])
goto err;
}
return 0;
err:
svc_stat_free_counts(statp);
return -ENOMEM;
}
EXPORT_SYMBOL_GPL(svc_stat_alloc_counts);
/**
* svc_stat_free_counts - free per-netns per-version call count arrays
* @statp: svc_stat whose vs_count arrays should be freed
*/
void svc_stat_free_counts(struct svc_stat *statp)
{
struct svc_program *prog = statp->program;
unsigned int i;
if (!statp->vs_count)
return;
for (i = 0; i < prog->pg_nvers; i++)
free_percpu(statp->vs_count[i]);
kfree(statp->vs_count);
statp->vs_count = NULL;
}
EXPORT_SYMBOL_GPL(svc_stat_free_counts);
/*
* Common routine for processing the RPC request.
*/