[PATCH] nvme: bump genctr when cancelling a request

Mateusz Nowicki mateusz.nowicki at posteo.net
Sun Sep 13 05:41:01 PDT 2026


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 at 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);



More information about the Linux-nvme mailing list