diff --git a/lib/bdev/iscsi/bdev_iscsi.c b/lib/bdev/iscsi/bdev_iscsi.c index 7b168f282..c751fa869 100644 --- a/lib/bdev/iscsi/bdev_iscsi.c +++ b/lib/bdev/iscsi/bdev_iscsi.c @@ -98,9 +98,10 @@ struct bdev_iscsi_conn_req { char *initiator_iqn; struct iscsi_context *context; spdk_bdev_iscsi_create_cb create_cb; - spdk_bdev_iscsi_create_cb create_cb_arg; + void *create_cb_arg; bool unmap_supported; int lun; + int status; TAILQ_ENTRY(bdev_iscsi_conn_req) link; }; @@ -110,17 +111,12 @@ complete_conn_req(struct bdev_iscsi_conn_req *req, struct spdk_bdev *bdev, { TAILQ_REMOVE(&g_iscsi_conn_req, req, link); req->create_cb(req->create_cb_arg, bdev, status); - if (status) { - /* if the request failed and no iscsi lun was - * created then we could not hand over this - * memory and have to free it manually now. - */ - iscsi_destroy_context(req->context); - free(req->initiator_iqn); - free(req->bdev_name); - free(req->url); - } - free(req); + + /* + * we are still running in the context of iscsi_service() + * so do not tear down its data structures here + */ + req->status = status; } static int @@ -145,14 +141,29 @@ _iscsi_free_lun(void *arg) free(lun); } +static void +_bdev_iscsi_conn_req_free(struct bdev_iscsi_conn_req *req) +{ + + free(req->initiator_iqn); + free(req->bdev_name); + free(req->url); + /* destroy will call iscsi_disconnect() implicitly if connected */ + iscsi_destroy_context(req->context); + free(req); +} + static void bdev_iscsi_finish(void) { - struct bdev_iscsi_conn_req *req; + struct bdev_iscsi_conn_req *req, *tmp; - while (!TAILQ_EMPTY(&g_iscsi_conn_req)) { - req = TAILQ_FIRST(&g_iscsi_conn_req); - complete_conn_req(req, NULL, -EINTR); + /* clear out pending connection requests here. We cannot + * simply set the state to a non SCSI_STATUS_GOOD state as + * the connection poller wont run anymore + */ + TAILQ_FOREACH_SAFE(req, &g_iscsi_conn_req, link, tmp) { + _bdev_iscsi_conn_req_free(req); } if (g_conn_poller) { @@ -725,8 +736,16 @@ iscsi_bdev_conn_poll(void *arg) SPDK_ERRLOG("iscsi_service failed: %s\n", iscsi_get_error(context)); } } - } + if (req->status != SCSI_STATUS_GOOD) { + /* + * An error has occurred during connecting. This req has already + * been removed from the g_iscsi_conn_req list, but we needed to + * wait until iscsi_service unwound before we could free the req. + */ + _bdev_iscsi_conn_req_free(req); + } + } return -1; } @@ -748,6 +767,7 @@ create_iscsi_disk(const char *bdev_name, const char *url, const char *initiator_ return -ENOMEM; } + req->status = SCSI_STATUS_GOOD; req->bdev_name = strdup(bdev_name); req->url = strdup(url); req->initiator_iqn = strdup(initiator_iqn);