]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
svcrdma: Handle ADDR_CHANGE CM event properly
authorChuck Lever <chuck.lever@oracle.com>
Fri, 31 May 2024 13:15:53 +0000 (09:15 -0400)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 8 Jul 2024 18:10:02 +0000 (14:10 -0400)
Sagi tells me that when a bonded device reports an address change,
the consumer must destroy its listener IDs and create new ones.

See commit a032e4f6d60d ("nvmet-rdma: fix bonding failover possible
NULL deref").

Suggested-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
net/sunrpc/xprtrdma/svc_rdma_transport.c

index fa50b7494a0aae6f6efe1b83f7922b54e1e870ce..f15750cacacff4ee7b32e95f08583e73ace0e950 100644 (file)
@@ -284,17 +284,31 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id,
  *
  * Return values:
  *     %0: Do not destroy @cma_id
- *     %1: Destroy @cma_id (never returned here)
+ *     %1: Destroy @cma_id
  *
  * NB: There is never a DEVICE_REMOVAL event for INADDR_ANY listeners.
  */
 static int svc_rdma_listen_handler(struct rdma_cm_id *cma_id,
                                   struct rdma_cm_event *event)
 {
+       struct sockaddr *sap = (struct sockaddr *)&cma_id->route.addr.src_addr;
+       struct svcxprt_rdma *cma_xprt = cma_id->context;
+       struct svc_xprt *cma_rdma = &cma_xprt->sc_xprt;
+       struct rdma_cm_id *listen_id;
+
        switch (event->event) {
        case RDMA_CM_EVENT_CONNECT_REQUEST:
                handle_connect_req(cma_id, &event->param.conn);
                break;
+       case RDMA_CM_EVENT_ADDR_CHANGE:
+               listen_id = svc_rdma_create_listen_id(cma_rdma->xpt_net,
+                                                     sap, cma_xprt);
+               if (IS_ERR(listen_id)) {
+                       pr_err("Listener dead, address change failed for device %s\n",
+                               cma_id->device->name);
+               } else
+                       cma_xprt->sc_cm_id = listen_id;
+               return 1;
        default:
                break;
        }