diff options
author | Maurizio Lombardi <mlombard@redhat.com> | 2021-11-16 16:49:18 +0100 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2021-11-23 17:19:25 +0100 |
commit | a208fc56721775987c1b86e20d86d7e0d017c0b2 (patch) | |
tree | f1298f7551961eab1f927db8ce2243a18cdafbb7 /drivers/nvme | |
parent | efcf5932230b9472cfdbe01c858726f29ac5ec7d (diff) | |
download | linux-a208fc56721775987c1b86e20d86d7e0d017c0b2.tar.bz2 |
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 <mlombard@redhat.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: John Meneghini <jmeneghi@redhat.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'drivers/nvme')
-rw-r--r-- | drivers/nvme/target/tcp.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 84c387e4bf43..18f36256095f 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); |