Thread (15 messages) flat view 15 messages, 2 authors, 22d ago
COLD22d

[PATCH v2 4/8] SUNRPC: undo partial rpcbind registrations when svc_register() fails

From: Jeff Layton <jlayton@kernel.org>
Date: 2026-08-11 12:03:18
Also in: linux-kselftest, linux-nfs, lkml
Subsystem: kernel nfsd, sunrpc, and lockd servers, networking [general], nfs, sunrpc, and lockd clients, the rest · Maintainers: Chuck Lever, Jeff Layton, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Trond Myklebust, Anna Schumaker, Linus Torvalds

svc_register() registers each [program, version] in turn. On failure the
caller tears the listener down -- svc_setup_socket() frees the svc_sock and
svc_create_socket() releases the socket -- but the entries that were already
set stay in rpcbind, now pointing at a closed port. XPT_RPCB_UNREG is set
later, in svc_udp_init()/svc_tcp_init(), so svc_delete_xprt() never runs for
this transport and nothing clears them.

Unwind on failure, and stop the walk there rather than registering the
programs after it. rpcbind matches RPCBPROC_UNSET on
[program, version, netid] and ignores the address, so the unwind clears the
netid, not just the port -- the same granularity svc_delete_xprt() already
unregisters at.

Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 net/sunrpc/svc.c | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 4f402bbf97ba..9ffa87007004 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1183,6 +1183,29 @@ int svc_generic_rpcbind_set(struct net *net,
 }
 EXPORT_SYMBOL_GPL(svc_generic_rpcbind_set);
 
+/*
+ * Undo the [program, version] registrations that this svc_register() call
+ * already made, stopping at version @nvers of program @nprog.
+ *
+ * Note that rpcbind matches RPCBPROC_UNSET on [program, version, netid] and
+ * ignores the address, so this clears the netid rather than the one port.
+ * That is the granularity svc_delete_xprt() unregisters at as well.
+ */
+static void svc_unwind_register(const struct svc_serv *serv, struct net *net,
+				const int family, const unsigned short proto,
+				unsigned int nprog, unsigned int nvers)
+{
+	unsigned int p, i;
+
+	for (p = 0; p <= nprog; p++) {
+		struct svc_program *progp = &serv->sv_programs[p];
+		unsigned int last = p < nprog ? progp->pg_nvers : nvers;
+
+		for (i = 0; i < last; i++)
+			progp->pg_rpcbind_set(net, progp, i, family, proto, 0);
+	}
+}
+
 /**
  * svc_register - register an RPC service with the local portmapper
  * @serv: svc_serv struct for the service to register
@@ -1191,7 +1214,8 @@ EXPORT_SYMBOL_GPL(svc_generic_rpcbind_set);
  * @proto: transport protocol number to advertise
  * @port: port to advertise
  *
- * Service is registered for any address in the passed-in protocol family
+ * Service is registered for any address in the passed-in protocol family.
+ * A @port of 0 unregisters instead, and then every program is attempted.
  */
 int svc_register(const struct svc_serv *serv, struct net *net,
 		 const int family, const unsigned short proto,
@@ -1216,6 +1240,11 @@ int svc_register(const struct svc_serv *serv, struct net *net,
 				printk(KERN_WARNING "svc: failed to register "
 					"%sv%u RPC service (errno %d).\n",
 					progp->pg_name, i, -ret);
+				if (port) {
+					svc_unwind_register(serv, net, family,
+							    proto, p, i);
+					return ret;
+				}
 				if (!error)
 					error = ret;
 				break;
-- 
2.55.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help