diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2018-03-19 14:23:16 -0400 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2018-04-10 16:07:10 -0400 |
commit | 25524288631fc5b7d33259fca1e0dc38146be5d6 (patch) | |
tree | 2b148001eb639023f8c308937c841c94522f6480 | |
parent | 571745935b2ec276345faec81af732fb9f51082b (diff) |
xprtrdma: Fix corner cases when handling device removal
Michal Kalderon has found some corner cases around device unload
with active NFS mounts that I didn't have the imagination to test
when xprtrdma device removal was added last year.
- The ULP device removal handler is responsible for deallocating
the PD. That wasn't clear to me initially, and my own testing
suggested it was not necessary, but that is incorrect.
- The transport destruction path can no longer assume that there
is a valid ID.
- When destroying a transport, ensure that ib_free_cq() is not
invoked on a CQ that was already released.
Reported-by: Michal Kalderon <Michal.Kalderon@cavium.com>
Fixes: bebd031866ca ("xprtrdma: Support unplugging an HCA from ...")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Cc: stable@vger.kernel.org # v4.12+
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r-- | net/sunrpc/xprtrdma/verbs.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 6a7a5a277e75..fe5eaca2d197 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
@@ -250,7 +250,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) | |||
250 | wait_for_completion(&ia->ri_remove_done); | 250 | wait_for_completion(&ia->ri_remove_done); |
251 | 251 | ||
252 | ia->ri_id = NULL; | 252 | ia->ri_id = NULL; |
253 | ia->ri_pd = NULL; | ||
254 | ia->ri_device = NULL; | 253 | ia->ri_device = NULL; |
255 | /* Return 1 to ensure the core destroys the id. */ | 254 | /* Return 1 to ensure the core destroys the id. */ |
256 | return 1; | 255 | return 1; |
@@ -447,7 +446,9 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia) | |||
447 | ia->ri_id->qp = NULL; | 446 | ia->ri_id->qp = NULL; |
448 | } | 447 | } |
449 | ib_free_cq(ep->rep_attr.recv_cq); | 448 | ib_free_cq(ep->rep_attr.recv_cq); |
449 | ep->rep_attr.recv_cq = NULL; | ||
450 | ib_free_cq(ep->rep_attr.send_cq); | 450 | ib_free_cq(ep->rep_attr.send_cq); |
451 | ep->rep_attr.send_cq = NULL; | ||
451 | 452 | ||
452 | /* The ULP is responsible for ensuring all DMA | 453 | /* The ULP is responsible for ensuring all DMA |
453 | * mappings and MRs are gone. | 454 | * mappings and MRs are gone. |
@@ -460,6 +461,8 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia) | |||
460 | rpcrdma_dma_unmap_regbuf(req->rl_recvbuf); | 461 | rpcrdma_dma_unmap_regbuf(req->rl_recvbuf); |
461 | } | 462 | } |
462 | rpcrdma_mrs_destroy(buf); | 463 | rpcrdma_mrs_destroy(buf); |
464 | ib_dealloc_pd(ia->ri_pd); | ||
465 | ia->ri_pd = NULL; | ||
463 | 466 | ||
464 | /* Allow waiters to continue */ | 467 | /* Allow waiters to continue */ |
465 | complete(&ia->ri_remove_done); | 468 | complete(&ia->ri_remove_done); |
@@ -627,14 +630,16 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | |||
627 | { | 630 | { |
628 | cancel_delayed_work_sync(&ep->rep_connect_worker); | 631 | cancel_delayed_work_sync(&ep->rep_connect_worker); |
629 | 632 | ||
630 | if (ia->ri_id->qp) { | 633 | if (ia->ri_id && ia->ri_id->qp) { |
631 | rpcrdma_ep_disconnect(ep, ia); | 634 | rpcrdma_ep_disconnect(ep, ia); |
632 | rdma_destroy_qp(ia->ri_id); | 635 | rdma_destroy_qp(ia->ri_id); |
633 | ia->ri_id->qp = NULL; | 636 | ia->ri_id->qp = NULL; |
634 | } | 637 | } |
635 | 638 | ||
636 | ib_free_cq(ep->rep_attr.recv_cq); | 639 | if (ep->rep_attr.recv_cq) |
637 | ib_free_cq(ep->rep_attr.send_cq); | 640 | ib_free_cq(ep->rep_attr.recv_cq); |
641 | if (ep->rep_attr.send_cq) | ||
642 | ib_free_cq(ep->rep_attr.send_cq); | ||
638 | } | 643 | } |
639 | 644 | ||
640 | /* Re-establish a connection after a device removal event. | 645 | /* Re-establish a connection after a device removal event. |