[PATCH v6 6/6] vhost-user-blk: use GET_VRING_BASE_SKIP_DRAIN when inflight-migration is on
Alexandr Moshkov <[email protected]> Mon, 3 Aug 2026 12:28:53 +0500
| Newsgroups | dev.linux.lists.virtio-fs,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Currently during live migration vhost-user-blk sends GET_VRING_BASE to stop vrings, which causes the back-end to drain all in-flight I/O before returning. This blocks the migration source until all I/O completes, adding significant downtime proportional to the I/O load. When inflight-migration is enabled, send GET_VRING_BASE_SKIP_DRAIN instead. This instructs the back-end to immediately suspend in-flight I/O and record it in the shared inflight region, which is then migrated to the destination host along with the rest of the device state. Since inflight-migration can only be toggled while the VM is running, i2ts value at stop time reliably reflects the intent set on a live VM. There is no need to check migration runstate to decide whether to skip draining. Using GET_VRING_BASE_SKIP_DRAIN on a regular VM stop is safe - the back-end records any in-flight requests in the shared inflight region, and they will be resubmitted when the VM starts again via SET_INFLIGHT_FD. If the back-end does not support VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN, migration is aborted with an error in pre_save rather than hitting an assert at runtime. Signed-off-by: Alexandr Moshkov <[email protected]> --- hw/block/vhost-user-blk.c | 29 +++++++++++++++++++++++------ hw/virtio/vhost-user.c | 3 +-- include/hw/virtio/vhost-user.h | 1 - 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 7a7e1a6d19..6a11dc23c3 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -135,10 +135,7 @@ static bool vhost_user_blk_inflight_needed(void *opaque) { struct VHostUserBlk *s = opaque; - bool inflight_migration = virtio_has_feature(s->dev.protocol_features, - VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT); - - return inflight_migration; + return s->inflight_migration; } @@ -239,11 +236,13 @@ static int vhost_user_blk_stop(VirtIODevice *vdev) return 0; } + bool skip_drain = vhost_user_blk_inflight_needed(s); + force_stop = s->skip_get_vring_base_on_force_shutdown && qemu_force_shutdown_requested(); ret = force_stop ? vhost_dev_force_stop(&s->dev, vdev, true) : - vhost_dev_stop(&s->dev, vdev, true, false); + vhost_dev_stop(&s->dev, vdev, true, skip_drain); err = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); if (err < 0) { @@ -375,7 +374,6 @@ static int vhost_user_blk_connect(DeviceState *dev, Error **errp) vhost_dev_set_config_notifier(&s->dev, &blk_ops); s->vhost_user.supports_config = true; - s->vhost_user.supports_inflight_migration = s->inflight_migration; ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0, errp); if (ret < 0) { @@ -598,10 +596,29 @@ static struct vhost_dev *vhost_user_blk_get_vhost(VirtIODevice *vdev) return &s->dev; } +static bool vhost_user_blk_pre_save(void *opaque, Error **errp) +{ + VHostUserBlk *s = VHOST_USER_BLK(opaque); + + bool inflight_migration_enabled = vhost_user_has_protocol_feature(&s->dev, + VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN); + + if (vhost_user_blk_inflight_needed(s) && !inflight_migration_enabled) { + error_setg(errp, "can't migrate vhost-user-blk device: " + "backend doesn't support " + "VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN " + "protocol feature"); + return false; + } + + return true; +} + static const VMStateDescription vmstate_vhost_user_blk_inflight = { .name = "vhost-user-blk/inflight", .version_id = 1, .needed = vhost_user_blk_inflight_needed, + .pre_save_errp = vhost_user_blk_pre_save, .fields = (const VMStateField[]) { VMSTATE_VHOST_INFLIGHT_REGION(inflight, VHostUserBlk), VMSTATE_END_OF_LIST() diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 58b142cbee..c8a3d184c8 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -2571,8 +2571,7 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, } } - if (!u->user->supports_inflight_migration || - !virtio_has_feature(protocol_features, + if (!virtio_has_feature(protocol_features, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) { protocol_features &= ~(1ULL << VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT); diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index 47c13f8677..78b4fba27f 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -73,7 +73,6 @@ typedef struct VhostUserState { GPtrArray *notifiers; int memory_slots; bool supports_config; - bool supports_inflight_migration; } VhostUserState; /** -- 2.34.1