[PATCH v2 6/6] nvmet: roll back queue bindings on connection failure

From: shao.mingyin

Date: Fri Nov 13 2026 - 13:16:24 EST


From: Shao Mingyin <shao.mingyin@xxxxxxxxxx>

nvmet_install_queue() publishes the SQ controller pointer before
claiming the CQ. If the CQ is already connected, it leaves the SQ
pointer and the controller reference taken for it behind on failure.

An install_queue() callback failure also leaves the CQ bound after
clearing the SQ pointer. The reference taken in nvmet_install_queue()
is in addition to the one the caller already holds: the caller's put
releases the reference acquired before the call, while this one belongs
to the CQ binding. It is not released on this path, so the controller
stays alive and a Connect retry on the same queue keeps finding the
stale binding.

Clear the tentative SQ binding and release the extra reference on a CQ
conflict. On a transport installation failure, destroy the CQ binding
as well, so its controller table entry and reference are released.

Link: https://lore.kernel.org/all/20261106015842.3534898-6-kanie@xxxxxxxxxxxxxxxxx/
Fixes: bb78836b3a7c ("nvmet: fabrics: add CQ init and destroy")
Cc: stable@xxxxxxxxxxxxxxx
Reviewed-by: Christoph Hellwig <hch@xxxxxx>
Signed-off-by: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
---
Changes in v2:
- Code and commit message unchanged; add Christoph Hellwig's Reviewed-by tag.
Previous version: https://lore.kernel.org/all/20261110230316687z-VG9wgpFwmzFNKVnMGKY@xxxxxxxxxx/

drivers/nvme/target/fabrics-cmd.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c
index fc626c2fd2c924342b550764f686010103e5ec84..6f0fc695e6499247340d3f17929608e4f03c00f2 100644
--- a/drivers/nvme/target/fabrics-cmd.c
+++ b/drivers/nvme/target/fabrics-cmd.c
@@ -216,6 +216,8 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
if (old) {
pr_warn("queue already connected!\n");
req->error_loc = offsetof(struct nvmf_connect_command, opcode);
+ req->sq->ctrl = NULL;
+ nvmet_ctrl_put(ctrl);
return NVME_SC_CONNECT_CTRL_BUSY | NVME_STATUS_DNR;
}

@@ -242,6 +244,7 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req)

err:
req->sq->ctrl = NULL;
+ nvmet_cq_destroy(req->cq);
return ret;
}

--
2.27.0