From 14e4e09443ac2b5cd90c1e313ee3c0bdd4928e0d Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 28 Oct 2026 10:42:33 -0600 Subject: [PATCH] nvmet-rdma: disable interrupts under rsp_wr_wait_lock rsp_wr_wait_lock protects the list of commands waiting for room in the send queue, and it's taken with plain spin_lock(). But nvmet_rdma_queue_response() calls nvmet_rdma_release_rsp() directly if ib_post_send() fails, and that processes the wait list. The call chain starts in nvmet_req_complete(), which for a block device namespace runs from the bio end_io callback, which can be in hard interrupt context. An interrupt that completes a command on a CPU holding the lock for the same queue spins forever. Lockdep over siw with a null_blk namespace: inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} usage Use spin_lock_irqsave() for both takers. The processing loop still drops the lock, and restores the caller's interrupt state, around nvmet_rdma_execute_command(). Fixes: 8f000cac6e7a ("nvmet-rdma: add a NVMe over Fabrics RDMA target driver") 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 | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index ed11263ea93f..279d0d097b55 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -513,7 +513,9 @@ static int nvmet_rdma_post_recv(struct nvmet_rdma_device *ndev, static void nvmet_rdma_process_wr_wait_list(struct nvmet_rdma_queue *queue) { - spin_lock(&queue->rsp_wr_wait_lock); + unsigned long flags; + + spin_lock_irqsave(&queue->rsp_wr_wait_lock, flags); while (!list_empty(&queue->rsp_wr_wait_list)) { struct nvmet_rdma_rsp *rsp; bool ret; @@ -522,16 +524,16 @@ static void nvmet_rdma_process_wr_wait_list(struct nvmet_rdma_queue *queue) struct nvmet_rdma_rsp, wait_list); list_del(&rsp->wait_list); - spin_unlock(&queue->rsp_wr_wait_lock); + spin_unlock_irqrestore(&queue->rsp_wr_wait_lock, flags); ret = nvmet_rdma_execute_command(rsp); - spin_lock(&queue->rsp_wr_wait_lock); + spin_lock_irqsave(&queue->rsp_wr_wait_lock, flags); if (!ret) { list_add(&rsp->wait_list, &queue->rsp_wr_wait_list); break; } } - spin_unlock(&queue->rsp_wr_wait_lock); + spin_unlock_irqrestore(&queue->rsp_wr_wait_lock, flags); } static u16 nvmet_rdma_check_pi_status(struct ib_mr *sig_mr) @@ -977,6 +979,7 @@ static bool nvmet_rdma_execute_command(struct nvmet_rdma_rsp *rsp) static void nvmet_rdma_handle_command(struct nvmet_rdma_queue *queue, struct nvmet_rdma_rsp *cmd) { + unsigned long flags; u16 status; ib_dma_sync_single_for_cpu(queue->dev->device, @@ -994,9 +997,9 @@ static void nvmet_rdma_handle_command(struct nvmet_rdma_queue *queue, goto out_err; if (unlikely(!nvmet_rdma_execute_command(cmd))) { - spin_lock(&queue->rsp_wr_wait_lock); + spin_lock_irqsave(&queue->rsp_wr_wait_lock, flags); list_add_tail(&cmd->wait_list, &queue->rsp_wr_wait_list); - spin_unlock(&queue->rsp_wr_wait_lock); + spin_unlock_irqrestore(&queue->rsp_wr_wait_lock, flags); } return;