* [PATCH v4 0/4] nfsd/sunrpc: convert nfsstat server-side interfaces to use netlink
@ 2026-06-16 12:45 Jeff Layton
2026-06-16 12:45 ` [PATCH v4 1/4] sunrpc: add per-netns per-procedure call counts to svc_stat Jeff Layton
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Jeff Layton @ 2026-06-16 12:45 UTC (permalink / raw)
To: NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey, Chuck Lever
Cc: Trond Myklebust, Anna Schumaker, Steve Dickson, linux-nfs,
linux-kernel, Jeff Layton
This version just fixes an error handling bug that Sashiko noticed.
The nfsstat tool currently scrapes /proc/net/rpc/nfsd for server
statistics. This procfs interface has several limitations: the
counters are global (not network-namespace-aware), the format is
fragile to parse, and it cannot be extended without breaking
existing parsers.
This series adds per-network-namespace procedure call counts to
the sunrpc layer and exposes them through a new netlink handler
in the nfsd generic netlink family, allowing nfsstat to retrieve
server statistics via netlink with a procfs fallback for older
kernels.
Patch 1 adds per-netns per-procedure percpu call count arrays to
struct svc_stat, allocated alongside the nfsd_net lifecycle.
Patch 2 switches svc_seq_show() to read from the per-netns
counters, making /proc/net/rpc/nfsd namespace-aware. Note that this
is a behavior change, but I think it's a desirable one.
Patch 3 implements the server-stats-get netlink dump handler,
streaming reply-cache, filehandle, IO, network, and RPC
statistics plus per-version and per-operation procedure counts.
Patch 4 removes the now-unused global svc_version vs_count
percpu arrays from nfsd, lockd, and the NFS client callback
service.
I'll also be sending an nfs-utils patch to convert nfsstat to use the
new interfaces.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
Changes in v4:
- Ensure error is returned when nla_put_*() calls fail
- Link to v3: https://lore.kernel.org/r/20260609-exportd-netlink-v3-0-aa5508a5bb1d@kernel.org
Changes in v3:
- Only increment per-net stats for the "primary" program
- Link to v2: https://lore.kernel.org/r/20260525-exportd-netlink-v2-0-40003fed450c@kernel.org
---
Jeff Layton (4):
sunrpc: add per-netns per-procedure call counts to svc_stat
sunrpc: use per-net counts in svc_seq_show()
nfsd: implement server-stats-get netlink handler
sunrpc: remove unused svc_version vs_count field
Documentation/netlink/specs/nfsd.yaml | 105 +++++++++++++++++
fs/lockd/svc4proc.c | 4 -
fs/lockd/svcproc.c | 7 --
fs/nfs/callback_xdr.c | 6 -
fs/nfsd/localio.c | 3 -
fs/nfsd/netlink.c | 5 +
fs/nfsd/netlink.h | 2 +
fs/nfsd/nfs2acl.c | 3 -
fs/nfsd/nfs3acl.c | 3 -
fs/nfsd/nfs3proc.c | 3 -
fs/nfsd/nfs4proc.c | 3 -
fs/nfsd/nfsctl.c | 214 +++++++++++++++++++++++++++++++++-
fs/nfsd/nfsproc.c | 3 -
include/linux/sunrpc/stats.h | 6 +
include/linux/sunrpc/svc.h | 1 -
include/uapi/linux/nfsd_netlink.h | 35 ++++++
net/sunrpc/stats.c | 56 ++++++++-
net/sunrpc/svc.c | 9 +-
18 files changed, 428 insertions(+), 40 deletions(-)
---
base-commit: c13952992d5459add7732eb4876eebfeec03af58
change-id: 20260316-exportd-netlink-1c9fb52536e3
Best regards,
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 1/4] sunrpc: add per-netns per-procedure call counts to svc_stat
2026-06-16 12:45 [PATCH v4 0/4] nfsd/sunrpc: convert nfsstat server-side interfaces to use netlink Jeff Layton
@ 2026-06-16 12:45 ` Jeff Layton
2026-06-16 23:55 ` Chuck Lever
2026-06-16 12:45 ` [PATCH v4 2/4] sunrpc: use per-net counts in svc_seq_show() Jeff Layton
` (2 subsequent siblings)
3 siblings, 1 reply; 7+ messages in thread
From: Jeff Layton @ 2026-06-16 12:45 UTC (permalink / raw)
To: NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey, Chuck Lever
Cc: Trond Myklebust, Anna Schumaker, Steve Dickson, linux-nfs,
linux-kernel, Jeff Layton
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: Claude:claude-opus-4-6
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
fs/nfsd/nfsctl.c | 8 ++++++-
include/linux/sunrpc/stats.h | 6 +++++
net/sunrpc/stats.c | 54 ++++++++++++++++++++++++++++++++++++++++++++
net/sunrpc/svc.c | 8 +++++++
4 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index caf59421f8f4..601301e34fc7 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -2514,9 +2514,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++)
@@ -2534,6 +2537,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:
@@ -2574,6 +2579,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);
diff --git a/include/linux/sunrpc/stats.h b/include/linux/sunrpc/stats.h
index 3ce1550d1beb..087ade905e29 100644
--- a/include/linux/sunrpc/stats.h
+++ b/include/linux/sunrpc/stats.h
@@ -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 *);
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index 7093e18ac26c..5bcecd2919b1 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -116,6 +116,60 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp)
}
EXPORT_SYMBOL_GPL(svc_seq_show);
+/**
+ * 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);
+
/**
* rpc_alloc_iostats - allocate an rpc_iostats structure
* @clnt: RPC program, version, and xprt
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index dd80a2eaaa74..f748004835f7 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1438,6 +1438,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:
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 2/4] sunrpc: use per-net counts in svc_seq_show()
2026-06-16 12:45 [PATCH v4 0/4] nfsd/sunrpc: convert nfsstat server-side interfaces to use netlink Jeff Layton
2026-06-16 12:45 ` [PATCH v4 1/4] sunrpc: add per-netns per-procedure call counts to svc_stat Jeff Layton
@ 2026-06-16 12:45 ` Jeff Layton
2026-06-16 12:45 ` [PATCH v4 3/4] nfsd: implement server-stats-get netlink handler Jeff Layton
2026-06-16 12:45 ` [PATCH v4 4/4] sunrpc: remove unused svc_version vs_count field Jeff Layton
3 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2026-06-16 12:45 UTC (permalink / raw)
To: NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey, Chuck Lever
Cc: Trond Myklebust, Anna Schumaker, Steve Dickson, linux-nfs,
linux-kernel, Jeff Layton
Update svc_seq_show() to read from the per-netns
statp->vs_count[] arrays instead of the global
svc_version->vs_count[].
The only caller is nfsd, which always allocates vs_count via
svc_stat_alloc_counts() in nfsd_net_init(), so the per-netns
arrays are always available.
This makes /proc/net/rpc/nfsd report per-network-namespace
procedure call counts.
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
net/sunrpc/stats.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index 5bcecd2919b1..fc2db251dfa0 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -108,7 +108,7 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp)
for (j = 0; j < vers->vs_nproc; j++) {
count = 0;
for_each_possible_cpu(k)
- count += per_cpu(vers->vs_count[j], k);
+ count += per_cpu(statp->vs_count[i][j], k);
seq_printf(seq, " %lu", count);
}
seq_putc(seq, '\n');
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 3/4] nfsd: implement server-stats-get netlink handler
2026-06-16 12:45 [PATCH v4 0/4] nfsd/sunrpc: convert nfsstat server-side interfaces to use netlink Jeff Layton
2026-06-16 12:45 ` [PATCH v4 1/4] sunrpc: add per-netns per-procedure call counts to svc_stat Jeff Layton
2026-06-16 12:45 ` [PATCH v4 2/4] sunrpc: use per-net counts in svc_seq_show() Jeff Layton
@ 2026-06-16 12:45 ` Jeff Layton
2026-06-17 0:57 ` Chuck Lever
2026-06-16 12:45 ` [PATCH v4 4/4] sunrpc: remove unused svc_version vs_count field Jeff Layton
3 siblings, 1 reply; 7+ messages in thread
From: Jeff Layton @ 2026-06-16 12:45 UTC (permalink / raw)
To: NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey, Chuck Lever
Cc: Trond Myklebust, Anna Schumaker, Steve Dickson, linux-nfs,
linux-kernel, Jeff Layton
Implement nfsd_nl_server_stats_get_dumpit() which exposes the
NFS server statistics currently available via /proc/net/rpc/nfsd
through the nfsd generic netlink family.
The handler uses a dump operation to stream statistics across
multiple netlink messages:
- First message: all scalar stats (reply cache, filehandle,
IO, network, RPC) plus per-version procedure counts
(proc2/3/4-ops) using per-netns vs_count arrays.
- Subsequent messages: NFSv4 per-operation counts
(proc4ops-ops), one entry per message, using cb->args[0]
to track the current operation index across dump calls.
This allows nfsstat to retrieve server statistics via netlink
with a procfs fallback for older kernels.
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
Documentation/netlink/specs/nfsd.yaml | 105 +++++++++++++++++
fs/nfsd/netlink.c | 5 +
fs/nfsd/netlink.h | 2 +
fs/nfsd/nfsctl.c | 206 ++++++++++++++++++++++++++++++++++
include/uapi/linux/nfsd_netlink.h | 35 ++++++
5 files changed, 353 insertions(+)
diff --git a/Documentation/netlink/specs/nfsd.yaml b/Documentation/netlink/specs/nfsd.yaml
index 8f36fadd68f7..2a89d355ee7b 100644
--- a/Documentation/netlink/specs/nfsd.yaml
+++ b/Documentation/netlink/specs/nfsd.yaml
@@ -330,6 +330,86 @@ attribute-sets:
of which client holds the state. Intended for use after
all clients have been unexported from a given path,
enabling the underlying filesystem to be unmounted.
+ -
+ name: server-proc-entry
+ attributes:
+ -
+ name: op
+ type: u32
+ -
+ name: count
+ type: u64
+ -
+ name: pad
+ type: pad
+ -
+ name: server-stats
+ attributes:
+ -
+ name: rc-hits
+ type: u64
+ -
+ name: rc-misses
+ type: u64
+ -
+ name: rc-nocache
+ type: u64
+ -
+ name: pad
+ type: pad
+ -
+ name: fh-stale
+ type: u64
+ -
+ name: io-read
+ type: u64
+ -
+ name: io-write
+ type: u64
+ -
+ name: netcnt
+ type: u32
+ -
+ name: netudpcnt
+ type: u32
+ -
+ name: nettcpcnt
+ type: u32
+ -
+ name: nettcpconn
+ type: u32
+ -
+ name: rpccnt
+ type: u32
+ -
+ name: rpcbadfmt
+ type: u32
+ -
+ name: rpcbadauth
+ type: u32
+ -
+ name: rpcbadclnt
+ type: u32
+ -
+ name: proc2-ops
+ type: nest
+ nested-attributes: server-proc-entry
+ multi-attr: true
+ -
+ name: proc3-ops
+ type: nest
+ nested-attributes: server-proc-entry
+ multi-attr: true
+ -
+ name: proc4-ops
+ type: nest
+ nested-attributes: server-proc-entry
+ multi-attr: true
+ -
+ name: proc4ops-ops
+ type: nest
+ nested-attributes: server-proc-entry
+ multi-attr: true
operations:
list:
@@ -516,6 +596,31 @@ operations:
request:
attributes:
- path
+ -
+ name: server-stats-get
+ doc: dump NFS server statistics
+ attribute-set: server-stats
+ dump:
+ reply:
+ attributes:
+ - rc-hits
+ - rc-misses
+ - rc-nocache
+ - fh-stale
+ - io-read
+ - io-write
+ - netcnt
+ - netudpcnt
+ - nettcpcnt
+ - nettcpconn
+ - rpccnt
+ - rpcbadfmt
+ - rpcbadauth
+ - rpcbadclnt
+ - proc2-ops
+ - proc3-ops
+ - proc4-ops
+ - proc4ops-ops
mcast-groups:
list:
diff --git a/fs/nfsd/netlink.c b/fs/nfsd/netlink.c
index fbee3676d253..eba8b353f412 100644
--- a/fs/nfsd/netlink.c
+++ b/fs/nfsd/netlink.c
@@ -225,6 +225,11 @@ static const struct genl_split_ops nfsd_nl_ops[] = {
.maxattr = NFSD_A_UNLOCK_EXPORT_PATH,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
+ {
+ .cmd = NFSD_CMD_SERVER_STATS_GET,
+ .dumpit = nfsd_nl_server_stats_get_dumpit,
+ .flags = GENL_CMD_CAP_DUMP,
+ },
};
static const struct genl_multicast_group nfsd_nl_mcgrps[] = {
diff --git a/fs/nfsd/netlink.h b/fs/nfsd/netlink.h
index af41aa0d4a65..027e2953db26 100644
--- a/fs/nfsd/netlink.h
+++ b/fs/nfsd/netlink.h
@@ -42,6 +42,8 @@ int nfsd_nl_cache_flush_doit(struct sk_buff *skb, struct genl_info *info);
int nfsd_nl_unlock_ip_doit(struct sk_buff *skb, struct genl_info *info);
int nfsd_nl_unlock_filesystem_doit(struct sk_buff *skb, struct genl_info *info);
int nfsd_nl_unlock_export_doit(struct sk_buff *skb, struct genl_info *info);
+int nfsd_nl_server_stats_get_dumpit(struct sk_buff *skb,
+ struct netlink_callback *cb);
enum {
NFSD_NLGRP_NONE,
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 601301e34fc7..f165f0023c70 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -2329,6 +2329,212 @@ int nfsd_nl_cache_flush_doit(struct sk_buff *skb, struct genl_info *info)
return 0;
}
+static int nfsd_nl_fill_proc_ops(struct sk_buff *skb, int attr,
+ unsigned long __percpu *counts,
+ unsigned int nproc)
+{
+ struct nlattr *nest;
+ unsigned int j;
+ int k;
+
+ for (j = 0; j < nproc; j++) {
+ unsigned long count = 0;
+
+ for_each_possible_cpu(k)
+ count += per_cpu(counts[j], k);
+
+ nest = nla_nest_start(skb, attr);
+ if (!nest)
+ return -EMSGSIZE;
+ if (nla_put_u32(skb, NFSD_A_SERVER_PROC_ENTRY_OP, j) ||
+ nla_put_u64_64bit(skb, NFSD_A_SERVER_PROC_ENTRY_COUNT,
+ count, NFSD_A_SERVER_PROC_ENTRY_PAD)) {
+ nla_nest_cancel(skb, nest);
+ return -EMSGSIZE;
+ }
+ nla_nest_end(skb, nest);
+ }
+
+ return 0;
+}
+
+/**
+ * nfsd_nl_server_stats_get_dumpit - dump NFS server statistics
+ * @skb: reply buffer
+ * @cb: netlink metadata and command arguments
+ *
+ * cb->args[0] tracks the current NFSv4 operation index for proc4ops.
+ * A value of 0 means we haven't started yet. We emit all scalar stats
+ * and per-version procedure counts in the first message, then emit
+ * proc4ops entries filling as many as will fit per message.
+ *
+ * Returns the size of the reply or a negative errno.
+ */
+int nfsd_nl_server_stats_get_dumpit(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ struct net *net = sock_net(skb->sk);
+ struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct svc_stat *statp = &nn->nfsd_svcstats;
+ struct svc_program *prog = statp->program;
+ int start = cb->args[0];
+ void *hdr;
+
+ /*
+ * cb->args[0] == 0: first call, emit scalar stats + procN counts
+ * cb->args[0] > 0: emit proc4ops entries starting from args[0] - 1
+ * cb->args[0] < 0: done
+ */
+ if (start < 0)
+ return 0;
+
+ if (start == 0) {
+ hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, &nfsd_nl_family,
+ NLM_F_MULTI, NFSD_CMD_SERVER_STATS_GET);
+ if (!hdr)
+ return -ENOBUFS;
+
+ /* Reply cache stats */
+ {
+ u64 hits, misses, nocache;
+
+ hits = percpu_counter_sum_positive(&nn->counter[NFSD_STATS_RC_HITS]);
+ misses = percpu_counter_sum_positive(&nn->counter[NFSD_STATS_RC_MISSES]);
+ nocache = percpu_counter_sum_positive(&nn->counter[NFSD_STATS_RC_NOCACHE]);
+ if (nla_put_u64_64bit(skb, NFSD_A_SERVER_STATS_RC_HITS,
+ hits, NFSD_A_SERVER_STATS_PAD) ||
+ nla_put_u64_64bit(skb, NFSD_A_SERVER_STATS_RC_MISSES,
+ misses, NFSD_A_SERVER_STATS_PAD) ||
+ nla_put_u64_64bit(skb, NFSD_A_SERVER_STATS_RC_NOCACHE,
+ nocache, NFSD_A_SERVER_STATS_PAD))
+ goto err_cancel;
+ }
+
+ /* Filehandle stats */
+ if (nla_put_u64_64bit(skb, NFSD_A_SERVER_STATS_FH_STALE,
+ percpu_counter_sum_positive(&nn->counter[NFSD_STATS_FH_STALE]),
+ NFSD_A_SERVER_STATS_PAD))
+ goto err_cancel;
+
+ /* IO stats */
+ {
+ u64 rd, wr;
+
+ rd = percpu_counter_sum_positive(&nn->counter[NFSD_STATS_IO_READ]);
+ wr = percpu_counter_sum_positive(&nn->counter[NFSD_STATS_IO_WRITE]);
+ if (nla_put_u64_64bit(skb, NFSD_A_SERVER_STATS_IO_READ,
+ rd, NFSD_A_SERVER_STATS_PAD) ||
+ nla_put_u64_64bit(skb, NFSD_A_SERVER_STATS_IO_WRITE,
+ wr, NFSD_A_SERVER_STATS_PAD))
+ goto err_cancel;
+ }
+
+ /* Network stats */
+ if (nla_put_u32(skb, NFSD_A_SERVER_STATS_NETCNT,
+ statp->netcnt) ||
+ nla_put_u32(skb, NFSD_A_SERVER_STATS_NETUDPCNT,
+ statp->netudpcnt) ||
+ nla_put_u32(skb, NFSD_A_SERVER_STATS_NETTCPCNT,
+ statp->nettcpcnt) ||
+ nla_put_u32(skb, NFSD_A_SERVER_STATS_NETTCPCONN,
+ statp->nettcpconn))
+ goto err_cancel;
+
+ /* RPC stats */
+ if (nla_put_u32(skb, NFSD_A_SERVER_STATS_RPCCNT,
+ statp->rpccnt) ||
+ nla_put_u32(skb, NFSD_A_SERVER_STATS_RPCBADFMT,
+ statp->rpcbadfmt) ||
+ nla_put_u32(skb, NFSD_A_SERVER_STATS_RPCBADAUTH,
+ statp->rpcbadauth) ||
+ nla_put_u32(skb, NFSD_A_SERVER_STATS_RPCBADCLNT,
+ statp->rpcbadclnt))
+ goto err_cancel;
+
+ /* Per-version procedure counts */
+ if (statp->vs_count) {
+ static const int proc_attrs[] = {
+ [2] = NFSD_A_SERVER_STATS_PROC2_OPS,
+ [3] = NFSD_A_SERVER_STATS_PROC3_OPS,
+ [4] = NFSD_A_SERVER_STATS_PROC4_OPS,
+ };
+ unsigned int i;
+
+ for (i = 0; i < prog->pg_nvers &&
+ i < ARRAY_SIZE(proc_attrs); i++) {
+ if (!prog->pg_vers[i] ||
+ !statp->vs_count[i])
+ continue;
+ if (!proc_attrs[i])
+ continue;
+ if (nfsd_nl_fill_proc_ops(skb,
+ proc_attrs[i],
+ statp->vs_count[i],
+ prog->pg_vers[i]->vs_nproc))
+ goto err_cancel;
+ }
+ }
+
+ genlmsg_end(skb, hdr);
+ cb->args[0] = 1;
+ }
+
+#ifdef CONFIG_NFSD_V4
+ /* NFSv4 individual operation counts */
+ {
+ int i = (start > 0) ? start - 1 : 0;
+
+ for (; i <= LAST_NFS4_OP; i++) {
+ struct percpu_counter *ctr;
+ struct nlattr *nest;
+ u64 cnt;
+
+ ctr = &nn->counter[NFSD_STATS_NFS4_OP(i)];
+ cnt = percpu_counter_sum_positive(ctr);
+
+ hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ &nfsd_nl_family, NLM_F_MULTI,
+ NFSD_CMD_SERVER_STATS_GET);
+ if (!hdr) {
+ cb->args[0] = i + 1;
+ goto out;
+ }
+
+ nest = nla_nest_start(skb,
+ NFSD_A_SERVER_STATS_PROC4OPS_OPS);
+ if (!nest) {
+ genlmsg_cancel(skb, hdr);
+ cb->args[0] = i + 1;
+ goto out;
+ }
+ if (nla_put_u32(skb, NFSD_A_SERVER_PROC_ENTRY_OP,
+ i) ||
+ nla_put_u64_64bit(skb,
+ NFSD_A_SERVER_PROC_ENTRY_COUNT,
+ cnt,
+ NFSD_A_SERVER_PROC_ENTRY_PAD)) {
+ nla_nest_cancel(skb, nest);
+ genlmsg_cancel(skb, hdr);
+ cb->args[0] = i + 1;
+ goto out;
+ }
+ nla_nest_end(skb, nest);
+ genlmsg_end(skb, hdr);
+ }
+ }
+#endif
+
+ cb->args[0] = -1;
+out:
+ return skb->len;
+
+err_cancel:
+ genlmsg_cancel(skb, hdr);
+ return -EMSGSIZE;
+}
+
int nfsd_cache_notify(struct cache_detail *cd, struct cache_head *h, u32 cache_type)
{
struct genlmsghdr *hdr;
diff --git a/include/uapi/linux/nfsd_netlink.h b/include/uapi/linux/nfsd_netlink.h
index f5b75d5caba9..3d076d173b1d 100644
--- a/include/uapi/linux/nfsd_netlink.h
+++ b/include/uapi/linux/nfsd_netlink.h
@@ -225,6 +225,40 @@ enum {
NFSD_A_UNLOCK_EXPORT_MAX = (__NFSD_A_UNLOCK_EXPORT_MAX - 1)
};
+enum {
+ NFSD_A_SERVER_PROC_ENTRY_OP = 1,
+ NFSD_A_SERVER_PROC_ENTRY_COUNT,
+ NFSD_A_SERVER_PROC_ENTRY_PAD,
+
+ __NFSD_A_SERVER_PROC_ENTRY_MAX,
+ NFSD_A_SERVER_PROC_ENTRY_MAX = (__NFSD_A_SERVER_PROC_ENTRY_MAX - 1)
+};
+
+enum {
+ NFSD_A_SERVER_STATS_RC_HITS = 1,
+ NFSD_A_SERVER_STATS_RC_MISSES,
+ NFSD_A_SERVER_STATS_RC_NOCACHE,
+ NFSD_A_SERVER_STATS_PAD,
+ NFSD_A_SERVER_STATS_FH_STALE,
+ NFSD_A_SERVER_STATS_IO_READ,
+ NFSD_A_SERVER_STATS_IO_WRITE,
+ NFSD_A_SERVER_STATS_NETCNT,
+ NFSD_A_SERVER_STATS_NETUDPCNT,
+ NFSD_A_SERVER_STATS_NETTCPCNT,
+ NFSD_A_SERVER_STATS_NETTCPCONN,
+ NFSD_A_SERVER_STATS_RPCCNT,
+ NFSD_A_SERVER_STATS_RPCBADFMT,
+ NFSD_A_SERVER_STATS_RPCBADAUTH,
+ NFSD_A_SERVER_STATS_RPCBADCLNT,
+ NFSD_A_SERVER_STATS_PROC2_OPS,
+ NFSD_A_SERVER_STATS_PROC3_OPS,
+ NFSD_A_SERVER_STATS_PROC4_OPS,
+ NFSD_A_SERVER_STATS_PROC4OPS_OPS,
+
+ __NFSD_A_SERVER_STATS_MAX,
+ NFSD_A_SERVER_STATS_MAX = (__NFSD_A_SERVER_STATS_MAX - 1)
+};
+
enum {
NFSD_CMD_RPC_STATUS_GET = 1,
NFSD_CMD_THREADS_SET,
@@ -244,6 +278,7 @@ enum {
NFSD_CMD_UNLOCK_IP,
NFSD_CMD_UNLOCK_FILESYSTEM,
NFSD_CMD_UNLOCK_EXPORT,
+ NFSD_CMD_SERVER_STATS_GET,
__NFSD_CMD_MAX,
NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1)
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 4/4] sunrpc: remove unused svc_version vs_count field
2026-06-16 12:45 [PATCH v4 0/4] nfsd/sunrpc: convert nfsstat server-side interfaces to use netlink Jeff Layton
` (2 preceding siblings ...)
2026-06-16 12:45 ` [PATCH v4 3/4] nfsd: implement server-stats-get netlink handler Jeff Layton
@ 2026-06-16 12:45 ` Jeff Layton
3 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2026-06-16 12:45 UTC (permalink / raw)
To: NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey, Chuck Lever
Cc: Trond Myklebust, Anna Schumaker, Steve Dickson, linux-nfs,
linux-kernel, Jeff Layton
Now that svc_seq_show() and the nfsd netlink stats handler both use
the per-netns svc_stat vs_count arrays, the global per-version
vs_count percpu counters are no longer read by anything. Remove the
vs_count field from struct svc_version and all the associated
DEFINE_PER_CPU_ALIGNED arrays and initializers across nfsd, lockd,
and the NFS client callback service.
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
fs/lockd/svc4proc.c | 4 ----
fs/lockd/svcproc.c | 7 -------
fs/nfs/callback_xdr.c | 6 ------
fs/nfsd/localio.c | 3 ---
fs/nfsd/nfs2acl.c | 3 ---
fs/nfsd/nfs3acl.c | 3 ---
fs/nfsd/nfs3proc.c | 3 ---
fs/nfsd/nfs4proc.c | 3 ---
fs/nfsd/nfsproc.c | 3 ---
include/linux/sunrpc/svc.h | 1 -
net/sunrpc/svc.c | 3 ---
11 files changed, 39 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 080dffce9d8e..c096c0c0cf60 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -1420,14 +1420,10 @@ union nlm4svc_xdrstore {
struct nlm4_shareres_wrapper shareres;
};
-static DEFINE_PER_CPU_ALIGNED(unsigned long,
- nlm4svc_call_counters[ARRAY_SIZE(nlm4svc_procedures)]);
-
const struct svc_version nlmsvc_version4 = {
.vs_vers = 4,
.vs_nproc = ARRAY_SIZE(nlm4svc_procedures),
.vs_proc = nlm4svc_procedures,
- .vs_count = nlm4svc_call_counters,
.vs_dispatch = nlmsvc_dispatch,
.vs_xdrsize = sizeof(union nlm4svc_xdrstore),
};
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index dce6f6e3fd40..07f65a03f300 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -1433,25 +1433,18 @@ union nlmsvc_xdrstore {
* NLMv1 defines only procedures 1 - 15. Linux lockd also implements
* procedures 0 (NULL) and 16 (SM_NOTIFY).
*/
-static DEFINE_PER_CPU_ALIGNED(unsigned long, nlm1svc_call_counters[17]);
-
const struct svc_version nlmsvc_version1 = {
.vs_vers = 1,
.vs_nproc = 17,
.vs_proc = nlmsvc_procedures,
- .vs_count = nlm1svc_call_counters,
.vs_dispatch = nlmsvc_dispatch,
.vs_xdrsize = sizeof(union nlmsvc_xdrstore),
};
-static DEFINE_PER_CPU_ALIGNED(unsigned long,
- nlm3svc_call_counters[ARRAY_SIZE(nlmsvc_procedures)]);
-
const struct svc_version nlmsvc_version3 = {
.vs_vers = 3,
.vs_nproc = ARRAY_SIZE(nlmsvc_procedures),
.vs_proc = nlmsvc_procedures,
- .vs_count = nlm3svc_call_counters,
.vs_dispatch = nlmsvc_dispatch,
.vs_xdrsize = sizeof(union nlmsvc_xdrstore),
};
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 4382baddc9ee..eec6040556c9 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -1090,26 +1090,20 @@ static const struct svc_procedure nfs4_callback_procedures1[] = {
}
};
-static DEFINE_PER_CPU_ALIGNED(unsigned long,
- nfs4_callback_count1[ARRAY_SIZE(nfs4_callback_procedures1)]);
const struct svc_version nfs4_callback_version1 = {
.vs_vers = 1,
.vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
.vs_proc = nfs4_callback_procedures1,
- .vs_count = nfs4_callback_count1,
.vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
.vs_dispatch = nfs_callback_dispatch,
.vs_hidden = true,
.vs_need_cong_ctrl = true,
};
-static DEFINE_PER_CPU_ALIGNED(unsigned long,
- nfs4_callback_count4[ARRAY_SIZE(nfs4_callback_procedures1)]);
const struct svc_version nfs4_callback_version4 = {
.vs_vers = 4,
.vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
.vs_proc = nfs4_callback_procedures1,
- .vs_count = nfs4_callback_count4,
.vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
.vs_dispatch = nfs_callback_dispatch,
.vs_hidden = true,
diff --git a/fs/nfsd/localio.c b/fs/nfsd/localio.c
index c3eb0557b3e1..c458c01e9478 100644
--- a/fs/nfsd/localio.c
+++ b/fs/nfsd/localio.c
@@ -210,14 +210,11 @@ static const struct svc_procedure localio_procedures1[] = {
};
#define LOCALIO_NR_PROCEDURES ARRAY_SIZE(localio_procedures1)
-static DEFINE_PER_CPU_ALIGNED(unsigned long,
- localio_count[LOCALIO_NR_PROCEDURES]);
const struct svc_version localio_version1 = {
.vs_vers = 1,
.vs_nproc = LOCALIO_NR_PROCEDURES,
.vs_proc = localio_procedures1,
.vs_dispatch = nfsd_dispatch,
- .vs_count = localio_count,
.vs_xdrsize = XDR_QUADLEN(UUID_SIZE),
.vs_hidden = true,
};
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 827f90194c43..0fd6d9def3b4 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -389,13 +389,10 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = {
},
};
-static DEFINE_PER_CPU_ALIGNED(unsigned long,
- nfsd_acl_count2[ARRAY_SIZE(nfsd_acl_procedures2)]);
const struct svc_version nfsd_acl_version2 = {
.vs_vers = 2,
.vs_nproc = ARRAY_SIZE(nfsd_acl_procedures2),
.vs_proc = nfsd_acl_procedures2,
- .vs_count = nfsd_acl_count2,
.vs_dispatch = nfsd_dispatch,
.vs_xdrsize = NFS3_SVC_XDRSIZE,
};
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index a87f9d7f32be..6b6b289db636 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -278,13 +278,10 @@ static const struct svc_procedure nfsd_acl_procedures3[3] = {
},
};
-static DEFINE_PER_CPU_ALIGNED(unsigned long,
- nfsd_acl_count3[ARRAY_SIZE(nfsd_acl_procedures3)]);
const struct svc_version nfsd_acl_version3 = {
.vs_vers = 3,
.vs_nproc = ARRAY_SIZE(nfsd_acl_procedures3),
.vs_proc = nfsd_acl_procedures3,
- .vs_count = nfsd_acl_count3,
.vs_dispatch = nfsd_dispatch,
.vs_xdrsize = NFS3_SVC_XDRSIZE,
};
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index aeda7a802bdf..2d5ab2178702 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -1068,13 +1068,10 @@ static const struct svc_procedure nfsd_procedures3[22] = {
},
};
-static DEFINE_PER_CPU_ALIGNED(unsigned long,
- nfsd_count3[ARRAY_SIZE(nfsd_procedures3)]);
const struct svc_version nfsd_version3 = {
.vs_vers = 3,
.vs_nproc = ARRAY_SIZE(nfsd_procedures3),
.vs_proc = nfsd_procedures3,
.vs_dispatch = nfsd_dispatch,
- .vs_count = nfsd_count3,
.vs_xdrsize = NFS3_SVC_XDRSIZE,
};
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 3e4de45aa360..fbfa69cb9dcc 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -4151,13 +4151,10 @@ static const struct svc_procedure nfsd_procedures4[2] = {
},
};
-static DEFINE_PER_CPU_ALIGNED(unsigned long,
- nfsd_count4[ARRAY_SIZE(nfsd_procedures4)]);
const struct svc_version nfsd_version4 = {
.vs_vers = 4,
.vs_nproc = ARRAY_SIZE(nfsd_procedures4),
.vs_proc = nfsd_procedures4,
- .vs_count = nfsd_count4,
.vs_dispatch = nfsd_dispatch,
.vs_xdrsize = NFS4_SVC_XDRSIZE,
.vs_rpcb_optnl = true,
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index a73d5c259cd9..b8421cde795a 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -845,13 +845,10 @@ static const struct svc_procedure nfsd_procedures2[18] = {
},
};
-static DEFINE_PER_CPU_ALIGNED(unsigned long,
- nfsd_count2[ARRAY_SIZE(nfsd_procedures2)]);
const struct svc_version nfsd_version2 = {
.vs_vers = 2,
.vs_nproc = ARRAY_SIZE(nfsd_procedures2),
.vs_proc = nfsd_procedures2,
- .vs_count = nfsd_count2,
.vs_dispatch = nfsd_dispatch,
.vs_xdrsize = NFS2_SVC_XDRSIZE,
};
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 3a0152d926fb..34490c0ba88c 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -408,7 +408,6 @@ struct svc_version {
u32 vs_vers; /* version number */
u32 vs_nproc; /* number of procedures */
const struct svc_procedure *vs_proc; /* per-procedure info */
- unsigned long __percpu *vs_count; /* call counts */
u32 vs_xdrsize; /* xdrsize needed for this version */
/* Don't register with rpcbind */
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index f748004835f7..dce268d8ec8e 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1435,9 +1435,6 @@ svc_generic_init_request(struct svc_rqst *rqstp,
memset(rqstp->rq_argp, 0, procp->pc_argzero);
memset(rqstp->rq_resp, 0, procp->pc_ressize);
- /* 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 &&
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v4 1/4] sunrpc: add per-netns per-procedure call counts to svc_stat
2026-06-16 12:45 ` [PATCH v4 1/4] sunrpc: add per-netns per-procedure call counts to svc_stat Jeff Layton
@ 2026-06-16 23:55 ` Chuck Lever
0 siblings, 0 replies; 7+ messages in thread
From: Chuck Lever @ 2026-06-16 23:55 UTC (permalink / raw)
To: Jeff Layton, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: Trond Myklebust, Anna Schumaker, Steve Dickson, linux-nfs,
linux-kernel
Hey Jeff -
On Tue, Jun 16, 2026, at 8:45 AM, Jeff Layton wrote:
> 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.
This patch appears to break the build for an NFSv3-only server
configured with CONFIG_PROC_FS=n.
svc_stat_alloc_counts() and svc_stat_free_counts() are defined in
net/sunrpc/stats.c, which the Makefile builds only under PROC_FS:
sunrpc-$(CONFIG_PROC_FS) += stats.o
nfsd_net_init()/nfsd_net_exit() call both helpers unconditionally,
and the declarations in <linux/sunrpc/stats.h> sit outside the
#ifdef CONFIG_PROC_FS block with no !PROC_FS stubs. CONFIG_NFSD does
not depend on PROC_FS -- only NFSD_V4 does -- so NFSD=y with
NFSD_V2/V3 and PROC_FS=n is a valid Kconfig combination. The result
is an undefined reference to svc_stat_alloc_counts at vmlinux link
(NFSD=y), or a modpost failure for NFSD=m since both symbols are
EXPORT_SYMBOL_GPL.
net/sunrpc/svc.c is always built, and might be a more natural home
for the new functions.
--
Chuck Lever
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 3/4] nfsd: implement server-stats-get netlink handler
2026-06-16 12:45 ` [PATCH v4 3/4] nfsd: implement server-stats-get netlink handler Jeff Layton
@ 2026-06-17 0:57 ` Chuck Lever
0 siblings, 0 replies; 7+ messages in thread
From: Chuck Lever @ 2026-06-17 0:57 UTC (permalink / raw)
To: Jeff Layton, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: Trond Myklebust, Anna Schumaker, Steve Dickson, linux-nfs,
linux-kernel
Hey Jeff -
On Tue, Jun 16, 2026, at 8:45 AM, Jeff Layton wrote:
> Implement nfsd_nl_server_stats_get_dumpit() which exposes the
> NFS server statistics currently available via /proc/net/rpc/nfsd
> through the nfsd generic netlink family.
>
> The handler uses a dump operation to stream statistics across
> multiple netlink messages:
>
> - First message: all scalar stats (reply cache, filehandle,
> IO, network, RPC) plus per-version procedure counts
> (proc2/3/4-ops) using per-netns vs_count arrays.
>
> - Subsequent messages: NFSv4 per-operation counts
> (proc4ops-ops), one entry per message, using cb->args[0]
> to track the current operation index across dump calls.
>
> This allows nfsstat to retrieve server statistics via netlink
> with a procfs fallback for older kernels.
>
> Assisted-by: Claude:claude-opus-4-6
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
> Documentation/netlink/specs/nfsd.yaml | 105 +++++++++++++++++
> fs/nfsd/netlink.c | 5 +
> fs/nfsd/netlink.h | 2 +
> fs/nfsd/nfsctl.c | 206 ++++++++++++++++++++++++++++++++++
> include/uapi/linux/nfsd_netlink.h | 35 ++++++
> 5 files changed, 353 insertions(+)
The procfs output in nfsd_show() emits one more counter that this dump
handler drops: wdeleg_getattr (NFSD_STATS_WDELEG_GETATTR), printed at
the end of the CONFIG_NFSD_V4 block in fs/nfsd/stats.c, right after
proc4ops. The netlink dump stops after proc4ops-ops and sets
cb->args[0] = -1, so the write-delegation GETATTR-conflict counter never
goes out on the wire.
There's no schema slot for it either: the server-stats attribute-set
ends at proc4ops-ops, so a consumer that prefers netlink and only falls
back to procfs on an old kernel loses this counter on every kernel new
enough to support server-stats-get.
I Suggest:
- add a wdeleg-getattr (u64) attribute to the server-stats
attribute-set in nfsd.yaml and list it under the dump reply
attributes;
- add NFSD_A_SERVER_STATS_WDELEG_GETATTR to the uapi enum, after
PROC4OPS_OPS and before __NFSD_A_SERVER_STATS_MAX so existing
values don't shift;
- emit it as a single scalar in the start == 0 message, wrapped in
CONFIG_NFSD_V4 to match the procfs side.
--
Chuck Lever
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-06-17 0:57 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-16 12:45 [PATCH v4 0/4] nfsd/sunrpc: convert nfsstat server-side interfaces to use netlink Jeff Layton
2026-06-16 12:45 ` [PATCH v4 1/4] sunrpc: add per-netns per-procedure call counts to svc_stat Jeff Layton
2026-06-16 23:55 ` Chuck Lever
2026-06-16 12:45 ` [PATCH v4 2/4] sunrpc: use per-net counts in svc_seq_show() Jeff Layton
2026-06-16 12:45 ` [PATCH v4 3/4] nfsd: implement server-stats-get netlink handler Jeff Layton
2026-06-17 0:57 ` Chuck Lever
2026-06-16 12:45 ` [PATCH v4 4/4] sunrpc: remove unused svc_version vs_count field Jeff Layton
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.