Skip to content

Commit 9ebbfe4

Browse files
lostandy26Christoph Hellwig
authored andcommitted
nvme-tcp: avoid request double completion for concurrent nvme_tcp_timeout
Each name space has a request queue, if complete request long time, multi request queues may have time out requests at the same time, nvme_tcp_timeout will execute concurrently. Multi requests in different request queues may be queued in the same tcp queue, multi nvme_tcp_timeout may call nvme_tcp_stop_queue at the same time. The first nvme_tcp_stop_queue will clear NVME_TCP_Q_LIVE and continue stopping the tcp queue(cancel io_work), but the others check NVME_TCP_Q_LIVE is already cleared, and then directly complete the requests, complete request before the io work is completely canceled may lead to a use-after-free condition. Add a multex lock to serialize nvme_tcp_stop_queue. Signed-off-by: Chao Leng <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 7674073 commit 9ebbfe4

File tree

1 file changed

+10
-4
lines changed

1 file changed

+10
-4
lines changed

drivers/nvme/host/tcp.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ struct nvme_tcp_queue {
7676
struct work_struct io_work;
7777
int io_cpu;
7878

79+
struct mutex queue_lock;
7980
struct mutex send_mutex;
8081
struct llist_head req_list;
8182
struct list_head send_list;
@@ -1219,6 +1220,7 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid)
12191220

12201221
sock_release(queue->sock);
12211222
kfree(queue->pdu);
1223+
mutex_destroy(&queue->queue_lock);
12221224
}
12231225

12241226
static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
@@ -1380,6 +1382,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
13801382
struct nvme_tcp_queue *queue = &ctrl->queues[qid];
13811383
int ret, rcv_pdu_size;
13821384

1385+
mutex_init(&queue->queue_lock);
13831386
queue->ctrl = ctrl;
13841387
init_llist_head(&queue->req_list);
13851388
INIT_LIST_HEAD(&queue->send_list);
@@ -1398,7 +1401,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
13981401
if (ret) {
13991402
dev_err(nctrl->device,
14001403
"failed to create socket: %d\n", ret);
1401-
return ret;
1404+
goto err_destroy_mutex;
14021405
}
14031406

14041407
/* Single syn retry */
@@ -1507,6 +1510,8 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
15071510
err_sock:
15081511
sock_release(queue->sock);
15091512
queue->sock = NULL;
1513+
err_destroy_mutex:
1514+
mutex_destroy(&queue->queue_lock);
15101515
return ret;
15111516
}
15121517

@@ -1534,9 +1539,10 @@ static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
15341539
struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
15351540
struct nvme_tcp_queue *queue = &ctrl->queues[qid];
15361541

1537-
if (!test_and_clear_bit(NVME_TCP_Q_LIVE, &queue->flags))
1538-
return;
1539-
__nvme_tcp_stop_queue(queue);
1542+
mutex_lock(&queue->queue_lock);
1543+
if (test_and_clear_bit(NVME_TCP_Q_LIVE, &queue->flags))
1544+
__nvme_tcp_stop_queue(queue);
1545+
mutex_unlock(&queue->queue_lock);
15401546
}
15411547

15421548
static int nvme_tcp_start_queue(struct nvme_ctrl *nctrl, int idx)

0 commit comments

Comments
 (0)