Commit c2f4030c42 for qemu.org
commit c2f4030c42da8344ac7c49de1c48d192f95a53ee
Author: Alexandr Moshkov <dtalexundeer@yandex-team.ru>
Date: Mon Aug 3 12:28:53 2026 +0500
vhost-user-blk: use GET_VRING_BASE_SKIP_DRAIN when inflight-migration is on
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 <dtalexundeer@yandex-team.ru>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260803072853.2920007-7-dtalexundeer@yandex-team.ru>
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
index 3eaaa19719..3dade143c9 100644
--- a/hw/block/vhost-user-blk.c
+++ b/hw/block/vhost-user-blk.c
@@ -141,10 +141,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;
}
@@ -245,11 +242,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) {
@@ -381,7 +380,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) {
@@ -608,10 +606,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 5fb5d61afb..65889b0776 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -2596,8 +2596,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;
/**