nvme-tcp: add clean action for failed reconnection
authorChao Leng <lengchao@huawei.com>
Thu, 21 Jan 2021 03:32:38 +0000 (11:32 +0800)
committerChristoph Hellwig <hch@lst.de>
Tue, 2 Feb 2021 09:26:12 +0000 (10:26 +0100)
If reconnect failed after start io queues, the queues will be unquiesced
and new requests continue to be delivered. Reconnection error handling
process directly free queues without cancel suspend requests. The
suppend request will time out, and then crash due to use the queue
after free.

Add sync queues and cancel suppend requests for reconnection error
handling.

Signed-off-by: Chao Leng <lengchao@huawei.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/nvme/host/tcp.c

index 4c13c7110dbe0a8573653d880e18ef7f07504071..8c256adb8c415e21c211e688f56fa3683c170914 100644 (file)
@@ -1812,8 +1812,10 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new)
 
 out_wait_freeze_timed_out:
        nvme_stop_queues(ctrl);
+       nvme_sync_io_queues(ctrl);
        nvme_tcp_stop_io_queues(ctrl);
 out_cleanup_connect_q:
+       nvme_cancel_tagset(ctrl);
        if (new)
                blk_cleanup_queue(ctrl->connect_q);
 out_free_tag_set:
@@ -1875,12 +1877,16 @@ static int nvme_tcp_configure_admin_queue(struct nvme_ctrl *ctrl, bool new)
 
        error = nvme_init_identify(ctrl);
        if (error)
-               goto out_stop_queue;
+               goto out_quiesce_queue;
 
        return 0;
 
+out_quiesce_queue:
+       blk_mq_quiesce_queue(ctrl->admin_q);
+       blk_sync_queue(ctrl->admin_q);
 out_stop_queue:
        nvme_tcp_stop_queue(ctrl, 0);
+       nvme_cancel_admin_tagset(ctrl);
 out_cleanup_queue:
        if (new)
                blk_cleanup_queue(ctrl->admin_q);
@@ -2000,10 +2006,18 @@ static int nvme_tcp_setup_ctrl(struct nvme_ctrl *ctrl, bool new)
        return 0;
 
 destroy_io:
-       if (ctrl->queue_count > 1)
+       if (ctrl->queue_count > 1) {
+               nvme_stop_queues(ctrl);
+               nvme_sync_io_queues(ctrl);
+               nvme_tcp_stop_io_queues(ctrl);
+               nvme_cancel_tagset(ctrl);
                nvme_tcp_destroy_io_queues(ctrl, new);
+       }
 destroy_admin:
+       blk_mq_quiesce_queue(ctrl->admin_q);
+       blk_sync_queue(ctrl->admin_q);
        nvme_tcp_stop_queue(ctrl, 0);
+       nvme_cancel_admin_tagset(ctrl);
        nvme_tcp_destroy_admin_queue(ctrl, new);
        return ret;
 }