From 5215fad6efebc6eac698412197cdad5120cc166a Mon Sep 17 00:00:00 2001 From: Seth Howell Date: Mon, 7 Oct 2019 16:41:23 -0700 Subject: [PATCH] nvme: Add an API for updating a controller trid. This can be useful when trying to perform multipath failover at the application level. However, the controller must be in the failed state before calling this function. Change-Id: I5403c0036fed5dd3600ee20592925297494ba8aa Signed-off-by: Seth Howell Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/470699 Reviewed-by: Jim Harris Reviewed-by: Shuhei Matsumoto Tested-by: SPDK CI Jenkins --- include/spdk/nvme.h | 19 +++++++++++ lib/nvme/nvme_ctrlr.c | 29 ++++++++++++++++ .../lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c | 33 +++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index 4e44c926d..6b1f7464c 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -693,6 +693,25 @@ int spdk_nvme_probe_poll_async(struct spdk_nvme_probe_ctx *probe_ctx); */ int spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr); +/** + * Update the transport ID for a given controller. + * + * This function allows the user to set a new trid for a controller only if the + * controller is failed. The controller's failed state can be obtained from + * spdk_nvme_ctrlr_is_failed(). The controller can also be forced to the failed + * state using spdk_nvme_ctrlr_fail(). + * + * This function also requires that the transport type and subnqn of the new trid + * be the same as the old trid. + * + * \param ctrlr Opaque handle to an NVMe controller. + * \param trid The new transport ID. + * + * \return 0 on success, -EINVAL if the trid is invalid, + * -EPERM if the ctrlr is not failed. + */ +int spdk_nvme_ctrlr_set_trid(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_transport_id *trid); + /** * Perform a full hardware reset of the NVMe controller. * diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index 953f22a28..2eecfd837 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -1107,6 +1107,35 @@ out: return rc; } +int +spdk_nvme_ctrlr_set_trid(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_transport_id *trid) +{ + int rc = 0; + + nvme_robust_mutex_lock(&ctrlr->ctrlr_lock); + + if (ctrlr->is_failed == false) { + rc = -EPERM; + goto out; + } + + if (trid->trtype != ctrlr->trid.trtype) { + rc = -EINVAL; + goto out; + } + + if (strncmp(trid->subnqn, ctrlr->trid.subnqn, SPDK_NVMF_NQN_MAX_LEN)) { + rc = -EINVAL; + goto out; + } + + ctrlr->trid = *trid; + +out: + nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock); + return rc; +} + static void nvme_ctrlr_identify_done(void *arg, const struct spdk_nvme_cpl *cpl) { diff --git a/test/unit/lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c b/test/unit/lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c index 307ff0e38..3f7a9df41 100644 --- a/test/unit/lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c +++ b/test/unit/lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c @@ -1890,6 +1890,38 @@ test_nvme_ctrlr_init_delay(void) nvme_ctrlr_destruct(&ctrlr); } +static void +test_spdk_nvme_ctrlr_set_trid(void) +{ + struct spdk_nvme_ctrlr ctrlr = {0}; + struct spdk_nvme_transport_id new_trid = {0}; + + ctrlr.is_failed = false; + ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_RDMA; + snprintf(ctrlr.trid.subnqn, SPDK_NVMF_NQN_MAX_LEN, "%s", "nqn.2016-06.io.spdk:cnode1"); + snprintf(ctrlr.trid.traddr, SPDK_NVMF_TRADDR_MAX_LEN, "%s", "192.168.100.8"); + snprintf(ctrlr.trid.trsvcid, SPDK_NVMF_TRSVCID_MAX_LEN, "%s", "4420"); + CU_ASSERT(spdk_nvme_ctrlr_set_trid(&ctrlr, &new_trid) == -EPERM); + + ctrlr.is_failed = true; + new_trid.trtype = SPDK_NVME_TRANSPORT_TCP; + CU_ASSERT(spdk_nvme_ctrlr_set_trid(&ctrlr, &new_trid) == -EINVAL); + CU_ASSERT(ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_RDMA); + + new_trid.trtype = SPDK_NVME_TRANSPORT_RDMA; + snprintf(new_trid.subnqn, SPDK_NVMF_NQN_MAX_LEN, "%s", "nqn.2016-06.io.spdk:cnode2"); + CU_ASSERT(spdk_nvme_ctrlr_set_trid(&ctrlr, &new_trid) == -EINVAL); + CU_ASSERT(strncmp(ctrlr.trid.subnqn, "nqn.2016-06.io.spdk:cnode1", SPDK_NVMF_NQN_MAX_LEN) == 0); + + + snprintf(new_trid.subnqn, SPDK_NVMF_NQN_MAX_LEN, "%s", "nqn.2016-06.io.spdk:cnode1"); + snprintf(new_trid.traddr, SPDK_NVMF_TRADDR_MAX_LEN, "%s", "192.168.100.9"); + snprintf(new_trid.trsvcid, SPDK_NVMF_TRSVCID_MAX_LEN, "%s", "4421"); + CU_ASSERT(spdk_nvme_ctrlr_set_trid(&ctrlr, &new_trid) == 0); + CU_ASSERT(strncmp(ctrlr.trid.traddr, "192.168.100.9", SPDK_NVMF_TRADDR_MAX_LEN) == 0); + CU_ASSERT(strncmp(ctrlr.trid.trsvcid, "4421", SPDK_NVMF_TRSVCID_MAX_LEN) == 0); +} + int main(int argc, char **argv) { CU_pSuite suite = NULL; @@ -1944,6 +1976,7 @@ int main(int argc, char **argv) test_nvme_ctrlr_test_active_ns) == NULL || CU_add_test(suite, "test_spdk_nvme_ctrlr_reconnect_io_qpair", test_spdk_nvme_ctrlr_reconnect_io_qpair) == NULL + || CU_add_test(suite, "test_spdk_nvme_ctrlr_set_trid", test_spdk_nvme_ctrlr_set_trid) == NULL ) { CU_cleanup_registry(); return CU_get_error();