Register virtio_driver.shutdown for reboot and poweroff via virtio_dev_shutdown: freeze to reclaim in-flight requests, then break virtqueues and mark the disk dead.
Also fail queue_rq early when vqs were removed during frozen reset_prepare and vqs is NULL. Assisted-by: DeepSeek:deepseek-v3 Signed-off-by: Xixin Liu <[email protected]> --- drivers/block/virtio_blk.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 32bf3ba07a9d..bbbbbbbbbbbb 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -435,6 +435,12 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx, blk_status_t status; int err; + /* VQs may be gone after frozen reset_prepare; avoid NULL deref. */ + if (unlikely(!vblk->vqs || !vblk->vdev)) { + blk_mq_start_request(req); + return BLK_STS_IOERR; + } + status = virtblk_prep_rq(hctx, vblk, req, vbr); if (unlikely(status)) return status; @@ -1561,6 +1561,34 @@ static int virtblk_probe(struct virtio_device *vdev) return err; } +/* System shutdown: reclaim in-flight requests, then break and mark dead. */ +static void virtblk_shutdown(struct virtio_device *vdev) +{ + struct virtio_blk *vblk = vdev->priv; + struct request_queue *q; + unsigned int memflags; + + if (!vblk || !vblk->disk) + return; + + q = vblk->disk->queue; + /* + * Reclaim request memory before break: freeze waits until + * q_usage_counter is zero (PDU + chained sg freed in done path). + * After virtio_break_device(), completions no longer run. + */ + memflags = blk_mq_freeze_queue(q); + blk_mq_quiesce_queue_nowait(q); + + virtio_break_device(vdev); + flush_work(&vblk->config_work); + + blk_mark_disk_dead(vblk->disk); + + blk_mq_unquiesce_queue(q); + blk_mq_unfreeze_queue(q, memflags); +} + static void virtblk_remove(struct virtio_device *vdev) { struct virtio_blk *vblk = vdev->priv; @@ -1684,6 +1712,7 @@ static struct virtio_driver virtio_blk = { .probe = virtblk_probe, .remove = virtblk_remove, .config_changed = virtblk_config_changed, + .shutdown = virtblk_shutdown, #ifdef CONFIG_PM_SLEEP .freeze = virtblk_freeze, .restore = virtblk_restore, -- 2.43.0

