mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] nvme: bump genctr when cancelling a request
@ 2026-09-13 12:41 Mateusz Nowicki
  2026-09-14 14:39 ` Keith Busch
  0 siblings, 1 reply; 3+ messages in thread
From: Mateusz Nowicki @ 2026-09-13 12:41 UTC (permalink / raw)
  To: kbusch, axboe, hch, sagi; +Cc: linux-nvme, linux-kernel, Mateusz Nowicki

nvme_find_rq() rejects a completion whose genctr does not match the
request, so a command completed once cannot be completed again by a
stale CQE. nvme_try_complete_req() bumps genctr for that reason.
nvme_cancel_request() completes the command too, but leaves genctr
alone. A CQE the controller posts for the cancelled command later still
matches and gets applied.

The cancel path is taken when the host stopped waiting for the
controller: CSTS.CFS set (dead path in nvme_dev_disable(), no CC.EN=0,
no wait), or CSTS.RDY not cleared within CAP.TO. Nothing stops the
controller from posting completions after that, and the second
nvme_dev_disable() from nvme_reset_work() reaps them in
nvme_reap_pending_cqes().

The cancelled request sits on the requeue list after the RETRY
disposition. The late CQE ends and frees it from there, and the next
dispatch hits req->mq_hctx == NULL:

  BUG: kernel NULL pointer dereference, address: 0000000000000158
  RIP: nvme_prep_rq+0x1a6
  nvme_queue_rq
  blk_mq_dispatch_rq_list
  __blk_mq_sched_dispatch_requests
  blk_mq_run_work_fn

Bump genctr in nvme_cancel_request() like a real completion does.

Reproduced with vnvme (https://github.com/Mateusz-Nowicki-Embedded/vnvme),
a virtual NVMe endpoint that holds completions back under I/O, sets
CSTS.CFS, and releases them after the tagset was cancelled.

Signed-off-by: Mateusz Nowicki <mateusz.nowicki@posteo.net>
---
 drivers/nvme/host/core.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -532,6 +532,8 @@ bool nvme_cancel_request(struct request *req, void *data)
 	if (blk_mq_rq_state(req) != MQ_RQ_IN_FLIGHT)
 		return true;
 
+	if (!(nvme_req(req)->ctrl->quirks & NVME_QUIRK_SKIP_CID_GEN))
+		nvme_req(req)->genctr++;
 	nvme_req(req)->status = NVME_SC_HOST_ABORTED_CMD;
 	nvme_req(req)->flags |= NVME_REQ_CANCELLED;
 	blk_mq_complete_request(req);

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-14 18:49 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-13 12:41 [PATCH] nvme: bump genctr when cancelling a request Mateusz Nowicki
2026-09-14 14:39 ` Keith Busch
2026-09-14 18:49   ` Mateusz Nowicki

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®