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 <[email protected]> --- 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

