From: Mohamed Khalfella <mkhalfella@purestorage.com>
To: Keith Busch <kbusch@kernel.org>, Jens Axboe <axboe@kernel.dk>,
Christoph Hellwig <hch@lst.de>, Sagi Grimberg <sagi@grimberg.me>
Cc: Justin Tee <justin.tee@broadcom.com>,
Naresh Gottumukkala <nareshgottumukkala83@gmail.com>,
Paul Ely <paul.ely@broadcom.com>,
Hannes Reinecke <hare@kernel.org>,
Chaitanya Kulkarni <kch@nvidia.com>,
James Smart <jsmart833426@gmail.com>,
Randy Jennings <randyj@purestorage.com>,
Mohamed Khalfella <mkhalfella@purestorage.com>,
linux-nvme@lists.infradead.org, linux-kernel@vger.kernel.org
Subject: [PATCH 18/18] nvme: let controller deletion wait out a fencing window
Date: Fri, 18 Sep 2026 11:14:18 -0700 [thread overview]
Message-ID: <20260918181614.3947933-19-mkhalfella@purestorage.com> (raw)
In-Reply-To: <20260918181614.3947933-1-mkhalfella@purestorage.com>
DELETING is not reachable from FENCING or FENCED, so during a fencing
window nvme_delete_ctrl() fails with -EBUSY. Its callers assume
deleting a live controller cannot fail: a sysfs disconnect is silently
dropped after the delete_controller node is already gone, rdma device
removal returns with the controller still holding resources on the
outgoing device, and module unload leaks live controllers.
Fencing is time-bounded and always ends in a state that allows
deletion. Add nvme_delete_ctrl_wait(), which waits on ctrl->state_wq
for the fencing window to end and retries, and use it in the tcp/rdma
module exit paths and rdma device removal. Make nvme_delete_ctrl_sync()
wait the same way so a sysfs disconnect during fencing is delayed
instead of dropped.
nvme-fc's remoteport unregister with dev_loss_tmo == 0 keeps the
non-waiting call since it runs under rport->lock; it does not need to
wait, as dev_loss_end has already expired and the reconnect path
deletes the controller once fencing completes.
Signed-off-by: Mohamed Khalfella <mkhalfella@purestorage.com>
---
drivers/nvme/host/core.c | 41 ++++++++++++++++++++++++++++++++++++++--
drivers/nvme/host/nvme.h | 1 +
drivers/nvme/host/rdma.c | 4 ++--
drivers/nvme/host/tcp.c | 2 +-
4 files changed, 43 insertions(+), 5 deletions(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index dc44e3af5f14..ca7f083702f5 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -271,6 +271,38 @@ int nvme_delete_ctrl(struct nvme_ctrl *ctrl)
}
EXPORT_SYMBOL_GPL(nvme_delete_ctrl);
+static bool nvme_ctrl_fencing(struct nvme_ctrl *ctrl)
+{
+ enum nvme_ctrl_state state = nvme_ctrl_state(ctrl);
+
+ return state == NVME_CTRL_FENCING || state == NVME_CTRL_FENCED;
+}
+
+static void nvme_wait_fencing_done(struct nvme_ctrl *ctrl)
+{
+ wait_event(ctrl->state_wq, !nvme_ctrl_fencing(ctrl));
+}
+
+/*
+ * Like nvme_delete_ctrl(), but waits for a fencing window to end
+ * instead of failing with -EBUSY. May sleep; callers that cannot
+ * sleep must use nvme_delete_ctrl() and handle the failure.
+ */
+int nvme_delete_ctrl_wait(struct nvme_ctrl *ctrl)
+{
+ int ret;
+
+ might_sleep();
+
+ for (;;) {
+ ret = nvme_delete_ctrl(ctrl);
+ if (!ret || !nvme_ctrl_fencing(ctrl))
+ return ret;
+ nvme_wait_fencing_done(ctrl);
+ }
+}
+EXPORT_SYMBOL_GPL(nvme_delete_ctrl_wait);
+
void nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl)
{
/*
@@ -278,8 +310,13 @@ void nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl)
* since ->delete_ctrl can free the controller.
*/
nvme_get_ctrl(ctrl);
- if (nvme_change_ctrl_state(ctrl, NVME_CTRL_DELETING))
- nvme_do_delete_ctrl(ctrl);
+ while (!nvme_change_ctrl_state(ctrl, NVME_CTRL_DELETING)) {
+ if (!nvme_ctrl_fencing(ctrl))
+ goto out_put;
+ nvme_wait_fencing_done(ctrl);
+ }
+ nvme_do_delete_ctrl(ctrl);
+out_put:
nvme_put_ctrl(ctrl);
}
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index bcecaaf06f7e..bf8c2bf91ad3 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -1026,6 +1026,7 @@ void nvme_stop_keep_alive(struct nvme_ctrl *ctrl);
int nvme_reset_ctrl(struct nvme_ctrl *ctrl);
int nvme_reset_ctrl_sync(struct nvme_ctrl *ctrl);
int nvme_delete_ctrl(struct nvme_ctrl *ctrl);
+int nvme_delete_ctrl_wait(struct nvme_ctrl *ctrl);
void nvme_queue_scan(struct nvme_ctrl *ctrl);
int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp, u8 csi,
void *log, size_t size, u64 offset);
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index 8ff5aa312377..ce37e3eafeae 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -2483,7 +2483,7 @@ static void nvme_rdma_remove_one(struct ib_device *ib_device, void *client_data)
list_for_each_entry(ctrl, &nvme_rdma_ctrl_list, list) {
if (ctrl->device->dev != ib_device)
continue;
- nvme_delete_ctrl(&ctrl->ctrl);
+ nvme_delete_ctrl_wait(&ctrl->ctrl);
}
mutex_unlock(&nvme_rdma_ctrl_mutex);
@@ -2523,7 +2523,7 @@ static void __exit nvme_rdma_cleanup_module(void)
mutex_lock(&nvme_rdma_ctrl_mutex);
list_for_each_entry(ctrl, &nvme_rdma_ctrl_list, list)
- nvme_delete_ctrl(&ctrl->ctrl);
+ nvme_delete_ctrl_wait(&ctrl->ctrl);
mutex_unlock(&nvme_rdma_ctrl_mutex);
flush_workqueue(nvme_delete_wq);
}
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 7b1d9e2cb00d..9331a3e0bd9a 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -3208,7 +3208,7 @@ static void __exit nvme_tcp_cleanup_module(void)
mutex_lock(&nvme_tcp_ctrl_mutex);
list_for_each_entry(ctrl, &nvme_tcp_ctrl_list, list)
- nvme_delete_ctrl(&ctrl->ctrl);
+ nvme_delete_ctrl_wait(&ctrl->ctrl);
mutex_unlock(&nvme_tcp_ctrl_mutex);
flush_workqueue(nvme_delete_wq);
--
2.55.0
prev parent reply other threads:[~2026-09-18 18:17 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-18 18:14 [PATCH 00/18] TP8028 Rapid Path Failure Recovery Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 01/18] nvmet: Rapid Path Failure Recovery set controller identify fields Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 02/18] nvmet/debugfs: Export controller CIU and CIRN via debugfs Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 03/18] nvmet: Implement CCR nvme command Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 04/18] nvmet: Implement CCR logpage Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 05/18] nvmet: Send an AEN on CCR completion Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 06/18] nvme: Rapid Path Failure Recovery read controller identify fields Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 07/18] nvme: Introduce FENCING and FENCED controller states Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 08/18] nvme: Implement cross-controller reset recovery Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 09/18] nvme: Implement cross-controller reset completion Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 10/18] nvme-tcp: Use CCR to recover controller that hits an error Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 11/18] nvme-rdma: " Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 12/18] nvme-fc: start error recovery instead of aborting timed out IOs Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 13/18] nvme-fc: perform error recovery directly from ioerr_work Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 14/18] nvme-fc: Use CCR to recover controller that hits an error Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 15/18] nvme-fc: Hold inflight requests while in FENCING state Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 16/18] nvmet: Add support for CQT to nvme target Mohamed Khalfella
2026-09-18 18:14 ` [PATCH 17/18] nvme: Add support for CQT to nvme host Mohamed Khalfella
2026-09-18 18:14 ` Mohamed Khalfella [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260918181614.3947933-19-mkhalfella@purestorage.com \
--to=mkhalfella@purestorage.com \
--cc=axboe@kernel.dk \
--cc=hare@kernel.org \
--cc=hch@lst.de \
--cc=jsmart833426@gmail.com \
--cc=justin.tee@broadcom.com \
--cc=kbusch@kernel.org \
--cc=kch@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nvme@lists.infradead.org \
--cc=nareshgottumukkala83@gmail.com \
--cc=paul.ely@broadcom.com \
--cc=randyj@purestorage.com \
--cc=sagi@grimberg.me \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®