lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250317-rpc-shutdown-v1-5-85ba8e20b75d@kernel.org>
Date: Mon, 17 Mar 2025 16:59:57 -0400
From: Jeff Layton <jlayton@...nel.org>
To: Trond Myklebust <trondmy@...nel.org>, Anna Schumaker <anna@...nel.org>, 
 Chuck Lever <chuck.lever@...cle.com>, Neil Brown <neilb@...e.de>, 
 Olga Kornievskaia <okorniev@...hat.com>, Dai Ngo <Dai.Ngo@...cle.com>, 
 Tom Talpey <tom@...pey.com>, "David S. Miller" <davem@...emloft.net>, 
 Eric Dumazet <edumazet@...gle.com>, Jakub Kicinski <kuba@...nel.org>, 
 Paolo Abeni <pabeni@...hat.com>, Simon Horman <horms@...nel.org>
Cc: Josef Bacik <josef@...icpanda.com>, 
 Benjamin Coddington <bcodding@...hat.com>, linux-nfs@...r.kernel.org, 
 linux-kernel@...r.kernel.org, netdev@...r.kernel.org, 
 Jeff Layton <jlayton@...nel.org>
Subject: [PATCH RFC 5/9] nfs: don't hold a reference to struct net in
 struct nfs_client

An NFS client holds a reference to the net namespace. This can cause
nfs_clients to stick around after a container dies spontaneously.

The container orchestrator sees that there are no more tasks in the
container, detaches the filesystems and tears down the networking.
Unfortunately, there can still be RPCs in flight that will end up
attempting to retransmit indefinitely. No userland tasks have a way
to reach that net namespace any longer though, so there is no hope of it
being rescued.

Instead of keeping a net reference in struct nfs_client, add a nfs_net
pre_exit routine that kills off the nfs_server and any remaining
nfs_clients, and then waits for the nfs_client_list to go empty.

Signed-off-by: Jeff Layton <jlayton@...nel.org>
---
 fs/nfs/client.c |  6 ++++--
 fs/nfs/inode.c  | 28 ++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 3b0918ade53cd331d76baaa86fd2adec5d945b78..8f41cb88f88c2b4d7f10424484b6e70ac2b8835a 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -180,7 +180,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
 	clp->cl_proto = cl_init->proto;
 	clp->cl_nconnect = cl_init->nconnect;
 	clp->cl_max_connect = cl_init->max_connect ? cl_init->max_connect : 1;
-	clp->cl_net = get_net(cl_init->net);
+	clp->cl_net = cl_init->net;
 
 #if IS_ENABLED(CONFIG_NFS_LOCALIO)
 	seqlock_init(&clp->cl_boot_lock);
@@ -244,13 +244,15 @@ static void pnfs_init_server(struct nfs_server *server)
  */
 void nfs_free_client(struct nfs_client *clp)
 {
+	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
+
 	nfs_localio_disable_client(clp);
 
 	/* -EIO all pending I/O */
 	if (!IS_ERR(clp->cl_rpcclient))
 		rpc_shutdown_client(clp->cl_rpcclient);
 
-	put_net(clp->cl_net);
+	wake_up_var(&nn->nfs_client_list);
 	put_nfs_version(clp->cl_nfs_mod);
 	kfree(clp->cl_hostname);
 	kfree(clp->cl_acceptor);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 1aa67fca69b2fbd8afb1c51be78198220b1e13c7..0352e7e6ee270562a971d031ba02bdec96496288 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -2562,9 +2562,37 @@ static void nfs_net_exit(struct net *net)
 	nfs_clients_exit(net);
 }
 
+static bool all_clients_gone(struct nfs_net *nn)
+{
+	bool	gone;
+
+	spin_lock(&nn->nfs_client_lock);
+	gone = list_empty(&nn->nfs_client_list);
+	spin_unlock(&nn->nfs_client_lock);
+
+	return gone;
+}
+
+static void nfs_net_pre_exit(struct net *net)
+{
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+	struct nfs_server *server;
+	struct nfs_client *clp;
+
+	spin_lock(&nn->nfs_client_lock);
+	list_for_each_entry(server, &nn->nfs_volume_list, master_link)
+		nfs_server_shutdown(server);
+	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link)
+		rpc_clnt_shutdown(clp->cl_rpcclient);
+	spin_unlock(&nn->nfs_client_lock);
+
+	wait_var_event(&nn->nfs_client_list, all_clients_gone(nn));
+}
+
 static struct pernet_operations nfs_net_ops = {
 	.init = nfs_net_init,
 	.exit = nfs_net_exit,
+	.pre_exit = nfs_net_pre_exit,
 	.id   = &nfs_net_id,
 	.size = sizeof(struct nfs_net),
 };

-- 
2.48.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ