xprtrdma: Restore transport after device removal
authorChuck Lever <chuck.lever@oracle.com>
Tue, 11 Apr 2017 17:23:26 +0000 (13:23 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Tue, 25 Apr 2017 20:12:28 +0000 (16:12 -0400)
After a device removal, enable the transport connect worker to
restore normal operation if there is another device with
connectivity to the server.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
net/sunrpc/xprtrdma/verbs.c

index 6479ad3fe69df74ea06a5bc4ac8d90a01b97f30d..b69daa30874fd5350f8f09415df9fe412f5f98f4 100644 (file)
@@ -69,6 +69,7 @@
 /*
  * internal functions
  */
+static void rpcrdma_create_mrs(struct rpcrdma_xprt *r_xprt);
 static void rpcrdma_destroy_mrs(struct rpcrdma_buffer *buf);
 static void rpcrdma_dma_unmap_regbuf(struct rpcrdma_regbuf *rb);
 
@@ -711,6 +712,48 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
        ib_free_cq(ep->rep_attr.send_cq);
 }
 
+/* Re-establish a connection after a device removal event.
+ * Unlike a normal reconnection, a fresh PD and a new set
+ * of MRs and buffers is needed.
+ */
+static int
+rpcrdma_ep_recreate_xprt(struct rpcrdma_xprt *r_xprt,
+                        struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
+{
+       struct sockaddr *sap = (struct sockaddr *)&r_xprt->rx_data.addr;
+       int rc, err;
+
+       pr_info("%s: r_xprt = %p\n", __func__, r_xprt);
+
+       rc = -EHOSTUNREACH;
+       if (rpcrdma_ia_open(r_xprt, sap))
+               goto out1;
+
+       rc = -ENOMEM;
+       err = rpcrdma_ep_create(ep, ia, &r_xprt->rx_data);
+       if (err) {
+               pr_err("rpcrdma: rpcrdma_ep_create returned %d\n", err);
+               goto out2;
+       }
+
+       rc = -ENETUNREACH;
+       err = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr);
+       if (err) {
+               pr_err("rpcrdma: rdma_create_qp returned %d\n", err);
+               goto out3;
+       }
+
+       rpcrdma_create_mrs(r_xprt);
+       return 0;
+
+out3:
+       rpcrdma_ep_destroy(ep, ia);
+out2:
+       rpcrdma_ia_close(ia);
+out1:
+       return rc;
+}
+
 static int
 rpcrdma_ep_reconnect(struct rpcrdma_xprt *r_xprt, struct rpcrdma_ep *ep,
                     struct rpcrdma_ia *ia)
@@ -785,6 +828,11 @@ retry:
                        goto out_noupdate;
                }
                break;
+       case -ENODEV:
+               rc = rpcrdma_ep_recreate_xprt(r_xprt, ep, ia);
+               if (rc)
+                       goto out_noupdate;
+               break;
        default:
                rc = rpcrdma_ep_reconnect(r_xprt, ep, ia);
                if (rc)