nvmet-rdma: recheck queue state is LIVE in state lock in recv done
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>
This commit is contained in:
parent
4082326807
commit
3988ac1c67
1 changed files with 23 additions and 10 deletions
|
@ -996,6 +996,27 @@ out_err:
|
||||||
nvmet_req_complete(&cmd->req, status);
|
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)
|
static void nvmet_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||||
{
|
{
|
||||||
struct nvmet_rdma_cmd *cmd =
|
struct nvmet_rdma_cmd *cmd =
|
||||||
|
@ -1038,17 +1059,9 @@ static void nvmet_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||||
rsp->n_rdma = 0;
|
rsp->n_rdma = 0;
|
||||||
rsp->invalidate_rkey = 0;
|
rsp->invalidate_rkey = 0;
|
||||||
|
|
||||||
if (unlikely(queue->state != NVMET_RDMA_Q_LIVE)) {
|
if (unlikely(queue->state != NVMET_RDMA_Q_LIVE) &&
|
||||||
unsigned long flags;
|
nvmet_rdma_recv_not_live(queue, rsp))
|
||||||
|
|
||||||
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);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
nvmet_rdma_handle_command(queue, rsp);
|
nvmet_rdma_handle_command(queue, rsp);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue