diff --git a/lib/scsi/dev.c b/lib/scsi/dev.c index 928accb08..deafd62c6 100644 --- a/lib/scsi/dev.c +++ b/lib/scsi/dev.c @@ -54,6 +54,7 @@ allocate_dev(void) memset(dev, 0, sizeof(*dev)); dev->id = i; dev->is_allocated = 1; + TAILQ_INIT(&dev->luns); return dev; } } @@ -79,8 +80,7 @@ void spdk_scsi_dev_destruct(struct spdk_scsi_dev *dev, spdk_scsi_dev_destruct_cb_t cb_fn, void *cb_arg) { - int lun_cnt; - int i; + struct spdk_scsi_lun *lun, *tmp_lun; if (dev == NULL) { if (cb_fn) { @@ -99,39 +99,62 @@ spdk_scsi_dev_destruct(struct spdk_scsi_dev *dev, dev->removed = true; dev->remove_cb = cb_fn; dev->remove_ctx = cb_arg; - lun_cnt = 0; - for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { - if (dev->lun[i] == NULL) { - continue; - } + if (TAILQ_EMPTY(&dev->luns)) { + free_dev(dev); + return; + } + TAILQ_FOREACH_SAFE(lun, &dev->luns, tailq, tmp_lun) { /* * LUN will remove itself from this dev when all outstanding IO * is done. When no more LUNs, dev will be deleted. */ - scsi_lun_destruct(dev->lun[i]); - lun_cnt++; - } - - if (lun_cnt == 0) { - free_dev(dev); - return; + scsi_lun_destruct(lun); } } +/* + * Search the lowest free LUN ID if the LUN ID is default, or check if the LUN ID is free otherwise, + * and also return the LUN which comes just before where we want to insert an new LUN. + */ static int -scsi_dev_find_lowest_free_lun_id(struct spdk_scsi_dev *dev) +scsi_dev_find_free_lun(struct spdk_scsi_dev *dev, int lun_id, + struct spdk_scsi_lun **prev_lun) { - int i; + struct spdk_scsi_lun *lun, *_prev_lun = NULL; - for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { - if (dev->lun[i] == NULL) { - return i; + if (prev_lun == NULL) { + return -EINVAL; + } + + if (lun_id == -1) { + lun_id = 0; + + TAILQ_FOREACH(lun, &dev->luns, tailq) { + if (lun->id > lun_id) { + break; + } + lun_id = lun->id + 1; + _prev_lun = lun; + } + + if (lun_id >= SPDK_SCSI_DEV_MAX_LUN) { + return -ENOSPC; + } + } else { + TAILQ_FOREACH(lun, &dev->luns, tailq) { + if (lun->id == lun_id) { + return -EEXIST; + } else if (lun->id > lun_id) { + break; + } + _prev_lun = lun; } } - return -1; + *prev_lun = _prev_lun; + return 0; } int @@ -151,20 +174,18 @@ spdk_scsi_dev_add_lun_ext(struct spdk_scsi_dev *dev, const char *bdev_name, int void (*hotremove_cb)(const struct spdk_scsi_lun *, void *), void *hotremove_ctx) { - struct spdk_scsi_lun *lun; + struct spdk_scsi_lun *lun, *prev_lun = NULL; + int rc; if (lun_id >= SPDK_SCSI_DEV_MAX_LUN) { SPDK_ERRLOG("LUN ID %d is more than the maximum.\n", lun_id); return -1; } - /* Search the lowest free LUN ID if LUN ID is default */ - if (lun_id == -1) { - lun_id = scsi_dev_find_lowest_free_lun_id(dev); - if (lun_id == -1) { - SPDK_ERRLOG("Free LUN ID is not found\n"); - return -1; - } + rc = scsi_dev_find_free_lun(dev, lun_id, &prev_lun); + if (rc != 0) { + SPDK_ERRLOG("%s\n", rc == -EEXIST ? "LUN ID is duplicated" : "Free LUN ID is not found"); + return rc; } lun = scsi_lun_construct(bdev_name, resize_cb, resize_ctx, hotremove_cb, hotremove_ctx); @@ -172,9 +193,21 @@ spdk_scsi_dev_add_lun_ext(struct spdk_scsi_dev *dev, const char *bdev_name, int return -1; } - lun->id = lun_id; lun->dev = dev; - dev->lun[lun_id] = lun; + + if (lun_id != -1) { + lun->id = lun_id; + } else if (prev_lun == NULL) { + lun->id = 0; + } else { + lun->id = prev_lun->id + 1; + } + + if (prev_lun == NULL) { + TAILQ_INSERT_HEAD(&dev->luns, lun, tailq); + } else { + TAILQ_INSERT_AFTER(&dev->luns, prev_lun, lun, tailq); + } return 0; } @@ -182,20 +215,9 @@ void spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev, struct spdk_scsi_lun *lun) { - int lun_cnt = 0; - int i; + TAILQ_REMOVE(&dev->luns, lun, tailq); - for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { - if (dev->lun[i] == lun) { - dev->lun[i] = NULL; - } - - if (dev->lun[i]) { - lun_cnt++; - } - } - - if (dev->removed == true && lun_cnt == 0) { + if (dev->removed && TAILQ_EMPTY(&dev->luns)) { free_dev(dev); } } @@ -382,26 +404,21 @@ spdk_scsi_dev_find_port_by_id(struct spdk_scsi_dev *dev, uint64_t id) void spdk_scsi_dev_free_io_channels(struct spdk_scsi_dev *dev) { - int i; + struct spdk_scsi_lun *lun, *tmp_lun; - for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { - if (dev->lun[i] == NULL) { - continue; - } - scsi_lun_free_io_channel(dev->lun[i]); + TAILQ_FOREACH_SAFE(lun, &dev->luns, tailq, tmp_lun) { + scsi_lun_free_io_channel(lun); } } int spdk_scsi_dev_allocate_io_channels(struct spdk_scsi_dev *dev) { - int i, rc; + struct spdk_scsi_lun *lun, *tmp_lun; + int rc; - for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { - if (dev->lun[i] == NULL) { - continue; - } - rc = scsi_lun_allocate_io_channel(dev->lun[i]); + TAILQ_FOREACH_SAFE(lun, &dev->luns, tailq, tmp_lun) { + rc = scsi_lun_allocate_io_channel(lun); if (rc < 0) { spdk_scsi_dev_free_io_channels(dev); return -1; @@ -428,28 +445,26 @@ spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id) { struct spdk_scsi_lun *lun; - if (lun_id < 0 || lun_id >= SPDK_SCSI_DEV_MAX_LUN) { - return NULL; + TAILQ_FOREACH(lun, &dev->luns, tailq) { + if (lun->id == lun_id) { + if (!spdk_scsi_lun_is_removing(lun)) { + return lun; + } else { + return NULL; + } + } } - lun = dev->lun[lun_id]; - - if (lun != NULL && !spdk_scsi_lun_is_removing(lun)) { - return lun; - } else { - return NULL; - } + return NULL; } struct spdk_scsi_lun * spdk_scsi_dev_get_first_lun(struct spdk_scsi_dev *dev) { struct spdk_scsi_lun *lun; - int lun_id; - for (lun_id = 0; lun_id < SPDK_SCSI_DEV_MAX_LUN; lun_id++) { - lun = dev->lun[lun_id]; - if (lun != NULL && !spdk_scsi_lun_is_removing(lun)) { + TAILQ_FOREACH(lun, &dev->luns, tailq) { + if (!spdk_scsi_lun_is_removing(lun)) { return lun; } } @@ -462,7 +477,6 @@ spdk_scsi_dev_get_next_lun(struct spdk_scsi_lun *prev_lun) { struct spdk_scsi_dev *dev; struct spdk_scsi_lun *lun; - int lun_id; if (prev_lun == NULL) { return NULL; @@ -470,26 +484,29 @@ spdk_scsi_dev_get_next_lun(struct spdk_scsi_lun *prev_lun) dev = prev_lun->dev; - for (lun_id = prev_lun->id + 1; lun_id < SPDK_SCSI_DEV_MAX_LUN; lun_id++) { - lun = dev->lun[lun_id]; - if (lun != NULL && !spdk_scsi_lun_is_removing(lun)) { - return lun; + lun = TAILQ_NEXT(prev_lun, tailq); + if (lun == NULL) { + return NULL; + } + + TAILQ_FOREACH_FROM(lun, &dev->luns, tailq) { + if (!spdk_scsi_lun_is_removing(lun)) { + break; } } - return NULL; + return lun; } bool spdk_scsi_dev_has_pending_tasks(const struct spdk_scsi_dev *dev, const struct spdk_scsi_port *initiator_port) { - int i; + struct spdk_scsi_lun *lun; - for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; ++i) { - if (dev->lun[i] && - (scsi_lun_has_pending_tasks(dev->lun[i], initiator_port) || - scsi_lun_has_pending_mgmt_tasks(dev->lun[i], initiator_port))) { + TAILQ_FOREACH(lun, &dev->luns, tailq) { + if (scsi_lun_has_pending_tasks(lun, initiator_port) || + scsi_lun_has_pending_mgmt_tasks(lun, initiator_port)) { return true; } } diff --git a/lib/scsi/scsi_internal.h b/lib/scsi/scsi_internal.h index 1648e5983..1ce36f0bf 100644 --- a/lib/scsi/scsi_internal.h +++ b/lib/scsi/scsi_internal.h @@ -92,7 +92,7 @@ struct spdk_scsi_dev { char name[SPDK_SCSI_DEV_MAX_NAME + 1]; - struct spdk_scsi_lun *lun[SPDK_SCSI_DEV_MAX_LUN]; + TAILQ_HEAD(, spdk_scsi_lun) luns; int num_ports; struct spdk_scsi_port port[SPDK_SCSI_DEV_MAX_PORTS]; @@ -173,6 +173,9 @@ struct spdk_scsi_lun { /** poller to check completion of tasks prior to reset */ struct spdk_poller *reset_poller; + + /** A structure to connect LUNs in a list. */ + TAILQ_ENTRY(spdk_scsi_lun) tailq; }; struct spdk_scsi_lun *scsi_lun_construct(const char *bdev_name, diff --git a/test/unit/lib/iscsi/common.c b/test/unit/lib/iscsi/common.c index e5d0f6ad1..732f50605 100644 --- a/test/unit/lib/iscsi/common.c +++ b/test/unit/lib/iscsi/common.c @@ -113,9 +113,12 @@ DEFINE_STUB_V(spdk_scsi_task_process_abort, (struct spdk_scsi_task *task)); void spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev, struct spdk_scsi_task *task) { - assert(dev->lun[0] != NULL); + struct spdk_scsi_lun *lun; - TAILQ_INSERT_TAIL(&dev->lun[0]->tasks, task, scsi_link); + lun = TAILQ_FIRST(&dev->luns); + SPDK_CU_ASSERT_FATAL(lun != NULL); + + TAILQ_INSERT_TAIL(&lun->tasks, task, scsi_link); } DEFINE_STUB(spdk_scsi_dev_find_port_by_id, struct spdk_scsi_port *, diff --git a/test/unit/lib/iscsi/iscsi.c/iscsi_ut.c b/test/unit/lib/iscsi/iscsi.c/iscsi_ut.c index 377d19e58..2992a0975 100644 --- a/test/unit/lib/iscsi/iscsi.c/iscsi_ut.c +++ b/test/unit/lib/iscsi/iscsi.c/iscsi_ut.c @@ -131,11 +131,15 @@ DEFINE_STUB(spdk_scsi_lun_is_removing, bool, (const struct spdk_scsi_lun *lun), struct spdk_scsi_lun * spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id) { - if (lun_id < 0 || lun_id >= SPDK_SCSI_DEV_MAX_LUN) { - return NULL; + struct spdk_scsi_lun *lun; + + TAILQ_FOREACH(lun, &dev->luns, tailq) { + if (lun->id == lun_id) { + break; + } } - return dev->lun[lun_id]; + return lun; } DEFINE_STUB(spdk_scsi_lun_id_int_to_fmt, uint64_t, (int lun_id), 0); @@ -294,7 +298,8 @@ maxburstlength_test(void) lun.id = 0; - dev.lun[0] = &lun; + TAILQ_INIT(&dev.luns); + TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq); conn.full_feature = 1; conn.sess = &sess; @@ -380,7 +385,8 @@ underflow_for_read_transfer_test(void) conn.sess = &sess; conn.MaxRecvDataSegmentLength = 8192; - dev.lun[0] = &lun; + TAILQ_INIT(&dev.luns); + TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq); conn.dev = &dev; pdu = iscsi_get_pdu(&conn); @@ -443,7 +449,8 @@ underflow_for_zero_read_transfer_test(void) conn.sess = &sess; conn.MaxRecvDataSegmentLength = 8192; - dev.lun[0] = &lun; + TAILQ_INIT(&dev.luns); + TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq); conn.dev = &dev; pdu = iscsi_get_pdu(&conn); @@ -508,7 +515,8 @@ underflow_for_request_sense_test(void) conn.sess = &sess; conn.MaxRecvDataSegmentLength = 8192; - dev.lun[0] = &lun; + TAILQ_INIT(&dev.luns); + TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq); conn.dev = &dev; pdu1 = iscsi_get_pdu(&conn); @@ -598,7 +606,8 @@ underflow_for_check_condition_test(void) conn.sess = &sess; conn.MaxRecvDataSegmentLength = 8192; - dev.lun[0] = &lun; + TAILQ_INIT(&dev.luns); + TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq); conn.dev = &dev; pdu = iscsi_get_pdu(&conn); @@ -1627,7 +1636,8 @@ pdu_hdr_op_scsi_test(void) CU_ASSERT(pdu.task == NULL); /* Case 5 - SCSI read command PDU is correct, and the configured iSCSI task is set to the PDU. */ - dev.lun[0] = &lun; + TAILQ_INIT(&dev.luns); + TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq); rc = iscsi_pdu_hdr_op_scsi(&conn, &pdu); CU_ASSERT(rc == 0); @@ -1750,7 +1760,8 @@ pdu_hdr_op_task_mgmt_test(void) check_iscsi_task_mgmt_response(ISCSI_TASK_FUNC_RESP_LUN_NOT_EXIST, 1234, 0, 0, 1); /* Case 3 - Unassigned function is specified. "Function rejected" response is sent. */ - dev.lun[0] = &lun; + TAILQ_INIT(&dev.luns); + TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq); task_reqh->flags = 0; rc = iscsi_pdu_hdr_op_task(&conn, &pdu); @@ -1960,7 +1971,8 @@ pdu_hdr_op_data_test(void) /* Case 10 - SCSI Data-Out PDU is correct and processed. Its F bit is 0 and hence * R2T is not sent. */ - dev.lun[0] = &lun; + TAILQ_INIT(&dev.luns); + TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq); to_be32(&data_reqh->data_sn, primary.r2t_datasn); to_be32(&data_reqh->buffer_offset, primary.next_expected_r2t_offset); @@ -2179,7 +2191,7 @@ static void data_out_pdu_sequence_test(void) { struct spdk_scsi_lun lun = { .tasks = TAILQ_HEAD_INITIALIZER(lun.tasks), }; - struct spdk_scsi_dev dev = { .lun[0] = &lun, }; + struct spdk_scsi_dev dev = { .luns = TAILQ_HEAD_INITIALIZER(dev.luns), }; struct spdk_iscsi_sess sess = { .session_type = SESSION_TYPE_NORMAL, .MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH, @@ -2197,6 +2209,8 @@ data_out_pdu_sequence_test(void) struct iscsi_bhs_data_out *data_reqh; int rc; + TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq); + mobj1.buf = calloc(1, SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH)); SPDK_CU_ASSERT_FATAL(mobj1.buf != NULL); diff --git a/test/unit/lib/iscsi/tgt_node.c/tgt_node_ut.c b/test/unit/lib/iscsi/tgt_node.c/tgt_node_ut.c index 9b21663ff..2eebed21e 100644 --- a/test/unit/lib/iscsi/tgt_node.c/tgt_node_ut.c +++ b/test/unit/lib/iscsi/tgt_node.c/tgt_node_ut.c @@ -91,11 +91,15 @@ DEFINE_STUB(iscsi_portal_grp_find_portal_by_addr, struct spdk_scsi_lun * spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id) { - if (lun_id < 0 || lun_id >= SPDK_SCSI_DEV_MAX_LUN) { - return NULL; + struct spdk_scsi_lun *lun; + + TAILQ_FOREACH(lun, &dev->luns, tailq) { + if (lun->id == lun_id) { + break; + } } - return dev->lun[lun_id]; + return lun; } int diff --git a/test/unit/lib/scsi/dev.c/dev_ut.c b/test/unit/lib/scsi/dev.c/dev_ut.c index 410d14eff..ca6b614c2 100644 --- a/test/unit/lib/scsi/dev.c/dev_ut.c +++ b/test/unit/lib/scsi/dev.c/dev_ut.c @@ -151,7 +151,7 @@ dev_destruct_null_lun(void) struct spdk_scsi_dev dev = { .is_allocated = 1 }; /* pass null for the lun */ - dev.lun[0] = NULL; + TAILQ_INIT(&dev.luns); /* free the dev */ spdk_scsi_dev_destruct(&dev, NULL, NULL); @@ -160,7 +160,10 @@ dev_destruct_null_lun(void) static void dev_destruct_success(void) { - struct spdk_scsi_dev dev = { .is_allocated = 1 }; + struct spdk_scsi_dev dev = { + .is_allocated = 1, + .luns = TAILQ_HEAD_INITIALIZER(dev.luns), + }; int rc; /* dev with a single lun */ @@ -543,11 +546,11 @@ static void dev_add_lun_bdev_not_found(void) { int rc; - struct spdk_scsi_dev dev = {0}; + struct spdk_scsi_dev dev = { .luns = TAILQ_HEAD_INITIALIZER(dev.luns), }; rc = spdk_scsi_dev_add_lun(&dev, "malloc3", 0, NULL, NULL); - SPDK_CU_ASSERT_FATAL(dev.lun[0] == NULL); + SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&dev.luns)); CU_ASSERT_NOT_EQUAL(rc, 0); } @@ -556,11 +559,12 @@ dev_add_lun_no_free_lun_id(void) { int rc; int i; - struct spdk_scsi_dev dev = {0}; - struct spdk_scsi_lun lun; + struct spdk_scsi_dev dev = { .luns = TAILQ_HEAD_INITIALIZER(dev.luns), }; + struct spdk_scsi_lun lun[SPDK_SCSI_DEV_MAX_LUN] = { 0 }; for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { - dev.lun[i] = &lun; + lun[i].id = i; + TAILQ_INSERT_TAIL(&dev.luns, &lun[i], tailq); } rc = spdk_scsi_dev_add_lun(&dev, "malloc0", -1, NULL, NULL); @@ -572,7 +576,7 @@ static void dev_add_lun_success1(void) { int rc; - struct spdk_scsi_dev dev = {0}; + struct spdk_scsi_dev dev = { .luns = TAILQ_HEAD_INITIALIZER(dev.luns), }; rc = spdk_scsi_dev_add_lun(&dev, "malloc0", -1, NULL, NULL); @@ -585,7 +589,7 @@ static void dev_add_lun_success2(void) { int rc; - struct spdk_scsi_dev dev = {0}; + struct spdk_scsi_dev dev = { .luns = TAILQ_HEAD_INITIALIZER(dev.luns), }; rc = spdk_scsi_dev_add_lun(&dev, "malloc0", 0, NULL, NULL); @@ -597,8 +601,8 @@ dev_add_lun_success2(void) static void dev_check_pending_tasks(void) { - struct spdk_scsi_dev dev = {}; - struct spdk_scsi_lun lun = {}; + struct spdk_scsi_dev dev = { .luns = TAILQ_HEAD_INITIALIZER(dev.luns), }; + struct spdk_scsi_lun lun = { .id = SPDK_SCSI_DEV_MAX_LUN - 1, }; struct spdk_scsi_port initiator_port = {}; g_initiator_port_with_pending_tasks = NULL; @@ -606,7 +610,7 @@ dev_check_pending_tasks(void) CU_ASSERT(spdk_scsi_dev_has_pending_tasks(&dev, NULL) == false); - dev.lun[SPDK_SCSI_DEV_MAX_LUN - 1] = &lun; + TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq); CU_ASSERT(spdk_scsi_dev_has_pending_tasks(&dev, NULL) == true); CU_ASSERT(spdk_scsi_dev_has_pending_tasks(&dev, &initiator_port) == false); @@ -651,6 +655,150 @@ dev_iterate_luns(void) spdk_scsi_dev_destruct(dev, NULL, NULL); } +static void +dev_find_free_lun(void) +{ + struct spdk_scsi_dev dev = { .luns = TAILQ_HEAD_INITIALIZER(dev.luns), }; + struct spdk_scsi_lun *lun, *prev_lun; + int i, rc; + + lun = calloc(SPDK_SCSI_DEV_MAX_LUN, sizeof(*lun)); + SPDK_CU_ASSERT_FATAL(lun != NULL); + + for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { + lun[i].id = i; + } + + /* LUN ID 0, 1, 15, 16, 17, SPDK_SCSI_DEV_MAX_LUN - 2, and SPDK_SCSI_DEV_MAX_LUN - 1 + * are free first. LUNs are required to be sorted by LUN ID. + */ + for (i = 2; i < 15; i++) { + TAILQ_INSERT_TAIL(&dev.luns, &lun[i], tailq); + } + + for (i = 18; i < SPDK_SCSI_DEV_MAX_LUN - 2; i++) { + TAILQ_INSERT_TAIL(&dev.luns, &lun[i], tailq); + } + + rc = scsi_dev_find_free_lun(&dev, -1, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == NULL); + + rc = scsi_dev_find_free_lun(&dev, 0, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == NULL); + + rc = scsi_dev_find_free_lun(&dev, 1, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == NULL); + + rc = scsi_dev_find_free_lun(&dev, 2, &prev_lun); + CU_ASSERT(rc == -EEXIST); + + TAILQ_INSERT_HEAD(&dev.luns, &lun[0], tailq); + + rc = scsi_dev_find_free_lun(&dev, 0, &prev_lun); + CU_ASSERT(rc == -EEXIST); + + rc = scsi_dev_find_free_lun(&dev, -1, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[0]); + prev_lun = NULL; + + rc = scsi_dev_find_free_lun(&dev, 1, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[0]); + prev_lun = NULL; + + TAILQ_INSERT_AFTER(&dev.luns, &lun[0], &lun[1], tailq); + + rc = scsi_dev_find_free_lun(&dev, 1, &prev_lun); + CU_ASSERT(rc == -EEXIST); + + rc = scsi_dev_find_free_lun(&dev, -1, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[14]); + prev_lun = NULL; + + rc = scsi_dev_find_free_lun(&dev, 15, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[14]); + prev_lun = NULL; + + rc = scsi_dev_find_free_lun(&dev, 16, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[14]); + prev_lun = NULL; + + rc = scsi_dev_find_free_lun(&dev, 17, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[14]); + prev_lun = NULL; + + TAILQ_INSERT_AFTER(&dev.luns, &lun[14], &lun[15], tailq); + TAILQ_INSERT_AFTER(&dev.luns, &lun[15], &lun[16], tailq); + TAILQ_INSERT_AFTER(&dev.luns, &lun[16], &lun[17], tailq); + + rc = scsi_dev_find_free_lun(&dev, 15, &prev_lun); + CU_ASSERT(rc == -EEXIST); + + rc = scsi_dev_find_free_lun(&dev, 16, &prev_lun); + CU_ASSERT(rc == -EEXIST); + + rc = scsi_dev_find_free_lun(&dev, 17, &prev_lun); + CU_ASSERT(rc == -EEXIST); + + rc = scsi_dev_find_free_lun(&dev, -1, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[SPDK_SCSI_DEV_MAX_LUN - 3]); + prev_lun = NULL; + + rc = scsi_dev_find_free_lun(&dev, SPDK_SCSI_DEV_MAX_LUN - 2, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[SPDK_SCSI_DEV_MAX_LUN - 3]); + prev_lun = NULL; + + rc = scsi_dev_find_free_lun(&dev, SPDK_SCSI_DEV_MAX_LUN - 1, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[SPDK_SCSI_DEV_MAX_LUN - 3]); + prev_lun = NULL; + + TAILQ_INSERT_AFTER(&dev.luns, &lun[SPDK_SCSI_DEV_MAX_LUN - 3], + &lun[SPDK_SCSI_DEV_MAX_LUN - 1], tailq); + + rc = scsi_dev_find_free_lun(&dev, -1, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[SPDK_SCSI_DEV_MAX_LUN - 3]); + prev_lun = NULL; + + rc = scsi_dev_find_free_lun(&dev, SPDK_SCSI_DEV_MAX_LUN - 2, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[SPDK_SCSI_DEV_MAX_LUN - 3]); + prev_lun = NULL; + + TAILQ_INSERT_AFTER(&dev.luns, &lun[SPDK_SCSI_DEV_MAX_LUN - 3], + &lun[SPDK_SCSI_DEV_MAX_LUN - 2], tailq); + + rc = scsi_dev_find_free_lun(&dev, -1, &prev_lun); + CU_ASSERT(rc == -ENOSPC); + + /* LUN ID 20 and 21 were freed. */ + TAILQ_REMOVE(&dev.luns, &lun[20], tailq); + TAILQ_REMOVE(&dev.luns, &lun[21], tailq); + + rc = scsi_dev_find_free_lun(&dev, -1, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[19]); + prev_lun = NULL; + + rc = scsi_dev_find_free_lun(&dev, 21, &prev_lun); + CU_ASSERT(rc == 0); + CU_ASSERT(prev_lun == &lun[19]); + prev_lun = NULL; + + free(lun); +} + int main(int argc, char **argv) { @@ -690,6 +838,7 @@ main(int argc, char **argv) CU_ADD_TEST(suite, dev_add_lun_success2); CU_ADD_TEST(suite, dev_check_pending_tasks); CU_ADD_TEST(suite, dev_iterate_luns); + CU_ADD_TEST(suite, dev_find_free_lun); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests();