From: Maurizio Lombardi Date: Tue, 16 Nov 2021 15:49:18 +0000 (+0100) Subject: nvmet-tcp: fix a race condition between release_queue and io_work X-Git-Tag: baikal/aarch64/sdk6.1~5215^2~1^2~9 X-Git-Url: https://git.baikalelectronics.ru/sdk/?a=commitdiff_plain;h=ac28b31ffa989f8ee5b4d63d68397786f12f8b86;p=kernel.git nvmet-tcp: fix a race condition between release_queue and io_work If the initiator executes a reset controller operation while performing I/O, the target kernel will crash because of a race condition between release_queue and io_work; nvmet_tcp_uninit_data_in_cmds() may be executed while io_work is running, calling flush_work() was not sufficient to prevent this because io_work could requeue itself. Fix this bug by using cancel_work_sync() to prevent io_work from requeuing itself and set rcv_state to NVMET_TCP_RECV_ERR to make sure we don't receive any more data from the socket. Signed-off-by: Maurizio Lombardi Reviewed-by: Keith Busch Reviewed-by: Sagi Grimberg Reviewed-by: John Meneghini Signed-off-by: Christoph Hellwig --- diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 84c387e4bf431..18f36256095f6 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -1437,7 +1437,9 @@ static void nvmet_tcp_release_queue_work(struct work_struct *w) mutex_unlock(&nvmet_tcp_queue_mutex); nvmet_tcp_restore_socket_callbacks(queue); - flush_work(&queue->io_work); + cancel_work_sync(&queue->io_work); + /* stop accepting incoming data */ + queue->rcv_state = NVMET_TCP_RECV_ERR; nvmet_tcp_uninit_data_in_cmds(queue); nvmet_sq_destroy(&queue->nvme_sq);