| From 3479ea8bcda944536a93703d65c6b24ccd80dec4 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 29 Jan 2024 16:52:50 +0800 |
| Subject: virtio-blk: Ensure no requests in virtqueues before deleting vqs. |
| |
| From: Yi Sun <yi.sun@unisoc.com> |
| |
| [ Upstream commit 4ce6e2db00de8103a0687fb0f65fd17124a51aaa ] |
| |
| Ensure no remaining requests in virtqueues before resetting vdev and |
| deleting virtqueues. Otherwise these requests will never be completed. |
| It may cause the system to become unresponsive. |
| |
| Function blk_mq_quiesce_queue() can ensure that requests have become |
| in_flight status, but it cannot guarantee that requests have been |
| processed by the device. Virtqueues should never be deleted before |
| all requests become complete status. |
| |
| Function blk_mq_freeze_queue() ensure that all requests in virtqueues |
| become complete status. And no requests can enter in virtqueues. |
| |
| Signed-off-by: Yi Sun <yi.sun@unisoc.com> |
| Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
| Link: https://lore.kernel.org/r/20240129085250.1550594-1-yi.sun@unisoc.com |
| Signed-off-by: Jens Axboe <axboe@kernel.dk> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/block/virtio_blk.c | 7 ++++--- |
| 1 file changed, 4 insertions(+), 3 deletions(-) |
| |
| diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c |
| index 9b54eec9b17eb..7eae3f3732336 100644 |
| --- a/drivers/block/virtio_blk.c |
| +++ b/drivers/block/virtio_blk.c |
| @@ -952,14 +952,15 @@ static int virtblk_freeze(struct virtio_device *vdev) |
| { |
| struct virtio_blk *vblk = vdev->priv; |
| |
| + /* Ensure no requests in virtqueues before deleting vqs. */ |
| + blk_mq_freeze_queue(vblk->disk->queue); |
| + |
| /* Ensure we don't receive any more interrupts */ |
| vdev->config->reset(vdev); |
| |
| /* Make sure no work handler is accessing the device. */ |
| flush_work(&vblk->config_work); |
| |
| - blk_mq_quiesce_queue(vblk->disk->queue); |
| - |
| vdev->config->del_vqs(vdev); |
| kfree(vblk->vqs); |
| |
| @@ -977,7 +978,7 @@ static int virtblk_restore(struct virtio_device *vdev) |
| |
| virtio_device_ready(vdev); |
| |
| - blk_mq_unquiesce_queue(vblk->disk->queue); |
| + blk_mq_unfreeze_queue(vblk->disk->queue); |
| return 0; |
| } |
| #endif |
| -- |
| 2.43.0 |
| |