Acked-by: Raphael Norwitz <[email protected]>
On Thu, Oct 16, 2025 at 7:47 AM Vladimir Sementsov-Ogievskiy <[email protected]> wrote: > > Add logic to transfer virtio notifiers through migration channel > for vhost backend migration case. > > Signed-off-by: Vladimir Sementsov-Ogievskiy <[email protected]> > --- > hw/virtio/virtio-bus.c | 2 +- > hw/virtio/virtio.c | 73 ++++++++++++++++++++++++++++++++++++-- > include/hw/virtio/virtio.h | 2 ++ > 3 files changed, 74 insertions(+), 3 deletions(-) > > diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c > index 9b545acda3..577693b6c9 100644 > --- a/hw/virtio/virtio-bus.c > +++ b/hw/virtio/virtio-bus.c > @@ -291,7 +291,7 @@ int virtio_bus_set_host_notifier(VirtioBusState *bus, int > n, bool assign) > return -ENOSYS; > } > > - if (assign) { > + if (assign && !virtio_is_vhost_backend_transfer(vdev)) { > r = event_notifier_init(notifier, 1); > if (r < 0) { > error_report("%s: unable to init event notifier: %s (%d)", > diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c > index 4184aff75c..bf361811d0 100644 > --- a/hw/virtio/virtio.c > +++ b/hw/virtio/virtio.c > @@ -26,6 +26,7 @@ > #include "hw/virtio/virtio.h" > #include "hw/virtio/vhost.h" > #include "migration/qemu-file-types.h" > +#include "migration/qemu-file.h" > #include "qemu/atomic.h" > #include "hw/virtio/virtio-bus.h" > #include "hw/qdev-properties.h" > @@ -3032,6 +3033,7 @@ int virtio_save(VirtIODevice *vdev, QEMUFile *f) > uint32_t guest_features_lo = (vdev->guest_features & 0xffffffff); > int i; > Error *local_err = NULL; > + bool migrating_backend = virtio_is_vhost_backend_transfer(vdev); > > if (k->save_config) { > k->save_config(qbus->parent, f); > @@ -3065,11 +3067,23 @@ int virtio_save(VirtIODevice *vdev, QEMUFile *f) > */ > qemu_put_be64(f, vdev->vq[i].vring.desc); > qemu_put_be16s(f, &vdev->vq[i].last_avail_idx); > + > + if (migrating_backend) { > + qemu_file_put_fd(f, > + > event_notifier_get_fd(&vdev->vq[i].host_notifier)); > + qemu_file_put_fd( > + f, event_notifier_get_fd(&vdev->vq[i].guest_notifier)); > + } > + > if (k->save_queue) { > k->save_queue(qbus->parent, i, f); > } > } > > + if (migrating_backend) { > + qemu_file_put_fd(f, event_notifier_get_fd(&vdev->config_notifier)); > + } > + > if (vdc->save != NULL) { > vdc->save(vdev, f); > } > @@ -3295,6 +3309,7 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int > version_id) > VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); > VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); > Error *local_err = NULL; > + bool migrating_backend = virtio_is_vhost_backend_transfer(vdev); > > /* > * We poison the endianness to ensure it does not get used before > @@ -3364,6 +3379,13 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int > version_id) > vdev->vq[i].signalled_used_valid = false; > vdev->vq[i].notification = true; > > + if (migrating_backend) { > + event_notifier_init_fd(&vdev->vq[i].host_notifier, > + qemu_file_get_fd(f)); > + event_notifier_init_fd(&vdev->vq[i].guest_notifier, > + qemu_file_get_fd(f)); > + } > + > if (!vdev->vq[i].vring.desc && vdev->vq[i].last_avail_idx) { > error_report("VQ %d address 0x0 " > "inconsistent with Host index 0x%x", > @@ -3377,6 +3399,10 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int > version_id) > } > } > > + if (migrating_backend) { > + event_notifier_init_fd(&vdev->config_notifier, qemu_file_get_fd(f)); > + } > + > virtio_notify_vector(vdev, VIRTIO_NO_VECTOR); > > if (vdc->load != NULL) { > @@ -3394,6 +3420,19 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int > version_id) > } > } > > + if (migrating_backend) { > + /* > + * On vhost backend migration, device do load host_features from > + * migration stream. So update host_features. > + */ > + vdev->host_features = vdc->get_features(vdev, vdev->host_features, > + &local_err); > + if (local_err) { > + error_report_err(local_err); > + return -EINVAL; > + } > + } > + > /* Subsections */ > ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1, &local_err); > if (ret) { > @@ -3447,6 +3486,18 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int > version_id) > continue; > } > > + if (migrating_backend) { > + /* > + * Indices are not synced prior to backend migration (as we > + * don't stop vrings by GET_VRING_BASE). No reason to sync > them > + * now, and do any checks. > + */ > + vdev->vq[i].used_idx = 0; > + vdev->vq[i].shadow_avail_idx = 0; > + vdev->vq[i].inuse = 0; > + continue; > + } > + > nheads = vring_avail_idx(&vdev->vq[i]) - > vdev->vq[i].last_avail_idx; > /* Check it isn't doing strange things with descriptor numbers. > */ > if (nheads > vdev->vq[i].vring.num) { > @@ -3815,8 +3866,9 @@ int virtio_queue_set_guest_notifier(VirtIODevice *vdev, > int n, bool assign, > EventNotifierHandler *read_fn = is_config ? > virtio_config_guest_notifier_read : > virtio_queue_guest_notifier_read; > + bool migrating_backend = virtio_is_vhost_backend_transfer(vdev); > > - if (assign) { > + if (assign && !migrating_backend) { > int r = event_notifier_init(notifier, 0); > if (r < 0) { > return r; > @@ -3826,7 +3878,7 @@ int virtio_queue_set_guest_notifier(VirtIODevice *vdev, > int n, bool assign, > event_notifier_set_handler(notifier, > (assign && !with_irqfd) ? read_fn : NULL); > > - if (!assign) { > + if (!assign && !migrating_backend) { > /* Test and clear notifier before closing it,*/ > /* in case poll callback didn't have time to run. */ > read_fn(notifier); > @@ -4445,6 +4497,23 @@ done: > return element; > } > > +bool virtio_is_vhost_backend_transfer(VirtIODevice *vdev) > +{ > + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); > + struct vhost_dev *hdev; > + > + if (!vdc->get_vhost) { > + return false; > + } > + > + hdev = vdc->get_vhost(vdev); > + if (!hdev) { > + return false; > + } > + > + return hdev->backend_transfer; > +} > + > static const TypeInfo virtio_device_info = { > .name = TYPE_VIRTIO_DEVICE, > .parent = TYPE_DEVICE, > diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h > index 620ee4e389..8e2d3019cd 100644 > --- a/include/hw/virtio/virtio.h > +++ b/include/hw/virtio/virtio.h > @@ -242,6 +242,8 @@ struct VirtioDeviceClass { > bool (*skip_vhost_migration_log)(VirtIODevice *vdev); > }; > > +bool virtio_is_vhost_backend_transfer(VirtIODevice *vdev); > + > void virtio_instance_init_common(Object *proxy_obj, void *data, > size_t vdev_size, const char *vdev_name); > > -- > 2.48.1 > >
