From f1dac2a2e75260d1466d9f03ccf0944d6d0449a4 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 28 Oct 2026 10:42:38 -0600 Subject: [PATCH] nvmet-rdma: fix double puts after a failed RDMA WRITE For a read with T10-PI the RDMA WRITE is posted alone and nvmet_rdma_write_data_done() posts the SEND once the metadata check result is known. By then the request has been completed and its references put: __nvmet_req_complete() put ns->ref and the pc_ref, and nvmet_req_complete() sq->ref, right after queuing the response. The error branch of nvmet_rdma_write_data_done() copies the one from nvmet_rdma_read_data_done() and calls nvmet_req_uninit(), which puts all three again. A WRITE fails whenever the connection ends with reads in flight, which is up to the host. Depending on timing the sq->ref count goes to zero early and the queue is freed under the remaining completions, or never reaches zero and nvmet_sq_destroy() sleeps forever, or percpu_ref_put() dereferences NULL after percpu_ref_exit(). ns->ref stays too low for good, so disabling the namespace hangs too. Reproduced with KASAN over rxe with a test patch forcing the PI path. Drop the nvmet_req_uninit(). The branch still releases the RDMA context and the response, which is all the request owns at that point. Fixes: b09160c3996c ("nvmet-rdma: add metadata/T10-PI support") Cc: Christoph Hellwig Cc: Sagi Grimberg Cc: Chaitanya Kulkarni Signed-off-by: Chris Mason Signed-off-by: Jens Axboe Signed-off-by: Keith Busch --- drivers/nvme/target/rdma.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index 279d0d097b55..b9e39d1657d2 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -803,7 +803,10 @@ static void nvmet_rdma_write_data_done(struct ib_cq *cq, struct ib_wc *wc) if (unlikely(wc->status != IB_WC_SUCCESS)) { nvmet_rdma_rw_ctx_destroy(rsp); - nvmet_req_uninit(&rsp->req); + /* + * Unlike in nvmet_rdma_read_data_done(), the request has been + * completed and its references are put: no nvmet_req_uninit(). + */ nvmet_rdma_release_rsp(rsp); if (wc->status != IB_WC_WR_FLUSH_ERR) { pr_info("RDMA WRITE for CQE failed with status %s (%d).\n",