From ec5cf8a22118afef6b4aaf7bb362ba5c34fb857b Mon Sep 17 00:00:00 2001 From: Ziye Yang Date: Tue, 27 Mar 2018 10:42:21 +0800 Subject: [PATCH] bdev/iSCSI: Make the connection connect in async mode. Change-Id: I9d3b56ed908273c6853014241a28237f8d077cfa Signed-off-by: Ziye Yang Reviewed-on: https://review.gerrithub.io/405537 Tested-by: SPDK Automated Test System Reviewed-by: Jim Harris Reviewed-by: Daniel Verkamp --- lib/bdev/iscsi/bdev_iscsi.c | 169 ++++++++++++++++++++++++++++++++---- 1 file changed, 150 insertions(+), 19 deletions(-) diff --git a/lib/bdev/iscsi/bdev_iscsi.c b/lib/bdev/iscsi/bdev_iscsi.c index 5bd21482c..223b48b17 100644 --- a/lib/bdev/iscsi/bdev_iscsi.c +++ b/lib/bdev/iscsi/bdev_iscsi.c @@ -55,6 +55,10 @@ struct bdev_iscsi_lun; static int bdev_iscsi_initialize(void); static TAILQ_HEAD(, bdev_iscsi_lun) g_iscsi_lun_head = TAILQ_HEAD_INITIALIZER(g_iscsi_lun_head); +static TAILQ_HEAD(, bdev_iscsi_conn_req) g_iscsi_conn_req = TAILQ_HEAD_INITIALIZER( + g_iscsi_conn_req); +static struct spdk_poller *g_conn_poller = NULL; +static bool g_module_is_initialized; struct bdev_iscsi_io { struct spdk_thread *submit_td; @@ -82,15 +86,30 @@ struct bdev_iscsi_io_channel { struct bdev_iscsi_lun *lun; }; +struct bdev_iscsi_conn_req { + struct iscsi_url *url; + char *bdev_name; + struct iscsi_context *context; + TAILQ_ENTRY(bdev_iscsi_conn_req) link; +}; + static int bdev_iscsi_get_ctx_size(void) { return sizeof(struct bdev_iscsi_io); } +static void +bdev_iscsi_remove_conn_req(struct bdev_iscsi_conn_req *req) +{ + TAILQ_REMOVE(&g_iscsi_conn_req, req, link); + free(req); +} + static void bdev_iscsi_finish(void) { struct bdev_iscsi_lun *lun; + struct bdev_iscsi_conn_req *req, *tmp; while (!TAILQ_EMPTY(&g_iscsi_lun_head)) { lun = TAILQ_FIRST(&g_iscsi_lun_head); @@ -99,6 +118,14 @@ static void bdev_iscsi_finish(void) iscsi_destroy_context(lun->context); iscsi_destroy_url(lun->url); } + + TAILQ_FOREACH_SAFE(req, &g_iscsi_conn_req, link, tmp) { + bdev_iscsi_remove_conn_req(req); + } + + if (g_conn_poller) { + spdk_poller_unregister(&g_conn_poller); + } } static struct spdk_bdev_module g_iscsi_bdev_module = { @@ -106,6 +133,7 @@ static struct spdk_bdev_module g_iscsi_bdev_module = { .module_init = bdev_iscsi_initialize, .module_fini = bdev_iscsi_finish, .get_ctx_size = bdev_iscsi_get_ctx_size, + .async_init = true, }; SPDK_BDEV_MODULE_REGISTER(&g_iscsi_bdev_module); @@ -218,7 +246,7 @@ bdev_iscsi_poll(void *arg) { struct bdev_iscsi_io_channel *ch = arg; struct bdev_iscsi_lun *lun = ch->lun; - struct pollfd pfd; + struct pollfd pfd = {}; pfd.fd = iscsi_get_fd(lun->context); pfd.events = iscsi_which_events(lun->context); @@ -426,20 +454,123 @@ error_return: return NULL; } +static struct bdev_iscsi_conn_req * +bdev_iscsi_allocate_conn_req(struct iscsi_context *context, char *bdev_name, struct iscsi_url *url) +{ + struct bdev_iscsi_conn_req *req; + + req = calloc(1, sizeof(struct bdev_iscsi_conn_req)); + if (!req) { + SPDK_ERRLOG("Cannot allocate pointer of struct bdev_iscsi_conn_req\n"); + return NULL; + } + + req->bdev_name = bdev_name; + req->url = url; + req->context = context; + + return req; +} + +static void +_bdev_iscsi_set_module_init(void) +{ + spdk_bdev_module_init_done(&g_iscsi_bdev_module); + g_module_is_initialized = true; +} + +static void +bdev_iscsi_set_module_init(void) +{ + if (!g_module_is_initialized && TAILQ_EMPTY(&g_iscsi_conn_req)) { + _bdev_iscsi_set_module_init(); + } +} + +static void +iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status, + void *command_data, void *private_data) +{ + struct bdev_iscsi_conn_req *req = private_data; + struct scsi_readcapacity16 *readcap16; + struct spdk_bdev *bdev; + struct scsi_task *task = command_data; + + if (status != SPDK_SCSI_STATUS_GOOD) { + goto ret; + } + + readcap16 = scsi_datain_unmarshall(task); + bdev = create_iscsi_lun(req->context, req->url, req->bdev_name, + readcap16->returned_lba + 1, readcap16->block_length); + if (!bdev) { + SPDK_ERRLOG("Unable to create iscsi bdev\n"); + } + +ret: + scsi_free_scsi_task(task); + bdev_iscsi_remove_conn_req(req); + bdev_iscsi_set_module_init(); +} + +static void +iscsi_connect_cb(struct iscsi_context *iscsi, int status, + void *command_data, void *private_data) +{ + struct bdev_iscsi_conn_req *req = private_data; + struct scsi_task *task; + + if (status != SPDK_SCSI_STATUS_GOOD) { + goto ret; + } + + task = iscsi_readcapacity16_task(iscsi, 0, iscsi_readcapacity16_cb, req); + if (task) { + return; + } +ret: + bdev_iscsi_remove_conn_req(req); + bdev_iscsi_set_module_init(); +} + +static int +iscsi_bdev_conn_poll(void *arg) +{ + struct bdev_iscsi_conn_req *req, *tmp; + struct pollfd pfd; + + TAILQ_FOREACH_SAFE(req, &g_iscsi_conn_req, link, tmp) { + pfd.fd = iscsi_get_fd(req->context); + pfd.events = iscsi_which_events(req->context); + pfd.revents = 0; + if (poll(&pfd, 1, 0) < 0) { + SPDK_ERRLOG("poll failed\n"); + return -1; + } + + if (pfd.revents != 0) { + if (iscsi_service(req->context, pfd.revents) < 0) { + SPDK_ERRLOG("iscsi_service failed: %s\n", iscsi_get_error(req->context)); + } + } + } + + return 0; +} + static int bdev_iscsi_initialize(void) { struct spdk_conf_section *sp; struct iscsi_context *context; struct iscsi_url *url; - struct spdk_bdev *bdev; - struct scsi_task *task; - struct scsi_readcapacity16 *readcap16; char *val, *bdev_name, *initiator_iqn; + struct bdev_iscsi_conn_req *req; int i, rc; sp = spdk_conf_find_section(NULL, "iSCSI_Initiator"); if (sp == NULL) { + _bdev_iscsi_set_module_init(); return 0; } @@ -473,28 +604,28 @@ bdev_iscsi_initialize(void) break; } + req = bdev_iscsi_allocate_conn_req(context, bdev_name, url); + if (!req) { + _bdev_iscsi_set_module_init(); + return -1; + } + iscsi_set_session_type(context, ISCSI_SESSION_NORMAL); iscsi_set_header_digest(context, ISCSI_HEADER_DIGEST_NONE); - rc = iscsi_full_connect_sync(context, url->portal, url->lun); - if (rc != 0) { - SPDK_ERRLOG("could not login\n"); - break; - } - - task = iscsi_readcapacity16_sync(context, 0); - readcap16 = scsi_datain_unmarshall(task); - scsi_free_scsi_task(task); - - bdev = create_iscsi_lun(context, url, bdev_name, - readcap16->returned_lba + 1, readcap16->block_length); - if (!bdev) { - SPDK_ERRLOG("Unable to create iscsi bdev\n"); - break; + rc = iscsi_full_connect_async(context, url->portal, url->lun, iscsi_connect_cb, req); + if (rc < 0) { + free(req); + SPDK_ERRLOG("Failed to connect provided URL=%s, will ignore it\n", val); + continue; } + TAILQ_INSERT_TAIL(&g_iscsi_conn_req, req, link); i++; } + if (!TAILQ_EMPTY(&g_iscsi_conn_req)) { + g_conn_poller = spdk_poller_register(iscsi_bdev_conn_poll, NULL, 0); + } return 0; }