Skip to content

Commit

Permalink
nvmet-rdma: recheck queue state is LIVE in state lock in recv done
Browse files Browse the repository at this point in the history
The queue state checking in nvmet_rdma_recv_done is not in queue state
lock.Queue state can transfer to LIVE in cm establish handler between
state checking and state lock here, cause a silent drop of nvme connect
cmd.
Recheck queue state whether in LIVE state in state lock to prevent this
issue.

Signed-off-by: Ruozhu Li <david.li@jaguarmicro.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Keith Busch <kbusch@kernel.org>
  • Loading branch information
Ruozhu Li authored and Keith Busch committed Feb 18, 2025
1 parent 4082326 commit 3988ac1
Showing 1 changed file with 23 additions and 10 deletions.
33 changes: 23 additions & 10 deletions drivers/nvme/target/rdma.c
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,27 @@ static void nvmet_rdma_handle_command(struct nvmet_rdma_queue *queue,
nvmet_req_complete(&cmd->req, status);
}

static bool nvmet_rdma_recv_not_live(struct nvmet_rdma_queue *queue,
struct nvmet_rdma_rsp *rsp)
{
unsigned long flags;
bool ret = true;

spin_lock_irqsave(&queue->state_lock, flags);
/*
* recheck queue state is not live to prevent a race condition
* with RDMA_CM_EVENT_ESTABLISHED handler.
*/
if (queue->state == NVMET_RDMA_Q_LIVE)
ret = false;
else if (queue->state == NVMET_RDMA_Q_CONNECTING)
list_add_tail(&rsp->wait_list, &queue->rsp_wait_list);
else
nvmet_rdma_put_rsp(rsp);
spin_unlock_irqrestore(&queue->state_lock, flags);
return ret;
}

static void nvmet_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc)
{
struct nvmet_rdma_cmd *cmd =
Expand Down Expand Up @@ -1038,17 +1059,9 @@ static void nvmet_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc)
rsp->n_rdma = 0;
rsp->invalidate_rkey = 0;

if (unlikely(queue->state != NVMET_RDMA_Q_LIVE)) {
unsigned long flags;

spin_lock_irqsave(&queue->state_lock, flags);
if (queue->state == NVMET_RDMA_Q_CONNECTING)
list_add_tail(&rsp->wait_list, &queue->rsp_wait_list);
else
nvmet_rdma_put_rsp(rsp);
spin_unlock_irqrestore(&queue->state_lock, flags);
if (unlikely(queue->state != NVMET_RDMA_Q_LIVE) &&
nvmet_rdma_recv_not_live(queue, rsp))
return;
}

nvmet_rdma_handle_command(queue, rsp);
}
Expand Down

0 comments on commit 3988ac1

Please sign in to comment.