Commit 0b88bfa4 authored by Edward Adam Davis's avatar Edward Adam Davis Committed by Chuck Lever
Browse files

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



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: default avatar <syzbot+6ee3b889bdeada0a6226@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/bug?extid=6ee3b889bdeada0a6226


Fixes: 39972494 ("nfsd: update percpu_ref to manage references on nfsd_net")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarEdward Adam Davis <eadavis@qq.com>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent d0424066
Loading
Loading
Loading
Loading
+15 −15
Original line number Diff line number Diff line
@@ -406,9 +406,7 @@ static void nfsd_shutdown_net(struct net *net)
{
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);

	if (!nn->nfsd_net_up)
		return;

	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);

@@ -420,12 +418,14 @@ static void nfsd_shutdown_net(struct net *net)
			lockd_down(net);
			nn->lockd_up = false;
		}

		wait_for_completion(&nn->nfsd_net_free_done);
	}

	percpu_ref_exit(&nn->nfsd_net_ref);

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

static DEFINE_SPINLOCK(nfsd_notifier_lock);