All of lore.kernel.org
 help / color / mirror / Atom feed
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 v6 18/18] nvme: let controller deletion wait out a fencing window
Date: Sun, 20 Sep 2026 11:28:16 -0700	[thread overview]
Message-ID: <20260920182936.2317916-19-mkhalfella@purestorage.com> (raw)
In-Reply-To: <20260920182936.2317916-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



      parent reply	other threads:[~2026-09-20 18:30 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-20 18:27 [PATCH v6 00/18] TP8028 Rapid Path Failure Recovery Mohamed Khalfella
2026-09-20 18:27 ` [PATCH v6 01/18] nvmet: Rapid Path Failure Recovery set controller identify fields Mohamed Khalfella
2026-10-15 12:58   ` Daniel Wagner
2026-10-19 18:06     ` Mohamed Khalfella
2026-09-20 18:28 ` [PATCH v6 02/18] nvmet/debugfs: Export controller CIU and CIRN via debugfs Mohamed Khalfella
2026-10-19 12:01   ` Daniel Wagner
2026-10-19 19:01     ` Mohamed Khalfella
2026-10-20 12:59       ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 03/18] nvmet: Implement CCR nvme command Mohamed Khalfella
2026-10-19 16:00   ` Daniel Wagner
2026-10-19 20:21     ` Mohamed Khalfella
2026-09-20 18:28 ` [PATCH v6 04/18] nvmet: Implement CCR logpage Mohamed Khalfella
2026-10-19 16:18   ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 05/18] nvmet: Send an AEN on CCR completion Mohamed Khalfella
2026-10-19 16:31   ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 06/18] nvme: Rapid Path Failure Recovery read controller identify fields Mohamed Khalfella
2026-10-19 16:56   ` Daniel Wagner
2026-10-19 21:18     ` Mohamed Khalfella
2026-09-20 18:28 ` [PATCH v6 07/18] nvme: Introduce FENCING and FENCED controller states Mohamed Khalfella
2026-10-19 17:01   ` Daniel Wagner
2026-10-19 17:18     ` Daniel Wagner
2026-10-19 21:40       ` Mohamed Khalfella
2026-10-20 13:15         ` Daniel Wagner
2026-10-19 21:26     ` Mohamed Khalfella
2026-10-20 13:10       ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 08/18] nvme: Implement cross-controller reset recovery Mohamed Khalfella
2026-10-20  8:55   ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 09/18] nvme: Implement cross-controller reset completion Mohamed Khalfella
2026-10-20  9:18   ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 10/18] nvme-tcp: Use CCR to recover controller that hits an error Mohamed Khalfella
2026-10-20  9:36   ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 11/18] nvme-rdma: " Mohamed Khalfella
2026-10-20  9:36   ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 12/18] nvme-fc: start error recovery instead of aborting timed out IOs Mohamed Khalfella
2026-10-20  9:55   ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 13/18] nvme-fc: perform error recovery directly from ioerr_work Mohamed Khalfella
2026-10-20 10:20   ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 14/18] nvme-fc: Use CCR to recover controller that hits an error Mohamed Khalfella
2026-10-20 11:56   ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 15/18] nvme-fc: Hold inflight requests while in FENCING state Mohamed Khalfella
2026-10-20 12:21   ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 16/18] nvmet: Add support for CQT to nvme target Mohamed Khalfella
2026-10-20 12:40   ` Daniel Wagner
2026-09-20 18:28 ` [PATCH v6 17/18] nvme: Add support for CQT to nvme host Mohamed Khalfella
2026-10-20 12:46   ` Daniel Wagner
2026-09-20 18:28 ` 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=20260920182936.2317916-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.