diff --git a/include/spdk/nvmf.h b/include/spdk/nvmf.h index 02dfddf9c..9a19bf039 100644 --- a/include/spdk/nvmf.h +++ b/include/spdk/nvmf.h @@ -131,7 +131,7 @@ struct spdk_nvmf_subsystem { char subnqn[SPDK_NVMF_NQN_MAX_LEN]; enum spdk_nvmf_subsystem_mode mode; enum spdk_nvmf_subtype subtype; - + bool is_removed; union { struct { struct spdk_nvme_ctrlr *ctrlr; diff --git a/lib/nvmf/request.c b/lib/nvmf/request.c index b8f6f2063..de642b5d6 100644 --- a/lib/nvmf/request.c +++ b/lib/nvmf/request.c @@ -364,10 +364,23 @@ spdk_nvmf_request_exec(struct spdk_nvmf_request *req) if (subsystem->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY) { status = nvmf_process_discovery_cmd(req); } else { - status = subsystem->ops->process_admin_cmd(req); + if (subsystem->is_removed) { + rsp->status.sc = SPDK_NVME_SC_ABORTED_BY_REQUEST; + status = SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } else { + status = subsystem->ops->process_admin_cmd(req); + } } } else { - status = session->subsys->ops->process_io_cmd(req); + struct spdk_nvmf_subsystem *subsystem; + + subsystem = session->subsys; + if (subsystem->is_removed) { + rsp->status.sc = SPDK_NVME_SC_ABORTED_BY_REQUEST; + status = SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } else { + status = session->subsys->ops->process_io_cmd(req); + } } switch (status) { diff --git a/lib/nvmf/session.c b/lib/nvmf/session.c index 348c42ed5..2673a1f47 100644 --- a/lib/nvmf/session.c +++ b/lib/nvmf/session.c @@ -619,12 +619,32 @@ int spdk_nvmf_session_poll(struct spdk_nvmf_session *session) { struct spdk_nvmf_conn *conn, *tmp; + struct spdk_nvmf_subsystem *subsys = session->subsys; + + if (subsys->is_removed && subsys->mode == NVMF_SUBSYSTEM_MODE_VIRTUAL) { + if (session->aer_req) { + struct spdk_nvmf_request *aer = session->aer_req; + + aer->rsp->nvme_cpl.status.sct = SPDK_NVME_SCT_GENERIC; + aer->rsp->nvme_cpl.status.sc = SPDK_NVME_SC_ABORTED_SQ_DELETION; + aer->rsp->nvme_cpl.status.dnr = 0; + spdk_nvmf_request_complete(aer); + session->aer_req = NULL; + } + } TAILQ_FOREACH_SAFE(conn, &session->connections, link, tmp) { if (conn->transport->conn_poll(conn) < 0) { SPDK_ERRLOG("Transport poll failed for conn %p; closing connection\n", conn); spdk_nvmf_session_disconnect(conn); } + if (subsys->subtype == SPDK_NVMF_SUBTYPE_NVME) { + if (subsys->is_removed && conn->transport->conn_is_idle(conn)) { + if (subsys->ops->detach) { + subsys->ops->detach(subsys); + } + } + } } return 0; diff --git a/lib/nvmf/subsystem.c b/lib/nvmf/subsystem.c index 17e85ec2f..88c592ffd 100644 --- a/lib/nvmf/subsystem.c +++ b/lib/nvmf/subsystem.c @@ -463,6 +463,13 @@ spdk_nvmf_get_discovery_log_page(void *buffer, uint64_t offset, uint32_t length) assert(copy_len + zero_len == length); } +static void spdk_nvmf_ctrlr_hot_remove(void *remove_ctx) +{ + struct spdk_nvmf_subsystem *subsystem = (struct spdk_nvmf_subsystem *)remove_ctx; + + subsystem->is_removed = true; +} + int spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bdev *bdev) { @@ -477,7 +484,7 @@ spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bd return -1; } - if (!spdk_bdev_claim(bdev, NULL, NULL)) { + if (!spdk_bdev_claim(bdev, spdk_nvmf_ctrlr_hot_remove, subsystem)) { SPDK_ERRLOG("Subsystem %s: bdev %s is already claimed\n", subsystem->subnqn, bdev->name); return -1; diff --git a/test/lib/nvmf/session/session_ut.c b/test/lib/nvmf/session/session_ut.c index 89310fdcc..875c6f5b2 100644 --- a/test/lib/nvmf/session/session_ut.c +++ b/test/lib/nvmf/session/session_ut.c @@ -67,6 +67,12 @@ test_foobar(void) { } +int +spdk_nvmf_request_complete(struct spdk_nvmf_request *req) +{ + return -1; +} + int main(int argc, char **argv) { CU_pSuite suite = NULL;