RPC/RDMA: avoid an oops due to disconnect racing with async upcalls.
authorTom Talpey <talpey@netapp.com>
Thu, 9 Oct 2008 19:01:00 +0000 (15:01 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 10 Oct 2008 19:11:40 +0000 (15:11 -0400)
RDMA disconnects yield an upcall from the RDMA connection manager,
which can race with rpc transport close, e.g. on ^C of a mount.
Ensure any rdma cm_id and qp are fully destroyed before continuing.

Signed-off-by: Tom Talpey <talpey@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
net/sunrpc/xprtrdma/verbs.c

index e3fe905..d94f379 100644 (file)
@@ -565,6 +565,7 @@ rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg)
        return 0;
 out2:
        rdma_destroy_id(ia->ri_id);
+       ia->ri_id = NULL;
 out1:
        return rc;
 }
@@ -585,15 +586,17 @@ rpcrdma_ia_close(struct rpcrdma_ia *ia)
                dprintk("RPC:       %s: ib_dereg_mr returned %i\n",
                        __func__, rc);
        }
-       if (ia->ri_id != NULL && !IS_ERR(ia->ri_id) && ia->ri_id->qp)
-               rdma_destroy_qp(ia->ri_id);
+       if (ia->ri_id != NULL && !IS_ERR(ia->ri_id)) {
+               if (ia->ri_id->qp)
+                       rdma_destroy_qp(ia->ri_id);
+               rdma_destroy_id(ia->ri_id);
+               ia->ri_id = NULL;
+       }
        if (ia->ri_pd != NULL && !IS_ERR(ia->ri_pd)) {
                rc = ib_dealloc_pd(ia->ri_pd);
                dprintk("RPC:       %s: ib_dealloc_pd returned %i\n",
                        __func__, rc);
        }
-       if (ia->ri_id != NULL && !IS_ERR(ia->ri_id))
-               rdma_destroy_id(ia->ri_id);
 }
 
 /*
@@ -751,21 +754,16 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
                if (rc)
                        dprintk("RPC:       %s: rpcrdma_ep_disconnect"
                                " returned %i\n", __func__, rc);
+               rdma_destroy_qp(ia->ri_id);
+               ia->ri_id->qp = NULL;
        }
 
-       ep->rep_func = NULL;
-
        /* padding - could be done in rpcrdma_buffer_destroy... */
        if (ep->rep_pad_mr) {
                rpcrdma_deregister_internal(ia, ep->rep_pad_mr, &ep->rep_pad);
                ep->rep_pad_mr = NULL;
        }
 
-       if (ia->ri_id->qp) {
-               rdma_destroy_qp(ia->ri_id);
-               ia->ri_id->qp = NULL;
-       }
-
        rpcrdma_clean_cq(ep->rep_cq);
        rc = ib_destroy_cq(ep->rep_cq);
        if (rc)