in our lab, when target is processing queue's connection
(queue->state==NVMET_RDMA_Q_CONNECTING), and the host sends
a command which will be put into wait list to target,
Before the command was processed, the host sent a discconnect
command to target, then the target will process disconnect command,
it will schedule a kworker to free the pre allocatedrsps array, and
it will cause kernel panic, because some items of rsps are in wait list.

Signed-off-by: jackygam2001 <[email protected]>
---
 drivers/nvme/target/rdma.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index ae6620489457..c6c892a43f68 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -1335,6 +1335,35 @@ static void nvmet_rdma_destroy_queue_ib(struct 
nvmet_rdma_queue *queue)
                       queue->send_queue_size + 1);
 }
 
+static void nvmet_rdma_destroy_queue_wait_list(struct nvmet_rdma_queue *queue)
+{
+       unsigned long flags;
+       struct nvmet_rdma_rsp *rsp;
+
+       spin_lock_irqsave(&queue->state_lock, flags);
+       while (!list_empty(&queue->rsp_wait_list)) {
+               rsp = list_first_entry(&queue->rsp_wait_list,
+                               struct nvmet_rdma_rsp, wait_list);
+               list_del(&rsp->wait_list);
+               nvmet_rdma_put_rsp(rsp);
+       }
+       spin_unlock_irqrestore(&queue->state_lock, flags);
+}
+
+static void nvmet_rdma_destroy_queue_wr_wait_list(struct nvmet_rdma_queue 
*queue)
+{
+       struct nvmet_rdma_rsp *rsp;
+
+       spin_lock(&queue->rsp_wr_wait_lock);
+       while (!list_empty(&queue->rsp_wr_wait_list)) {
+               rsp = list_first_entry(&queue->rsp_wr_wait_list,
+                               struct nvmet_rdma_rsp, wait_list);
+               list_del(&rsp->wait_list);
+               nvmet_rdma_put_rsp(rsp);
+       }
+       spin_unlock(&queue->rsp_wr_wait_lock);
+}
+
 static void nvmet_rdma_free_queue(struct nvmet_rdma_queue *queue)
 {
        pr_debug("freeing queue %d\n", queue->idx);
@@ -1347,6 +1376,8 @@ static void nvmet_rdma_free_queue(struct nvmet_rdma_queue 
*queue)
                                queue->recv_queue_size,
                                !queue->host_qid);
        }
+       nvmet_rdma_destroy_queue_wr_wait_list(queue);
+       nvmet_rdma_destroy_queue_wait_list(queue);
        nvmet_rdma_free_rsps(queue);
        ida_simple_remove(&nvmet_rdma_queue_ida, queue->idx);
        kfree(queue);
-- 
2.17.1


Reply via email to