[PATCH] NFSD: net ref data still needs to be freed even if net hasn't startup

Edward Adam Davis
2025-12-16T10:27:48Z

When the NFSD instance doesn't to startup, the net ref data memory is
not properly reclaimed, which triggers the memory leak issue reported
by syzbot [1].

To avoid the problem reported in [1], the net ref data memory reclamation
action is moved outside of nfsd_net_up when the net is shutdown.

[1]
BUG: memory leak
unreferenced object 0xffff88812a39dfc0 (size 64):
backtrace (crc a2262fc6):
percpu_ref_init+0x94/0x1e0 lib/percpu-refcount.c:76
nfsd_create_serv+0xbe/0x260 fs/nfsd/nfssvc.c:605
nfsd_nl_listener_set_doit+0x62/0xb00 fs/nfsd/nfsctl.c:1882
genl_family_rcv_msg_doit+0x11e/0x190 net/netlink/genetlink.c:1115
genl_family_rcv_msg net/netlink/genetlink.c:1195 [inline]
genl_rcv_msg+0x2fd/0x440 net/netlink/genetlink.c:1210

Reported-by: syzbot+6ee3b889bdeada0a6226@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=6ee3b889bdeada0a6226
Signed-off-by: Edward Adam Davis <eadavis@qq.com>
---
fs/nfsd/nfssvc.c | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index b08ae85d53ef..e2b2cf0dd013 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -406,26 +406,26 @@ static void nfsd_shutdown_net(struct net *net)
{
struct nfsd_net *nn = net_generic(net, nfsd_net_id);

- if (!nn->nfsd_net_up)
- return;
-
- percpu_ref_kill_and_confirm(&nn->nfsd_net_ref, nfsd_net_done);
- wait_for_completion(&nn->nfsd_net_confirm_done);
-
- nfsd_export_flush(net);
- nfs4_state_shutdown_net(net);
- nfsd_reply_cache_shutdown(nn);
- nfsd_file_cache_shutdown_net(net);
- if (nn->lockd_up) {
- lockd_down(net);
- nn->lockd_up = false;
+ if (nn->nfsd_net_up) {
+ percpu_ref_kill_and_confirm(&nn->nfsd_net_ref, nfsd_net_done);
+ wait_for_completion(&nn->nfsd_net_confirm_done);
+
+ nfsd_export_flush(net);
+ nfs4_state_shutdown_net(net);
+ nfsd_reply_cache_shutdown(nn);
+ nfsd_file_cache_shutdown_net(net);
+ if (nn->lockd_up) {
+ lockd_down(net);
+ nn->lockd_up = false;
+ }
+ wait_for_completion(&nn->nfsd_net_free_done);
}

- wait_for_completion(&nn->nfsd_net_free_done);
percpu_ref_exit(&nn->nfsd_net_ref);

+ if (nn->nfsd_net_up)
+ nfsd_shutdown_generic();
nn->nfsd_net_up = false;
- nfsd_shutdown_generic();
}

static DEFINE_SPINLOCK(nfsd_notifier_lock);
--
2.43.0