summaryrefslogtreecommitdiff
path: root/drivers/nvme/target
diff options
context:
space:
mode:
authorChris Mason <mason@kernel.org>2026-10-28 10:42:33 -0600
committerKeith Busch <kbusch@kernel.org>2026-10-28 11:41:43 -0700
commit14e4e09443ac2b5cd90c1e313ee3c0bdd4928e0d (patch)
tree4168fcc6f27aa59fc3d96bb1588ee3e7c99d31ef /drivers/nvme/target
parent2b646788ee24d895b8862514e12a95ce5d72d6cc (diff)
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 <hch@lst.de> Cc: Sagi Grimberg <sagi@grimberg.me> Cc: Chaitanya Kulkarni <kch@nvidia.com> Signed-off-by: Chris Mason <mason@kernel.org> Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Keith Busch <kbusch@kernel.org>
Diffstat (limited to 'drivers/nvme/target')
-rw-r--r--drivers/nvme/target/rdma.c15
1 files 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;