mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
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: 8f000cac6e ("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>
This commit is contained in:
parent
2b646788ee
commit
14e4e09443
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user