diff options
author | Raju Rangoju <rajur@chelsio.com> | 2016-08-29 07:45:49 -0400 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2016-09-02 13:46:32 -0400 |
commit | 63b268d232b869dfbc92e49c77f7e0648e1d039c (patch) | |
tree | aa246fc50f9bfe35472fa086ab3fa15b7b24f824 | |
parent | 6aaa382f1267644072f288916476879684502f73 (diff) |
IB/isert: Properly release resources on DEVICE_REMOVAL
When the low level driver exercises the hot unplug they would call
rdma_cm cma_remove_one which would fire DEVICE_REMOVAL event to all cma
consumers. Now, if consumer doesn't make sure they destroy all IB
objects created on that IB device instance prior to finalizing all
processing of DEVICE_REMOVAL callback, rdma_cm will let the lld to
de-register with IB core and destroy the IB device instance. And if the
consumer calls (say) ib_dereg_mr(), it will crash since that dev object
is NULL.
In the current implementation, iser-target just initiates the cleanup
and returns from DEVICE_REMOVAL callback. This deferred work creates a
race between iser-target cleaning IB objects(say MR) and lld destroying
IB device instance.
This patch includes the following fixes
-> make sure that consumer frees all IB objects associated with device
instance
-> return non-zero from the callback to destroy the rdma_cm id
Signed-off-by: Raju Rangoju <rajur@chelsio.com>
Acked-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r-- | drivers/infiniband/ulp/isert/ib_isert.c | 23 | ||||
-rw-r--r-- | drivers/infiniband/ulp/isert/ib_isert.h | 2 |
2 files changed, 22 insertions, 3 deletions
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 7914c14478cd..cae9bbcc27e7 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c | |||
@@ -403,6 +403,7 @@ isert_init_conn(struct isert_conn *isert_conn) | |||
403 | INIT_LIST_HEAD(&isert_conn->node); | 403 | INIT_LIST_HEAD(&isert_conn->node); |
404 | init_completion(&isert_conn->login_comp); | 404 | init_completion(&isert_conn->login_comp); |
405 | init_completion(&isert_conn->login_req_comp); | 405 | init_completion(&isert_conn->login_req_comp); |
406 | init_waitqueue_head(&isert_conn->rem_wait); | ||
406 | kref_init(&isert_conn->kref); | 407 | kref_init(&isert_conn->kref); |
407 | mutex_init(&isert_conn->mutex); | 408 | mutex_init(&isert_conn->mutex); |
408 | INIT_WORK(&isert_conn->release_work, isert_release_work); | 409 | INIT_WORK(&isert_conn->release_work, isert_release_work); |
@@ -578,7 +579,8 @@ isert_connect_release(struct isert_conn *isert_conn) | |||
578 | BUG_ON(!device); | 579 | BUG_ON(!device); |
579 | 580 | ||
580 | isert_free_rx_descriptors(isert_conn); | 581 | isert_free_rx_descriptors(isert_conn); |
581 | if (isert_conn->cm_id) | 582 | if (isert_conn->cm_id && |
583 | !isert_conn->dev_removed) | ||
582 | rdma_destroy_id(isert_conn->cm_id); | 584 | rdma_destroy_id(isert_conn->cm_id); |
583 | 585 | ||
584 | if (isert_conn->qp) { | 586 | if (isert_conn->qp) { |
@@ -593,7 +595,10 @@ isert_connect_release(struct isert_conn *isert_conn) | |||
593 | 595 | ||
594 | isert_device_put(device); | 596 | isert_device_put(device); |
595 | 597 | ||
596 | kfree(isert_conn); | 598 | if (isert_conn->dev_removed) |
599 | wake_up_interruptible(&isert_conn->rem_wait); | ||
600 | else | ||
601 | kfree(isert_conn); | ||
597 | } | 602 | } |
598 | 603 | ||
599 | static void | 604 | static void |
@@ -753,6 +758,7 @@ static int | |||
753 | isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) | 758 | isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) |
754 | { | 759 | { |
755 | struct isert_np *isert_np = cma_id->context; | 760 | struct isert_np *isert_np = cma_id->context; |
761 | struct isert_conn *isert_conn; | ||
756 | int ret = 0; | 762 | int ret = 0; |
757 | 763 | ||
758 | isert_info("%s (%d): status %d id %p np %p\n", | 764 | isert_info("%s (%d): status %d id %p np %p\n", |
@@ -773,10 +779,21 @@ isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) | |||
773 | break; | 779 | break; |
774 | case RDMA_CM_EVENT_ADDR_CHANGE: /* FALLTHRU */ | 780 | case RDMA_CM_EVENT_ADDR_CHANGE: /* FALLTHRU */ |
775 | case RDMA_CM_EVENT_DISCONNECTED: /* FALLTHRU */ | 781 | case RDMA_CM_EVENT_DISCONNECTED: /* FALLTHRU */ |
776 | case RDMA_CM_EVENT_DEVICE_REMOVAL: /* FALLTHRU */ | ||
777 | case RDMA_CM_EVENT_TIMEWAIT_EXIT: /* FALLTHRU */ | 782 | case RDMA_CM_EVENT_TIMEWAIT_EXIT: /* FALLTHRU */ |
778 | ret = isert_disconnected_handler(cma_id, event->event); | 783 | ret = isert_disconnected_handler(cma_id, event->event); |
779 | break; | 784 | break; |
785 | case RDMA_CM_EVENT_DEVICE_REMOVAL: | ||
786 | isert_conn = cma_id->qp->qp_context; | ||
787 | isert_conn->dev_removed = true; | ||
788 | isert_disconnected_handler(cma_id, event->event); | ||
789 | wait_event_interruptible(isert_conn->rem_wait, | ||
790 | isert_conn->state == ISER_CONN_DOWN); | ||
791 | kfree(isert_conn); | ||
792 | /* | ||
793 | * return non-zero from the callback to destroy | ||
794 | * the rdma cm id | ||
795 | */ | ||
796 | return 1; | ||
780 | case RDMA_CM_EVENT_REJECTED: /* FALLTHRU */ | 797 | case RDMA_CM_EVENT_REJECTED: /* FALLTHRU */ |
781 | case RDMA_CM_EVENT_UNREACHABLE: /* FALLTHRU */ | 798 | case RDMA_CM_EVENT_UNREACHABLE: /* FALLTHRU */ |
782 | case RDMA_CM_EVENT_CONNECT_ERROR: | 799 | case RDMA_CM_EVENT_CONNECT_ERROR: |
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h index fc791efe3a10..c02ada57d7f5 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.h +++ b/drivers/infiniband/ulp/isert/ib_isert.h | |||
@@ -158,6 +158,8 @@ struct isert_conn { | |||
158 | struct work_struct release_work; | 158 | struct work_struct release_work; |
159 | bool logout_posted; | 159 | bool logout_posted; |
160 | bool snd_w_inv; | 160 | bool snd_w_inv; |
161 | wait_queue_head_t rem_wait; | ||
162 | bool dev_removed; | ||
161 | }; | 163 | }; |
162 | 164 | ||
163 | #define ISERT_MAX_CQ 64 | 165 | #define ISERT_MAX_CQ 64 |