[PATCH v1 1/3] nfsd: report NFSv4 grace state through Netlink
From: Prabhakar Pujeri
Date: Tue Aug 25 2026 - 02:54:22 EST
Operational tooling needs to distinguish a server that is accepting
normal NFSv4 state operations from one that is still accepting only
recovery requests. The existing Netlink threads query reports
server-wide configuration, but recovery state is available only through
the nfsd filesystem.
Add an in-grace value to the threads-get reply. Return it in every reply
so user space can distinguish a server that is not in grace from an older
kernel that does not provide the attribute.
Signed-off-by: Prabhakar Pujeri <prabhakar.pujeri@xxxxxxxx>
---
Documentation/admin-guide/nfs/nfsd-admin-interfaces.rst | 3 +++
Documentation/netlink/specs/nfsd.yaml | 6 ++++++
fs/nfsd/nfsctl.c | 9 ++++++++-
include/uapi/linux/nfsd_netlink.h | 1 +
4 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/Documentation/admin-guide/nfs/nfsd-admin-interfaces.rst b/Documentation/admin-guide/nfs/nfsd-admin-interfaces.rst
index c05926f79054..35c174000ab3 100644
--- a/Documentation/admin-guide/nfs/nfsd-admin-interfaces.rst
+++ b/Documentation/admin-guide/nfs/nfsd-admin-interfaces.rst
@@ -25,6 +25,9 @@ udp and one tcp listener at port 2049 (see nfsd_init_socks).
On startup, nfsd and lockd grace periods start. nfsd is shut down by a write of
0 to nfsd/threads. All locks and state are thrown away at that point.
+The ``in-grace`` value in the ``threads-get`` Generic Netlink reply reports
+whether the NFSv4 server's recovery grace period is still active.
+
Between startup and shutdown, the number of threads may be adjusted up
or down by additional writes to nfsd/threads or by writes to
nfsd/pool_threads.
diff --git a/Documentation/netlink/specs/nfsd.yaml b/Documentation/netlink/specs/nfsd.yaml
index 642268819c6f..d01d93f39392 100644
--- a/Documentation/netlink/specs/nfsd.yaml
+++ b/Documentation/netlink/specs/nfsd.yaml
@@ -130,6 +130,11 @@ attribute-sets:
type: binary
checks:
exact-len: 16
+ -
+ name: in-grace
+ type: u8
+ doc: One while the NFSv4 server is in its recovery grace period,
+ otherwise zero.
-
name: version
attributes:
@@ -464,6 +469,7 @@ operations:
- leasetime
- scope
- min-threads
+ - in-grace
-
name: version-set
doc: set nfs enabled versions
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 6e63950a99e1..7ea865b372cc 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -1775,6 +1775,7 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)
{
struct net *net = genl_info_net(info);
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ bool in_grace = false;
void *hdr;
int err;
@@ -1790,6 +1791,11 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)
mutex_lock(&nfsd_mutex);
+#ifdef CONFIG_NFSD_V4
+ in_grace = nfsd_vers(nn, 4, NFSD_TEST) &&
+ test_bit(NFSD_NET_UP, &nn->flags) &&
+ !test_bit(NFSD_NET_GRACE_ENDED, &nn->flags);
+#endif
err = nla_put_u32(skb, NFSD_A_SERVER_GRACETIME,
nn->nfsd4_grace) ||
nla_put_u32(skb, NFSD_A_SERVER_LEASETIME,
@@ -1797,7 +1803,8 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)
nla_put_u32(skb, NFSD_A_SERVER_MIN_THREADS,
nn->min_threads) ||
nla_put_string(skb, NFSD_A_SERVER_SCOPE,
- nn->nfsd_name);
+ nn->nfsd_name) ||
+ nla_put_u8(skb, NFSD_A_SERVER_IN_GRACE, in_grace);
if (err)
goto err_unlock;
diff --git a/include/uapi/linux/nfsd_netlink.h b/include/uapi/linux/nfsd_netlink.h
index 87da1d0bb21e..e1fc2db00046 100644
--- a/include/uapi/linux/nfsd_netlink.h
+++ b/include/uapi/linux/nfsd_netlink.h
@@ -84,6 +84,7 @@ enum {
NFSD_A_SERVER_SCOPE,
NFSD_A_SERVER_MIN_THREADS,
NFSD_A_SERVER_FH_KEY,
+ NFSD_A_SERVER_IN_GRACE,
__NFSD_A_SERVER_MAX,
NFSD_A_SERVER_MAX = (__NFSD_A_SERVER_MAX - 1)
--
2.54.0