diff --git a/lib/nvmf/ctrlr.c b/lib/nvmf/ctrlr.c index 19ddc94e3..ff76cd901 100644 --- a/lib/nvmf/ctrlr.c +++ b/lib/nvmf/ctrlr.c @@ -182,8 +182,8 @@ nvmf_ctrlr_keep_alive_poll(void *ctx) keep_alive_timeout_tick = ctrlr->last_keep_alive_tick + ctrlr->feat.keep_alive_timer.bits.kato * spdk_get_ticks_hz() / UINT64_C(1000); if (now > keep_alive_timeout_tick) { - SPDK_NOTICELOG("Disconnecting host from subsystem %s due to keep alive timeout.\n", - ctrlr->subsys->subnqn); + SPDK_NOTICELOG("Disconnecting host %s from subsystem %s due to keep alive timeout.\n", + ctrlr->hostnqn, ctrlr->subsys->subnqn); /* set the Controller Fatal Status bit to '1' */ if (ctrlr->vcprop.csts.bits.cfs == 0) { ctrlr->vcprop.csts.bits.cfs = 1; @@ -591,6 +591,15 @@ _nvmf_ctrlr_add_io_qpair(void *ctx) } admin_qpair = ctrlr->admin_qpair; + if (admin_qpair->state != SPDK_NVMF_QPAIR_ACTIVE || admin_qpair->group == NULL) { + /* There is a chance that admin qpair is being destroyed at this moment due to e.g. + * expired keep alive timer. Part of the qpair destruction process is change of qpair's + * state to DEACTIVATING and removing it from poll group */ + SPDK_ERRLOG("Inactive admin qpair (state %d, group %p)\n", admin_qpair->state, admin_qpair->group); + SPDK_NVMF_INVALID_CONNECT_CMD(rsp, qid); + spdk_nvmf_request_complete(req); + return; + } qpair->ctrlr = ctrlr; spdk_thread_send_msg(admin_qpair->group->thread, nvmf_ctrlr_add_io_qpair, req); } diff --git a/test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c b/test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c index 280ec1dbb..411e84bf8 100644 --- a/test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c +++ b/test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c @@ -380,6 +380,7 @@ test_connect(void) memset(&admin_qpair, 0, sizeof(admin_qpair)); admin_qpair.group = &group; + admin_qpair.state = SPDK_NVMF_QPAIR_ACTIVE; memset(&tgt, 0, sizeof(tgt)); memset(&transport, 0, sizeof(transport)); @@ -765,6 +766,21 @@ test_connect(void) CU_ASSERT(qpair.ctrlr == NULL); CU_ASSERT(sgroups[subsystem.id].io_outstanding == 0); + /* I/O connect when admin qpair is being destroyed */ + admin_qpair.group = NULL; + admin_qpair.state = SPDK_NVMF_QPAIR_DEACTIVATING; + memset(&rsp, 0, sizeof(rsp)); + sgroups[subsystem.id].io_outstanding++; + TAILQ_INSERT_TAIL(&qpair.outstanding, &req, link); + rc = nvmf_ctrlr_cmd_connect(&req); + poll_threads(); + CU_ASSERT(rsp.nvme_cpl.status.sct == SPDK_NVME_SCT_COMMAND_SPECIFIC); + CU_ASSERT(rsp.nvme_cpl.status.sc == SPDK_NVMF_FABRIC_SC_INVALID_PARAM); + CU_ASSERT(qpair.ctrlr == NULL); + CU_ASSERT(sgroups[subsystem.id].io_outstanding == 0); + admin_qpair.group = &group; + admin_qpair.state = SPDK_NVMF_QPAIR_ACTIVE; + /* Clean up globals */ MOCK_CLEAR(spdk_nvmf_tgt_find_subsystem); MOCK_CLEAR(spdk_nvmf_poll_group_create);