From 3b3c6002c9a88a811bb9038809ca4f172c234a63 Mon Sep 17 00:00:00 2001 From: Shuhei Matsumoto Date: Fri, 12 Jan 2018 09:42:02 +0900 Subject: [PATCH] iscsi: Add LUN to an existing target (not runtime) Removing an LUN from an existing iSCSI target is possible by removing the corresponding BDEV. However adding an LUN to an existing iSCSI target is not possible yet. Add a new function spdk_iscsi_tgt_node_add_lun() and related functions first toward supporting this function. JSON-RPC for this operation will be submitted an another patch. Informing the newly added LUN to the initiator is not included in this patch. Hence this operation is possible only for any inactive target. Change-Id: I3a28f4d75a17126e49c9d12ce64c3ad68f231840 Signed-off-by: Shuhei Matsumoto Reviewed-on: https://review.gerrithub.io/385180 Tested-by: SPDK Automated Test System Reviewed-by: Jim Harris Reviewed-by: Ben Walker --- include/spdk/scsi.h | 4 +- lib/iscsi/tgt_node.c | 33 +++++++++ lib/iscsi/tgt_node.h | 2 + lib/scsi/dev.c | 76 +++++++++++++------- test/unit/lib/iscsi/tgt_node.c/tgt_node_ut.c | 66 ++++++++++++++++- test/unit/lib/scsi/dev.c/dev_ut.c | 72 +++++++++++++++++++ 6 files changed, 226 insertions(+), 27 deletions(-) diff --git a/include/spdk/scsi.h b/include/spdk/scsi.h index 3e34601b7..ff8ac87dd 100644 --- a/include/spdk/scsi.h +++ b/include/spdk/scsi.h @@ -192,7 +192,9 @@ struct spdk_scsi_dev *spdk_scsi_dev_construct(const char *name, void *hotremove_ctx); void spdk_scsi_dev_delete_lun(struct spdk_scsi_dev *dev, struct spdk_scsi_lun *lun); - +int spdk_scsi_dev_add_lun(struct spdk_scsi_dev *dev, const char *bdev_name, int lun_id, + void (*hotremove_cb)(const struct spdk_scsi_lun *, void *), + void *hotremove_ctx); struct spdk_scsi_port *spdk_scsi_port_create(uint64_t id, uint16_t index, const char *name); void spdk_scsi_port_free(struct spdk_scsi_port **pport); diff --git a/lib/iscsi/tgt_node.c b/lib/iscsi/tgt_node.c index 3268df04b..5aa1275d8 100644 --- a/lib/iscsi/tgt_node.c +++ b/lib/iscsi/tgt_node.c @@ -1294,3 +1294,36 @@ void spdk_iscsi_tgt_node_delete_map(struct spdk_iscsi_portal_grp *portal_group, } pthread_mutex_unlock(&g_spdk_iscsi.mutex); } + +int +spdk_iscsi_tgt_node_add_lun(struct spdk_iscsi_tgt_node *target, + const char *bdev_name, int lun_id) +{ + struct spdk_scsi_dev *dev; + int rc; + + if (target->num_active_conns > 0) { + SPDK_ERRLOG("Target has active connections (count=%d)\n", + target->num_active_conns); + return -1; + } + + if (lun_id < -1 || lun_id >= SPDK_SCSI_DEV_MAX_LUN) { + SPDK_ERRLOG("Specified LUN ID (%d) is invalid\n", lun_id); + return -1; + } + + dev = target->dev; + if (dev == NULL) { + SPDK_ERRLOG("SCSI device is not found\n"); + return -1; + } + + rc = spdk_scsi_dev_add_lun(dev, bdev_name, lun_id, NULL, NULL); + if (rc != 0) { + SPDK_ERRLOG("spdk_scsi_dev_add_lun failed\n"); + return -1; + } + + return 0; +} diff --git a/lib/iscsi/tgt_node.h b/lib/iscsi/tgt_node.h index 8f94f13bf..2bc3623ca 100644 --- a/lib/iscsi/tgt_node.h +++ b/lib/iscsi/tgt_node.h @@ -132,4 +132,6 @@ int spdk_iscsi_tgt_node_cleanup_luns(struct spdk_iscsi_conn *conn, struct spdk_iscsi_tgt_node *target); void spdk_iscsi_tgt_node_delete_map(struct spdk_iscsi_portal_grp *portal_group, struct spdk_iscsi_init_grp *initiator_group); +int spdk_iscsi_tgt_node_add_lun(struct spdk_iscsi_tgt_node *target, + const char *bdev_name, int lun_id); #endif /* SPDK_ISCSI_TGT_NODE_H_ */ diff --git a/lib/scsi/dev.c b/lib/scsi/dev.c index 1221d84a8..aa5f1d5dc 100644 --- a/lib/scsi/dev.c +++ b/lib/scsi/dev.c @@ -102,13 +102,53 @@ spdk_scsi_dev_destruct(struct spdk_scsi_dev *dev) } } -static void -spdk_scsi_dev_add_lun(struct spdk_scsi_dev *dev, - struct spdk_scsi_lun *lun, int id) +static int +spdk_scsi_dev_find_lowest_free_lun_id(struct spdk_scsi_dev *dev) { - lun->id = id; + int i; + + for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { + if (dev->lun[i] == NULL) { + return i; + } + } + + return -1; +} + +int +spdk_scsi_dev_add_lun(struct spdk_scsi_dev *dev, const char *bdev_name, int lun_id, + void (*hotremove_cb)(const struct spdk_scsi_lun *, void *), + void *hotremove_ctx) +{ + struct spdk_bdev *bdev; + struct spdk_scsi_lun *lun; + + bdev = spdk_bdev_get_by_name(bdev_name); + if (bdev == NULL) { + SPDK_ERRLOG("device %s: cannot find bdev '%s' (target %d)\n", + dev->name, bdev_name, lun_id); + return -1; + } + + /* Search the lowest free LUN ID if LUN ID is default */ + if (lun_id == -1) { + lun_id = spdk_scsi_dev_find_lowest_free_lun_id(dev); + if (lun_id == -1) { + SPDK_ERRLOG("Free LUN ID is not found\n"); + return -1; + } + } + + lun = spdk_scsi_lun_construct(bdev, hotremove_cb, hotremove_ctx); + if (lun == NULL) { + return -1; + } + + lun->id = lun_id; lun->dev = dev; - dev->lun[id] = lun; + dev->lun[lun_id] = lun; + return 0; } void @@ -145,10 +185,8 @@ spdk_scsi_dev_construct(const char *name, const char *bdev_name_list[], void *hotremove_ctx) { struct spdk_scsi_dev *dev; - struct spdk_bdev *bdev; - struct spdk_scsi_lun *lun = NULL; bool found_lun_0; - int i; + int i, rc; if (num_luns == 0) { SPDK_ERRLOG("device %s: no LUNs specified\n", name); @@ -187,27 +225,15 @@ spdk_scsi_dev_construct(const char *name, const char *bdev_name_list[], dev->protocol_id = protocol_id; for (i = 0; i < num_luns; i++) { - bdev = spdk_bdev_get_by_name(bdev_name_list[i]); - if (bdev == NULL) { - SPDK_ERRLOG("device %s: cannot find bdev '%s' (target %d)\n", - name, bdev_name_list[i], i); - goto error; + rc = spdk_scsi_dev_add_lun(dev, bdev_name_list[i], lun_id_list[i], + hotremove_cb, hotremove_ctx); + if (rc < 0) { + spdk_scsi_dev_destruct(dev); + return NULL; } - - lun = spdk_scsi_lun_construct(bdev, hotremove_cb, hotremove_ctx); - if (lun == NULL) { - goto error; - } - - spdk_scsi_dev_add_lun(dev, lun, lun_id_list[i]); } return dev; - -error: - spdk_scsi_dev_destruct(dev); - - return NULL; } void 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 050a1d392..0f1793c7c 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 @@ -95,6 +95,69 @@ spdk_scsi_dev_get_lun(struct spdk_scsi_dev *dev, int lun_id) return dev->lun[lun_id]; } +int +spdk_scsi_dev_add_lun(struct spdk_scsi_dev *dev, const char *bdev_name, int lun_id, + void (*hotremove_cb)(const struct spdk_scsi_lun *, void *), + void *hotremove_ctx) +{ + if (bdev_name == NULL) { + return -1; + } else { + return 0; + } +} + +static void +add_lun_test_cases(void) +{ + struct spdk_iscsi_tgt_node tgtnode; + int lun_id = 0; + char *bdev_name = NULL; + struct spdk_scsi_dev scsi_dev; + int rc; + + memset(&tgtnode, 0, sizeof(struct spdk_iscsi_tgt_node)); + memset(&scsi_dev, 0, sizeof(struct spdk_scsi_dev)); + + /* case 1 */ + tgtnode.num_active_conns = 1; + + rc = spdk_iscsi_tgt_node_add_lun(&tgtnode, bdev_name, lun_id); + CU_ASSERT(rc != 0); + + /* case 2 */ + tgtnode.num_active_conns = 0; + lun_id = -2; + + rc = spdk_iscsi_tgt_node_add_lun(&tgtnode, bdev_name, lun_id); + CU_ASSERT(rc != 0); + + /* case 3 */ + lun_id = SPDK_SCSI_DEV_MAX_LUN; + + rc = spdk_iscsi_tgt_node_add_lun(&tgtnode, bdev_name, lun_id); + CU_ASSERT(rc != 0); + + /* case 4 */ + lun_id = -1; + tgtnode.dev = NULL; + + rc = spdk_iscsi_tgt_node_add_lun(&tgtnode, bdev_name, lun_id); + CU_ASSERT(rc != 0); + + /* case 5 */ + tgtnode.dev = &scsi_dev; + + rc = spdk_iscsi_tgt_node_add_lun(&tgtnode, bdev_name, lun_id); + CU_ASSERT(rc != 0); + + /* case 6 */ + bdev_name = "LUN0"; + + rc = spdk_iscsi_tgt_node_add_lun(&tgtnode, bdev_name, lun_id); + CU_ASSERT(rc == 0); +} + static void config_file_fail_cases(void) { @@ -755,7 +818,8 @@ main(int argc, char **argv) } if ( - CU_add_test(suite, "config file fail cases", config_file_fail_cases) == NULL + CU_add_test(suite, "add lun test cases", add_lun_test_cases) == NULL + || CU_add_test(suite, "config file fail cases", config_file_fail_cases) == NULL || CU_add_test(suite, "allow any allowed case", allow_any_allowed) == NULL || CU_add_test(suite, "allow ipv6 allowed case", allow_ipv6_allowed) == NULL || CU_add_test(suite, "allow ipv6 denied case", allow_ipv6_denied) == NULL diff --git a/test/unit/lib/scsi/dev.c/dev_ut.c b/test/unit/lib/scsi/dev.c/dev_ut.c index 9a4264876..27eef447e 100644 --- a/test/unit/lib/scsi/dev.c/dev_ut.c +++ b/test/unit/lib/scsi/dev.c/dev_ut.c @@ -531,6 +531,70 @@ dev_find_port_by_id_success(void) } } +static void +dev_add_lun_bdev_not_found(void) +{ + int rc; + struct spdk_scsi_dev dev = {0}; + + rc = spdk_scsi_dev_add_lun(&dev, "malloc2", -1, NULL, NULL); + + CU_ASSERT_NOT_EQUAL(rc, 0); +} + +static void +dev_add_lun_no_free_lun_id(void) +{ + int rc; + int i; + struct spdk_scsi_dev dev = {0}; + struct spdk_scsi_lun lun; + + for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { + dev.lun[i] = &lun; + } + + rc = spdk_scsi_dev_add_lun(&dev, "malloc0", -1, NULL, NULL); + + CU_ASSERT_NOT_EQUAL(rc, 0); +} + +static void +dev_add_lun_success1(void) +{ + int rc; + int i; + struct spdk_scsi_dev dev; + + for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { + dev.lun[i] = NULL; + } + + rc = spdk_scsi_dev_add_lun(&dev, "malloc0", -1, NULL, NULL); + + CU_ASSERT_EQUAL(rc, 0); + + spdk_scsi_dev_destruct(&dev); +} + +static void +dev_add_lun_success2(void) +{ + int rc; + int i; + struct spdk_scsi_dev dev; + + for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { + dev.lun[i] = NULL; + } + + rc = spdk_scsi_dev_add_lun(&dev, "malloc0", 0, NULL, NULL); + + CU_ASSERT_EQUAL(rc, 0); + + spdk_scsi_dev_destruct(&dev); +} + int main(int argc, char **argv) { @@ -585,6 +649,14 @@ main(int argc, char **argv) dev_find_port_by_id_id_not_found_failure) == NULL || CU_add_test(suite, "dev find port by id - success", dev_find_port_by_id_success) == NULL + || CU_add_test(suite, "dev add lun - bdev not found", + dev_add_lun_bdev_not_found) == NULL + || CU_add_test(suite, "dev add lun - no free lun id", + dev_add_lun_no_free_lun_id) == NULL + || CU_add_test(suite, "dev add lun - success 1", + dev_add_lun_success1) == NULL + || CU_add_test(suite, "dev add lun - success 2", + dev_add_lun_success2) == NULL ) { CU_cleanup_registry(); return CU_get_error();