Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72f67636 authored by Ruozhu Li's avatar Ruozhu Li Committed by Greg Kroah-Hartman
Browse files

nvmet-rdma: recheck queue state is LIVE in state lock in recv done



[ Upstream commit 3988ac1c67e6e84d2feb987d7b36d5791174b3da ]

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: default avatarRuozhu Li <david.li@jaguarmicro.com>
Reviewed-by: default avatarSagi Grimberg <sagi@grimberg.me>
Signed-off-by: default avatarKeith Busch <kbusch@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 3dbbc37d
Loading
Loading
Loading
Loading
+23 −10
Original line number Diff line number Diff line
@@ -777,6 +777,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 =
@@ -818,17 +839,9 @@ static void nvmet_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc)
	rsp->req.port = queue->port;
	rsp->n_rdma = 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);
}