isert-scst: 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>

See also upstream commit 63b268d232b8 ("IB/isert: Properly release
resources on DEVICE_REMOVAL")

Signed-off-by: Chesnokov Gleb <Chesnokov.G@raidix.com>
[ bvanassche: edited patch description and moved a break statement into a code
  block ]


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9480 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Bart Van Assche
2021-07-12 02:41:47 +00:00
parent 4ab077523a
commit 6cfbb697fd
2 changed files with 36 additions and 5 deletions

View File

@@ -231,6 +231,9 @@ struct isert_conn {
struct isert_portal *portal;
void *priv_data; /* for connection tracking */
wait_queue_head_t rem_wait;
atomic_t dev_removed;
};
struct isert_device {

View File

@@ -1274,6 +1274,7 @@ isert_init_conn(struct isert_conn *isert_conn)
INIT_LIST_HEAD(&isert_conn->tx_busy_list);
spin_lock_init(&isert_conn->tx_lock);
spin_lock_init(&isert_conn->post_recv_lock);
init_waitqueue_head(&isert_conn->rem_wait);
kref_init(&isert_conn->kref);
mutex_init(&isert_conn->state_mutex);
}
@@ -1389,8 +1390,11 @@ static void isert_release_kref(struct kref *kref)
isert_free_conn_resources(isert_conn);
rdma_destroy_id(isert_conn->cm_id);
isert_conn->cm_id = NULL;
if (isert_conn->cm_id &&
!atomic_read(&isert_conn->dev_removed)) {
rdma_destroy_id(isert_conn->cm_id);
isert_conn->cm_id = NULL;
}
dev = isert_get_priv(&isert_conn->iscsi);
if (dev) {
@@ -1413,9 +1417,14 @@ static void isert_release_kref(struct kref *kref)
isert_portal_free(isert_conn->portal);
mutex_unlock(&dev_list_mutex);
isert_conn_kfree(isert_conn);
module_put(THIS_MODULE);
if (atomic_read(&isert_conn->dev_removed)) {
atomic_set(&isert_conn->dev_removed, 0);
wake_up_interruptible(&isert_conn->rem_wait);
} else {
isert_conn_kfree(isert_conn);
module_put(THIS_MODULE);
}
TRACE_EXIT();
}
@@ -1706,12 +1715,31 @@ static int isert_cm_evt_handler(struct rdma_cm_id *cm_id,
case RDMA_CM_EVENT_ADDR_CHANGE:
case RDMA_CM_EVENT_DISCONNECTED:
case RDMA_CM_EVENT_DEVICE_REMOVAL:
case RDMA_CM_EVENT_TIMEWAIT_EXIT:
isert_cm_disconnect_handler(cm_id, ev_type);
err = isert_cm_disconnected_handler(cm_id, cm_ev);
break;
case RDMA_CM_EVENT_DEVICE_REMOVAL: {
struct isert_conn *isert_conn = cm_id->qp->qp_context;
atomic_set(&isert_conn->dev_removed, 1);
isert_cm_disconnect_handler(cm_id, ev_type);
isert_cm_disconnected_handler(cm_id, cm_ev);
wait_event_interruptible(isert_conn->rem_wait,
!atomic_read(&isert_conn->dev_removed));
isert_conn_kfree(isert_conn);
module_put(THIS_MODULE);
/*
* return non-zero from the callback to destroy
* the rdma cm id
*/
err = 1;
break;
}
case RDMA_CM_EVENT_MULTICAST_JOIN:
case RDMA_CM_EVENT_MULTICAST_ERROR:
PRINT_ERROR("UD-related event:%d, ignored", ev_type);