[PATCH 10/19] nvmet: move preempt and abort work off nvmet-wq
Keith Busch
kbusch at meta.com
Thu Oct 29 08:52:43 PDT 2026
From: Chris Mason <mason at kernel.org>
nvmet_pr_do_abort() runs on nvmet-wq, holds pr_sem while it waits for
the preempted controllers' I/O, and releases it at the end. nvmet-wq
also runs nvmet_tcp_release_queue_work(), which cancel_work_sync()s the
io_work of a closed connection, and that io_work may be sleeping on
pr_sem in a reservation command. So a host that keeps a write in flight
on a preempted controller, sends a second preempt and abort, and then
closes enough connections with a reservation command in flight fills
nvmet-wq with release works that wait for pr_sem. When the first abort
finishes, the second one is queued on a full workqueue behind them and
never starts, pr_sem is never released, and the accept work doesn't run
either, so nobody can connect.
Queue the abort work on its own workqueue so it starts regardless. The
release works can still fill nvmet-wq while pr_sem is held, and a
file-backed namespace's flush, DSM and write zeroes need nvmet-wq
themselves, so this is a mitigation.
Fixes: 5a47c2080a73 ("nvmet: support reservation feature")
Cc: Christoph Hellwig <hch at lst.de>
Cc: Sagi Grimberg <sagi at grimberg.me>
Cc: Chaitanya Kulkarni <kch at nvidia.com>
Signed-off-by: Chris Mason <mason at kernel.org>
Signed-off-by: Jens Axboe <axboe at kernel.dk>
Signed-off-by: Keith Busch <kbusch at kernel.org>
---
drivers/nvme/target/core.c | 11 ++++++++++-
drivers/nvme/target/nvmet.h | 1 +
drivers/nvme/target/pr.c | 6 +++++-
3 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 27b27c83ff831..1ed250cd4b56e 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -29,6 +29,7 @@ struct workqueue_struct *nvmet_wq;
EXPORT_SYMBOL_GPL(nvmet_wq);
struct workqueue_struct *nvmet_aen_wq;
EXPORT_SYMBOL_GPL(nvmet_aen_wq);
+struct workqueue_struct *nvmet_pr_wq;
/*
* This read/write semaphore is used to synchronize access to configuration
@@ -2018,9 +2019,14 @@ static int __init nvmet_init(void)
if (!nvmet_aen_wq)
goto out_free_nvmet_work_queue;
+ nvmet_pr_wq = alloc_workqueue("nvmet-pr-wq",
+ WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
+ if (!nvmet_pr_wq)
+ goto out_free_nvmet_aen_work_queue;
+
error = nvmet_init_debugfs();
if (error)
- goto out_free_nvmet_aen_work_queue;
+ goto out_free_nvmet_pr_work_queue;
error = nvmet_init_discovery();
if (error)
@@ -2036,6 +2042,8 @@ static int __init nvmet_init(void)
nvmet_exit_discovery();
out_exit_debugfs:
nvmet_exit_debugfs();
+out_free_nvmet_pr_work_queue:
+ destroy_workqueue(nvmet_pr_wq);
out_free_nvmet_aen_work_queue:
destroy_workqueue(nvmet_aen_wq);
out_free_nvmet_work_queue:
@@ -2055,6 +2063,7 @@ static void __exit nvmet_exit(void)
nvmet_exit_discovery();
nvmet_exit_debugfs();
ida_destroy(&cntlid_ida);
+ destroy_workqueue(nvmet_pr_wq);
destroy_workqueue(nvmet_aen_wq);
destroy_workqueue(nvmet_wq);
destroy_workqueue(buffered_io_wq);
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index a89b384c4bbc9..7b429cc16d491 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -528,6 +528,7 @@ extern struct workqueue_struct *buffered_io_wq;
extern struct workqueue_struct *zbd_wq;
extern struct workqueue_struct *nvmet_wq;
extern struct workqueue_struct *nvmet_aen_wq;
+extern struct workqueue_struct *nvmet_pr_wq;
static inline void nvmet_set_result(struct nvmet_req *req, u32 result)
{
diff --git a/drivers/nvme/target/pr.c b/drivers/nvme/target/pr.c
index 1c0d6cac1a6b3..1a03f74c2e14f 100644
--- a/drivers/nvme/target/pr.c
+++ b/drivers/nvme/target/pr.c
@@ -756,7 +756,11 @@ static void nvmet_execute_pr_acquire(struct nvmet_req *req)
if (!status && acquire_act == NVME_PR_ACQUIRE_ACT_PREEMPT_AND_ABORT) {
kfree(d);
INIT_WORK(&req->r.abort_work, nvmet_pr_do_abort);
- queue_work(nvmet_wq, &req->r.abort_work);
+ /*
+ * Not nvmet_wq: works on it can wait for pr_sem, which this
+ * work releases.
+ */
+ queue_work(nvmet_pr_wq, &req->r.abort_work);
return;
}
--
2.52.0
More information about the Linux-nvme
mailing list