Skip to content

Commit d6f6621

Browse files
lostandy26Christoph Hellwig
authored andcommitted
nvme-tcp: avoid race between time out and tear down
Now use teardown_lock to serialize for time out and tear down. This may cause abnormal: first cancel all request in tear down, then time out may complete the request again, but the request may already be freed or restarted. To avoid race between time out and tear down, in tear down process, first we quiesce the queue, and then delete the timer and cancel the time out work for the queue. At the same time we need to delete teardown_lock. Signed-off-by: Chao Leng <lengchao@huawei.com> Reviewed-by: Sagi Grimberg <sagi@grimberg.me> Signed-off-by: Christoph Hellwig <hch@lst.de>
1 parent 3017013 commit d6f6621

1 file changed

Lines changed: 3 additions & 11 deletions

File tree

drivers/nvme/host/tcp.c

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ struct nvme_tcp_ctrl {
124124
struct sockaddr_storage src_addr;
125125
struct nvme_ctrl ctrl;
126126

127-
struct mutex teardown_lock;
128127
struct work_struct err_work;
129128
struct delayed_work connect_work;
130129
struct nvme_tcp_request async_req;
@@ -1886,8 +1885,8 @@ static int nvme_tcp_configure_admin_queue(struct nvme_ctrl *ctrl, bool new)
18861885
static void nvme_tcp_teardown_admin_queue(struct nvme_ctrl *ctrl,
18871886
bool remove)
18881887
{
1889-
mutex_lock(&to_tcp_ctrl(ctrl)->teardown_lock);
18901888
blk_mq_quiesce_queue(ctrl->admin_q);
1889+
blk_sync_queue(ctrl->admin_q);
18911890
nvme_tcp_stop_queue(ctrl, 0);
18921891
if (ctrl->admin_tagset) {
18931892
blk_mq_tagset_busy_iter(ctrl->admin_tagset,
@@ -1897,18 +1896,17 @@ static void nvme_tcp_teardown_admin_queue(struct nvme_ctrl *ctrl,
18971896
if (remove)
18981897
blk_mq_unquiesce_queue(ctrl->admin_q);
18991898
nvme_tcp_destroy_admin_queue(ctrl, remove);
1900-
mutex_unlock(&to_tcp_ctrl(ctrl)->teardown_lock);
19011899
}
19021900

19031901
static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl,
19041902
bool remove)
19051903
{
1906-
mutex_lock(&to_tcp_ctrl(ctrl)->teardown_lock);
19071904
if (ctrl->queue_count <= 1)
1908-
goto out;
1905+
return;
19091906
blk_mq_quiesce_queue(ctrl->admin_q);
19101907
nvme_start_freeze(ctrl);
19111908
nvme_stop_queues(ctrl);
1909+
nvme_sync_io_queues(ctrl);
19121910
nvme_tcp_stop_io_queues(ctrl);
19131911
if (ctrl->tagset) {
19141912
blk_mq_tagset_busy_iter(ctrl->tagset,
@@ -1918,8 +1916,6 @@ static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl,
19181916
if (remove)
19191917
nvme_start_queues(ctrl);
19201918
nvme_tcp_destroy_io_queues(ctrl, remove);
1921-
out:
1922-
mutex_unlock(&to_tcp_ctrl(ctrl)->teardown_lock);
19231919
}
19241920

19251921
static void nvme_tcp_reconnect_or_remove(struct nvme_ctrl *ctrl)
@@ -2171,14 +2167,11 @@ static void nvme_tcp_complete_timed_out(struct request *rq)
21712167
struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
21722168
struct nvme_ctrl *ctrl = &req->queue->ctrl->ctrl;
21732169

2174-
/* fence other contexts that may complete the command */
2175-
mutex_lock(&to_tcp_ctrl(ctrl)->teardown_lock);
21762170
nvme_tcp_stop_queue(ctrl, nvme_tcp_queue_id(req->queue));
21772171
if (!blk_mq_request_completed(rq)) {
21782172
nvme_req(rq)->status = NVME_SC_HOST_ABORTED_CMD;
21792173
blk_mq_complete_request(rq);
21802174
}
2181-
mutex_unlock(&to_tcp_ctrl(ctrl)->teardown_lock);
21822175
}
21832176

21842177
static enum blk_eh_timer_return
@@ -2455,7 +2448,6 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev,
24552448
nvme_tcp_reconnect_ctrl_work);
24562449
INIT_WORK(&ctrl->err_work, nvme_tcp_error_recovery_work);
24572450
INIT_WORK(&ctrl->ctrl.reset_work, nvme_reset_ctrl_work);
2458-
mutex_init(&ctrl->teardown_lock);
24592451

24602452
if (!(opts->mask & NVMF_OPT_TRSVCID)) {
24612453
opts->trsvcid =

0 commit comments

Comments
 (0)