public inbox for qemu-devel@nongnu.org
 help / color / mirror / Atom feed
From: Jonah Palmer <jonah.palmer@oracle.com>
To: qemu-devel@nongnu.org
Cc: eduardo@habkost.net, marcel.apfelbaum@gmail.com,
	philmd@linaro.org, wangyanan55@huawei.com, zhao1.liu@intel.com,
	mst@redhat.com, sgarzare@redhat.com, jasowang@redhat.com,
	leiyang@redhat.com, si-wei.liu@oracle.com, eperezma@redhat.com,
	boris.ostrovsky@oracle.com, armbru@redhat.com,
	jonah.palmer@oracle.com
Subject: [RFC v2 03/14] virtio,virtio-net: virtio-delta VMSD - VQ state
Date: Fri, 20 Mar 2026 14:20:04 +0000	[thread overview]
Message-ID: <20260320142015.3856652-4-jonah.palmer@oracle.com> (raw)
In-Reply-To: <20260320142015.3856652-1-jonah.palmer@oracle.com>

Introduce a new virtio VMStateDescription vmstate_virtio_delta for
VirtIODevices.

This parent VMSD will be used by virtio devices that send their state
early (before the stop-and-copy phase) and only need to resend any
state that changed since then. Any data that is re-sent is done during
the stop-and-copy phase, when the source has been paused.

This patch also adds subsections to vmstate_virtio_delta for resyncing a
VirtIODevice's VQs' state. Since it's more likely than not that these
fields changed since they were sent early, we just send their updated
values without checking if they did indeed change.

After loading delta VQ state, re-sync runtime shadow queue indices to the
delta-loaded avail indices and clear signalled_used_valid so runtime
queue bookkeeping stays consistent for both split and packed rings.

Lastly, this new VirtIODevice parent VMSD is registered for a virtio-net
device only if it has its early-mig property enabled.

Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
---
 hw/net/virtio-net.c        |   2 +
 hw/virtio/virtio.c         | 150 +++++++++++++++++++++++++++++++++++++
 include/hw/virtio/virtio.h |   3 +
 3 files changed, 155 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index ddd6ed6e62..5d71ad235e 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -4090,6 +4090,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
             vdev->migration->early_load = false;
 
             vmstate_register_any(VMSTATE_IF(n), &vmstate_virtio_net_early, n);
+            virtio_delta_vmsd_register(vdev);
         }
     }
 }
@@ -4142,6 +4143,7 @@ static void virtio_net_device_unrealize(DeviceState *dev)
         vdev->migration = NULL;
 
         vmstate_unregister(VMSTATE_IF(n), &vmstate_virtio_net_early, n);
+        virtio_delta_vmsd_unregister(vdev);
     }
 }
 
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 48de4a430b..47236bf7d7 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2780,6 +2780,13 @@ static bool virtio_virtqueue_needed(void *opaque)
     return virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1);
 }
 
+static bool virtio_split_virtqueue_needed(void *opaque)
+{
+    VirtIODevice *vdev = opaque;
+
+    return !virtio_host_has_feature(vdev, VIRTIO_F_RING_PACKED);
+}
+
 static bool virtio_packed_virtqueue_needed(void *opaque)
 {
     VirtIODevice *vdev = opaque;
@@ -2842,6 +2849,18 @@ static const VMStateDescription vmstate_virtqueue = {
     }
 };
 
+static const VMStateDescription vmstate_split_virtqueue = {
+    .name = "split_virtqueue_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT16(last_avail_idx, struct VirtQueue),
+        VMSTATE_UINT16(used_idx, struct VirtQueue),
+        VMSTATE_UINT32(inuse, struct VirtQueue),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_packed_virtqueue = {
     .name = "packed_virtqueue_state",
     .version_id = 1,
@@ -2856,6 +2875,89 @@ static const VMStateDescription vmstate_packed_virtqueue = {
     }
 };
 
+/*
+ * Temporary type used with VMSTATE_WITH_TMP to migrate
+ * active VQs only for VirtIODevices that participated
+ * in early live migration.
+ */
+typedef struct VirtIOMigVQsTmp {
+    VirtIODevice *parent;
+    VirtQueue *vqs;
+    uint16_t num_vqs;
+} VirtIOMigVQsTmp;
+
+static int virtio_delta_vqs_pre_save(void *opaque)
+{
+    VirtIOMigVQsTmp *tmp = opaque;
+    tmp->vqs = tmp->parent->vq;
+    tmp->num_vqs = virtio_get_num_queues(tmp->parent);
+    return 0;
+}
+
+static int virtio_delta_vqs_pre_load(void *opaque)
+{
+    VirtIOMigVQsTmp *tmp = opaque;
+    uint16_t num_vqs = virtio_get_num_queues(tmp->parent);
+
+    tmp->vqs = tmp->parent->vq;
+    tmp->num_vqs = num_vqs;
+
+    if (tmp->num_vqs > VIRTIO_QUEUE_MAX) {
+        return -EINVAL;
+    }
+    return 0;
+}
+
+/* Re-sync runtime shadow queue indices with final delta-loaded indices */
+static int virtio_delta_vqs_post_load(void *opaque, int version_id)
+{
+    VirtIOMigVQsTmp *tmp = opaque;
+    bool packed = virtio_vdev_has_feature(tmp->parent, VIRTIO_F_RING_PACKED);
+    int i;
+
+    for (i = 0; i < tmp->num_vqs; i++) {
+        VirtQueue *vq = &tmp->vqs[i];
+
+        if (!vq->vring.desc) {
+            continue;
+        }
+
+        vq->shadow_avail_idx = vq->last_avail_idx;
+        if (packed) {
+            vq->shadow_avail_wrap_counter = vq->last_avail_wrap_counter;
+        }
+        vq->signalled_used_valid = false;
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_virtio_delta_split_vqs_tmp = {
+    .name = "virtio-delta/split_vqs_tmp",
+    .pre_save = virtio_delta_vqs_pre_save,
+    .pre_load = virtio_delta_vqs_pre_load,
+    .post_load = virtio_delta_vqs_post_load,
+    .fields = (const VMStateField[]) {
+        VMSTATE_STRUCT_VARRAY_POINTER_UINT16(vqs, VirtIOMigVQsTmp, num_vqs,
+                                             vmstate_split_virtqueue,
+                                             VirtQueue),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static const VMStateDescription vmstate_virtio_delta_packed_vqs_tmp = {
+    .name = "virtio-delta/packed_vqs_tmp",
+    .pre_save = virtio_delta_vqs_pre_save,
+    .pre_load = virtio_delta_vqs_pre_load,
+    .post_load = virtio_delta_vqs_post_load,
+    .fields = (const VMStateField[]) {
+        VMSTATE_STRUCT_VARRAY_POINTER_UINT16(vqs, VirtIOMigVQsTmp, num_vqs,
+                                             vmstate_packed_virtqueue,
+                                             VirtQueue),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
 static const VMStateDescription vmstate_virtio_virtqueues = {
     .name = "virtio/virtqueues",
     .version_id = 1,
@@ -3053,6 +3155,54 @@ static const VMStateDescription vmstate_virtio = {
     }
 };
 
+static const VMStateDescription vmstate_virtio_delta_split_virtqueues = {
+    .name = "virtio-delta/split_virtqueues",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = &virtio_split_virtqueue_needed,
+    .fields = (const VMStateField[]) {
+        VMSTATE_WITH_TMP(VirtIODevice, VirtIOMigVQsTmp,
+                         vmstate_virtio_delta_split_vqs_tmp),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_virtio_delta_packed_virtqueues = {
+    .name = "virtio-delta/packed_virtqueues",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = &virtio_packed_virtqueue_needed,
+    .fields = (const VMStateField[]) {
+        VMSTATE_WITH_TMP(VirtIODevice, VirtIOMigVQsTmp,
+                         vmstate_virtio_delta_packed_vqs_tmp),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_virtio_delta = {
+    .name = "virtio-delta",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (const VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (const VMStateDescription * const []) {
+        &vmstate_virtio_delta_split_virtqueues,
+        &vmstate_virtio_delta_packed_virtqueues,
+        NULL
+    }
+};
+
+void virtio_delta_vmsd_register(VirtIODevice *vdev)
+{
+    vmstate_register_any(VMSTATE_IF(vdev), &vmstate_virtio_delta, vdev);
+}
+
+void virtio_delta_vmsd_unregister(VirtIODevice *vdev)
+{
+    vmstate_unregister(VMSTATE_IF(vdev), &vmstate_virtio_delta, vdev);
+}
+
 int virtio_save(VirtIODevice *vdev, QEMUFile *f)
 {
     BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 4c886eb48b..74fed8c324 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -305,6 +305,9 @@ int virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
 
 void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
 
+void virtio_delta_vmsd_register(VirtIODevice *vdev);
+void virtio_delta_vmsd_unregister(VirtIODevice *vdev);
+
 int virtio_save(VirtIODevice *vdev, QEMUFile *f);
 
 extern const VMStateInfo virtio_vmstate_info;
-- 
2.51.0



  parent reply	other threads:[~2026-03-20 14:21 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-20 14:20 [RFC v2 00/14] virtio-net: early VMStateDescription live migration support Jonah Palmer
2026-03-20 14:20 ` [RFC v2 01/14] machine,virtio-net: add early-mig property Jonah Palmer
2026-03-23 10:25   ` Eugenio Perez Martin
2026-03-24 14:07     ` Jonah Palmer
2026-03-26  8:02       ` Eugenio Perez Martin
2026-03-20 14:20 ` [RFC v2 02/14] virtio, virtio-net: add initial early VMSD for setup-phase migration Jonah Palmer via qemu development
2026-03-24  9:27   ` [RFC v2 02/14] virtio,virtio-net: " Eugenio Perez Martin
2026-03-24 14:28     ` Jonah Palmer
2026-03-24 14:38       ` Eugenio Perez Martin
2026-03-24 17:16         ` Jonah Palmer
2026-03-20 14:20 ` Jonah Palmer [this message]
2026-03-20 14:20 ` [RFC v2 04/14] virtio-net: detect VirtIODevice status mid-migration change Jonah Palmer
2026-03-24 10:45   ` Eugenio Perez Martin
2026-03-24 15:01     ` Jonah Palmer
2026-03-26 10:08       ` Eugenio Perez Martin
2026-03-20 14:20 ` [RFC v2 05/14] virtio-net: detect VirtIODevice config buffer " Jonah Palmer
2026-03-24 10:48   ` Eugenio Perez Martin
2026-03-24 15:25     ` Jonah Palmer
2026-03-20 14:20 ` [RFC v2 06/14] virtio-net: detect VirtIONet MAC addr " Jonah Palmer
2026-03-20 14:20 ` [RFC v2 07/14] virtio-net: detect VirtIONet MAC table mid-migration changes Jonah Palmer
2026-03-20 14:20 ` [RFC v2 08/14] virtio-net: detect VirtIONet status mid-migration change Jonah Palmer
2026-03-24 11:26   ` Eugenio Perez Martin
2026-03-24 16:23     ` Jonah Palmer
2026-03-26 10:20       ` Eugenio Perez Martin
2026-03-20 14:20 ` [RFC v2 09/14] virtio-net: detect VirtIONet Rx filter mid-migration changes Jonah Palmer
2026-03-20 14:20 ` [RFC v2 10/14] virtio-net: detect VirtIONet VLAN filter table changes Jonah Palmer
2026-03-20 14:20 ` [RFC v2 11/14] virtio-net: detect VirtIONet guest offload & MQ mid-migration changes Jonah Palmer
2026-03-20 14:20 ` [RFC v2 12/14] virtio-net: detect RSS state " Jonah Palmer
2026-03-20 14:20 ` [RFC v2 13/14] virtio-net: detect pending Tx work for VQs " Jonah Palmer
2026-03-24 11:35   ` Eugenio Perez Martin
2026-03-24 16:47     ` Jonah Palmer
2026-03-26 10:30       ` Eugenio Perez Martin
2026-03-20 14:20 ` [RFC v2 14/14] virtio-net, vhost-net: early migration support for vhost-net Jonah Palmer via qemu development

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260320142015.3856652-4-jonah.palmer@oracle.com \
    --to=jonah.palmer@oracle.com \
    --cc=armbru@redhat.com \
    --cc=boris.ostrovsky@oracle.com \
    --cc=eduardo@habkost.net \
    --cc=eperezma@redhat.com \
    --cc=jasowang@redhat.com \
    --cc=leiyang@redhat.com \
    --cc=marcel.apfelbaum@gmail.com \
    --cc=mst@redhat.com \
    --cc=philmd@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=sgarzare@redhat.com \
    --cc=si-wei.liu@oracle.com \
    --cc=wangyanan55@huawei.com \
    --cc=zhao1.liu@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox