* [PATCH 6.1.y 2/4] svcrdma: Refactor the creation of listener CMA ID
2026-09-09 1:31 ` [PATCH 6.1.y 1/4] svcrdma: Allocate new transports on device's NUMA node Sasha Levin
@ 2026-09-09 1:31 ` Sasha Levin
2026-09-09 1:31 ` [PATCH 6.1.y 3/4] sunrpc: xprtrdma: Use ERR_CAST() to return Sasha Levin
2026-09-09 1:31 ` [PATCH 6.1.y 4/4] svcrdma: Use svc_xprt_put to free listener on create failure Sasha Levin
2 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-09-09 1:31 UTC (permalink / raw)
To: stable; +Cc: Chuck Lever, Sagi Grimberg, Sasha Levin
From: Chuck Lever <chuck.lever@oracle.com>
[ Upstream commit 283d28546234b1764a0a37cb3df30cc3321c75b4 ]
In a moment, I will add a second consumer of CMA ID creation in
svcrdma. Refactor so this code can be reused.
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Stable-dep-of: e346ef7bcb13 ("svcrdma: Use svc_xprt_put to free listener on create failure")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sunrpc/xprtrdma/svc_rdma_transport.c | 67 ++++++++++++++----------
1 file changed, 40 insertions(+), 27 deletions(-)
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 9c4cd4caa0c1c..c84343fbf2d2f 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -65,6 +65,8 @@
static struct svcxprt_rdma *svc_rdma_create_xprt(struct svc_serv *serv,
struct net *net, int node);
+static int svc_rdma_listen_handler(struct rdma_cm_id *cma_id,
+ struct rdma_cm_event *event);
static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
struct net *net,
struct sockaddr *sa, int salen,
@@ -124,6 +126,41 @@ static void qp_event_handler(struct ib_event *event, void *context)
}
}
+static struct rdma_cm_id *
+svc_rdma_create_listen_id(struct net *net, struct sockaddr *sap,
+ void *context)
+{
+ struct rdma_cm_id *listen_id;
+ int ret;
+
+ listen_id = rdma_create_id(net, svc_rdma_listen_handler, context,
+ RDMA_PS_TCP, IB_QPT_RC);
+ if (IS_ERR(listen_id))
+ return listen_id;
+
+ /* Allow both IPv4 and IPv6 sockets to bind a single port
+ * at the same time.
+ */
+#if IS_ENABLED(CONFIG_IPV6)
+ ret = rdma_set_afonly(listen_id, 1);
+ if (ret)
+ goto out_destroy;
+#endif
+ ret = rdma_bind_addr(listen_id, sap);
+ if (ret)
+ goto out_destroy;
+
+ ret = rdma_listen(listen_id, RPCRDMA_LISTEN_BACKLOG);
+ if (ret)
+ goto out_destroy;
+
+ return listen_id;
+
+out_destroy:
+ rdma_destroy_id(listen_id);
+ return ERR_PTR(ret);
+}
+
static struct svcxprt_rdma *svc_rdma_create_xprt(struct svc_serv *serv,
struct net *net, int node)
{
@@ -302,7 +339,6 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
{
struct rdma_cm_id *listen_id;
struct svcxprt_rdma *cma_xprt;
- int ret;
if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
return ERR_PTR(-EAFNOSUPPORT);
@@ -312,30 +348,13 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
set_bit(XPT_LISTENER, &cma_xprt->sc_xprt.xpt_flags);
strcpy(cma_xprt->sc_xprt.xpt_remotebuf, "listener");
- listen_id = rdma_create_id(net, svc_rdma_listen_handler, cma_xprt,
- RDMA_PS_TCP, IB_QPT_RC);
+ listen_id = svc_rdma_create_listen_id(net, sa, cma_xprt);
if (IS_ERR(listen_id)) {
- ret = PTR_ERR(listen_id);
- goto err0;
+ kfree(cma_xprt);
+ return (struct svc_xprt *)listen_id;
}
-
- /* Allow both IPv4 and IPv6 sockets to bind a single port
- * at the same time.
- */
-#if IS_ENABLED(CONFIG_IPV6)
- ret = rdma_set_afonly(listen_id, 1);
- if (ret)
- goto err1;
-#endif
- ret = rdma_bind_addr(listen_id, sa);
- if (ret)
- goto err1;
cma_xprt->sc_cm_id = listen_id;
- ret = rdma_listen(listen_id, RPCRDMA_LISTEN_BACKLOG);
- if (ret)
- goto err1;
-
/*
* We need to use the address from the cm_id in case the
* caller specified 0 for the port number.
@@ -344,12 +363,6 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
svc_xprt_set_local(&cma_xprt->sc_xprt, sa, salen);
return &cma_xprt->sc_xprt;
-
- err1:
- rdma_destroy_id(listen_id);
- err0:
- kfree(cma_xprt);
- return ERR_PTR(ret);
}
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 6.1.y 3/4] sunrpc: xprtrdma: Use ERR_CAST() to return
2026-09-09 1:31 ` [PATCH 6.1.y 1/4] svcrdma: Allocate new transports on device's NUMA node Sasha Levin
2026-09-09 1:31 ` [PATCH 6.1.y 2/4] svcrdma: Refactor the creation of listener CMA ID Sasha Levin
@ 2026-09-09 1:31 ` Sasha Levin
2026-09-09 1:31 ` [PATCH 6.1.y 4/4] svcrdma: Use svc_xprt_put to free listener on create failure Sasha Levin
2 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-09-09 1:31 UTC (permalink / raw)
To: stable; +Cc: Yan Zhen, Chuck Lever, Sasha Levin
From: Yan Zhen <yanzhen@vivo.com>
[ Upstream commit aeddf8e6c5662d60d434ce59f7e08ea020162323 ]
Using ERR_CAST() is more reasonable and safer, When it is necessary
to convert the type of an error pointer and return it.
Signed-off-by: Yan Zhen <yanzhen@vivo.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Stable-dep-of: e346ef7bcb13 ("svcrdma: Use svc_xprt_put to free listener on create failure")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sunrpc/xprtrdma/svc_rdma_transport.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index c84343fbf2d2f..ae15c2ed2f12c 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -351,7 +351,7 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
listen_id = svc_rdma_create_listen_id(net, sa, cma_xprt);
if (IS_ERR(listen_id)) {
kfree(cma_xprt);
- return (struct svc_xprt *)listen_id;
+ return ERR_CAST(listen_id);
}
cma_xprt->sc_cm_id = listen_id;
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 6.1.y 4/4] svcrdma: Use svc_xprt_put to free listener on create failure
2026-09-09 1:31 ` [PATCH 6.1.y 1/4] svcrdma: Allocate new transports on device's NUMA node Sasha Levin
2026-09-09 1:31 ` [PATCH 6.1.y 2/4] svcrdma: Refactor the creation of listener CMA ID Sasha Levin
2026-09-09 1:31 ` [PATCH 6.1.y 3/4] sunrpc: xprtrdma: Use ERR_CAST() to return Sasha Levin
@ 2026-09-09 1:31 ` Sasha Levin
2 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-09-09 1:31 UTC (permalink / raw)
To: stable; +Cc: Chuck Lever, Jeff Layton, Sasha Levin
From: Chuck Lever <chuck.lever@oracle.com>
[ Upstream commit e346ef7bcb137f50c49f969330ab7dcf64ea1654 ]
svc_rdma_create() calls kfree(cma_xprt) when
svc_rdma_create_listen_id() fails. svc_xprt_init() has already
acquired a net namespace reference via get_net_track(); kfree
bypasses svc_xprt_free() which releases it.
Replace the kfree() with svc_xprt_put() so the kref_init birth
reference drops to zero and svc_xprt_free() dispatches
svc_rdma_free() to clean up properly. sc_cm_id is still NULL
at that point; the preceding patch added the necessary NULL
guard in svc_rdma_free().
svc_xprt_free() also drops the module reference via
module_put(), but the caller _svc_xprt_create() does the same
on xpo_create failure, double-putting the single
try_module_get() it acquired. Take a compensating
__module_get() before the svc_xprt_put() to keep the count
balanced, matching the convention in svc_rdma_accept()'s error
path.
Fixes: 4fb8518bdac8 ("sunrpc: Tag svc_xprt with net")
Cc: stable@vger.kernel.org
Acked-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260527-rdma-follow-on-v1-3-1b09bd87b6cd@oracle.com
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sunrpc/xprtrdma/svc_rdma_transport.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index ae15c2ed2f12c..f573b555853c7 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -350,7 +350,13 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
listen_id = svc_rdma_create_listen_id(net, sa, cma_xprt);
if (IS_ERR(listen_id)) {
- kfree(cma_xprt);
+ /* _svc_xprt_create() acquired one module reference and
+ * puts it on xpo_create failure. svc_xprt_free() puts
+ * a second one when the kref drops to zero. Take a
+ * compensating reference so both puts are balanced.
+ */
+ __module_get(cma_xprt->sc_xprt.xpt_class->xcl_owner);
+ svc_xprt_put(&cma_xprt->sc_xprt);
return ERR_CAST(listen_id);
}
cma_xprt->sc_cm_id = listen_id;
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread