From e626f321296a6d71a7bb518ef4a2b7c1d5969908 Mon Sep 17 00:00:00 2001 From: Susobhan Dey Date: Thu, 7 May 2026 09:20:39 +0000 Subject: [PATCH 1/3] Added vendor specific subsystem pause/resume if vendor sets flag during subsystem pause we keep allowing keep alive for 120 sec even though subsystem is not active There is no change in fabric command. Only we allow admin cmds for 120 sec Signed-off-by: Susobhan Dey --- include/spdk/nvmf.h | 18 +++++++++++++++ lib/nvmf/ctrlr.c | 10 +++++++++ lib/nvmf/nvmf_internal.h | 3 +++ lib/nvmf/subsystem.c | 48 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) diff --git a/include/spdk/nvmf.h b/include/spdk/nvmf.h index f531ec0b3b0..6ac86d55493 100644 --- a/include/spdk/nvmf.h +++ b/include/spdk/nvmf.h @@ -27,6 +27,8 @@ extern "C" { #define SPDK_TLS_PSK_MAX_LEN 200 +#define SPDK_NVMF_SUBSYSTEM_PAUSE_KEEP_ADMINQ 0x1 + struct spdk_nvmf_tgt; struct spdk_nvmf_subsystem; struct spdk_nvmf_ctrlr; @@ -543,6 +545,15 @@ int spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem, spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg); +/** + * Vendor specific wrapper of subsystem pause + * we need to keep allow some admin commands during subsystem pause + */ +int spdk_nvmf_subsystem_pause_ext(struct spdk_nvmf_subsystem *subsystem, + uint32_t nsid, + uint32_t flags, + spdk_nvmf_subsystem_state_change_done cb_fn, + void *cb_arg); /** * Transition an NVMe-oF subsystem from Paused to Active state. * @@ -559,6 +570,13 @@ int spdk_nvmf_subsystem_resume(struct spdk_nvmf_subsystem *subsystem, spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg); +/** + * Vendor specific wrapper of subsystem resume + * We need to clear vendor specific flags during resume + */ +int spdk_nvmf_subsystem_resume_ext(struct spdk_nvmf_subsystem *subsystem, + spdk_nvmf_subsystem_state_change_done cb_fn, + void *cb_arg); /** * Search the target for a subsystem with the given NQN. * diff --git a/lib/nvmf/ctrlr.c b/lib/nvmf/ctrlr.c index 6e8e327ee28..3df42c74d6f 100644 --- a/lib/nvmf/ctrlr.c +++ b/lib/nvmf/ctrlr.c @@ -4606,6 +4606,16 @@ nvmf_check_subsystem_active(struct spdk_nvmf_request *req) if (spdk_unlikely(req->cmd->nvmf_cmd.opcode == SPDK_NVME_OPC_FABRIC || nvmf_qpair_is_admin_queue(qpair))) { if (sgroup->state != SPDK_NVMF_SUBSYSTEM_ACTIVE) { + struct spdk_nvmf_subsystem *subsystem = qpair->ctrlr->subsys; + if (req->cmd->nvmf_cmd.opcode != SPDK_NVME_OPC_FABRIC && + (subsystem->pause_flags & SPDK_NVMF_SUBSYSTEM_PAUSE_KEEP_ADMINQ)) { + /* + * Vendor maintenance pause + * allow normal admin queue commands while data IO is paused + */ + sgroup->mgmt_io_outstanding++; + return true; + } /* The subsystem is not currently active. Queue this request. */ TAILQ_INSERT_TAIL(&sgroup->queued, req, link); return false; diff --git a/lib/nvmf/nvmf_internal.h b/lib/nvmf/nvmf_internal.h index 66f155b5196..aecf95592ae 100644 --- a/lib/nvmf/nvmf_internal.h +++ b/lib/nvmf/nvmf_internal.h @@ -320,6 +320,9 @@ struct spdk_nvmf_subsystem { /* Subsystem event callback and its argument. */ spdk_nvmf_subsystem_event_cb event_cb_fn; void *event_cb_arg; + /* Vendor specific flags for maintainance work */ + uint32_t pause_flags; + struct spdk_poller *pause_timer; }; static int diff --git a/lib/nvmf/subsystem.c b/lib/nvmf/subsystem.c index 6cf29112b58..b16d5bda6b5 100644 --- a/lib/nvmf/subsystem.c +++ b/lib/nvmf/subsystem.c @@ -382,6 +382,11 @@ _nvmf_subsystem_destroy(struct spdk_nvmf_subsystem *subsystem) return -EINPROGRESS; } + if (subsystem->pause_timer) { + spdk_poller_unregister(&subsystem->pause_timer); + subsystem->pause_timer = NULL; + } + ns = spdk_nvmf_subsystem_get_first_ns(subsystem); while (ns != NULL) { struct spdk_nvmf_ns *next_ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns); @@ -758,6 +763,36 @@ spdk_nvmf_subsystem_stop(struct spdk_nvmf_subsystem *subsystem, return nvmf_subsystem_state_change(subsystem, 0, SPDK_NVMF_SUBSYSTEM_INACTIVE, cb_fn, cb_arg); } +static +int nvmf_subsys_pause_timer_cb(void *arg) +{ + struct spdk_nvmf_subsystem *subsystem = arg; + subsystem->pause_flags = 0; + if (subsystem->pause_timer) { + spdk_poller_unregister(&subsystem->pause_timer); + subsystem->pause_timer = NULL; + } + return SPDK_POLLER_BUSY; +} + +int +spdk_nvmf_subsystem_pause_ext(struct spdk_nvmf_subsystem *subsystem, + uint32_t nsid, + uint32_t flags, + spdk_nvmf_subsystem_state_change_done cb_fn, + void *cb_arg) +{ + subsystem->pause_flags = flags; + if (subsystem->pause_timer == NULL) { + subsystem->pause_timer = spdk_poller_register( + nvmf_subsys_pause_timer_cb, + subsystem, + 120ULL * 1000000ULL + ); + } + return spdk_nvmf_subsystem_pause(subsystem, nsid, cb_fn, cb_arg); +} + int spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid, @@ -767,6 +802,19 @@ spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem, return nvmf_subsystem_state_change(subsystem, nsid, SPDK_NVMF_SUBSYSTEM_PAUSED, cb_fn, cb_arg); } +int +spdk_nvmf_subsystem_resume_ext(struct spdk_nvmf_subsystem *subsystem, + spdk_nvmf_subsystem_state_change_done cb_fn, + void *cb_arg) +{ + subsystem->pause_flags = 0; + if (subsystem->pause_timer) { + spdk_poller_unregister(&subsystem->pause_timer); + subsystem->pause_timer = NULL; + } + return spdk_nvmf_subsystem_resume(subsystem, cb_fn, cb_arg); +} + int spdk_nvmf_subsystem_resume(struct spdk_nvmf_subsystem *subsystem, spdk_nvmf_subsystem_state_change_done cb_fn, From 8925ea0a78368498a6333e78a2718e9b7b7b741d Mon Sep 17 00:00:00 2001 From: Susobhan Dey Date: Thu, 7 May 2026 20:07:10 +0000 Subject: [PATCH 2/3] Added rpc option to change the subsystem pause timeout scripts/rpc.py nvmf_subsystem_set_pause_timeout