]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
NFSD: net ref data still needs to be freed even if net hasn't startup
authorEdward Adam Davis <eadavis@qq.com>
Tue, 16 Dec 2025 10:27:37 +0000 (18:27 +0800)
committerChuck Lever <chuck.lever@oracle.com>
Fri, 2 Jan 2026 18:50:14 +0000 (13:50 -0500)
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]
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

BUG: memory leak

Reported-by: syzbot+6ee3b889bdeada0a6226@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=6ee3b889bdeada0a6226
Fixes: 39972494e318 ("nfsd: update percpu_ref to manage references on nfsd_net")
Cc: stable@vger.kernel.org
Signed-off-by: Edward Adam Davis <eadavis@qq.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/nfssvc.c

index f6cae4430ba44fa6d99b9544773c4a19bde569e9..f1cc223ecee2f6ea5bd1d88abf1b0569bc430238 100644 (file)
@@ -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);