Iterative live migration for virtio-net sends an initial VMStateDescription while the source is still active. Because data continues to flow for virtio-net, the guest's avail index continues to increment after last_avail_idx had already been sent. This causes the destination to often see something like this from virtio_error():
VQ 0 size 0x100 Guest index 0x0 inconsistent with Host index 0xc: delta 0xfff4 This patch suppresses this consistency check if we're loading the initial VMStateDescriptions via iterative migration and unsuppresses it for the stop-and-copy phase when the final VMStateDescriptions (carrying the correct indices) are loaded. A temporary VirtIODevMigration migration data structure is introduced here to represent the iterative migration process for a VirtIODevice. For now it just holds a flag to indicate whether or not the initial VMStateDescription was sent during the iterative live migration process. Signed-off-by: Jonah Palmer <jonah.pal...@oracle.com> --- hw/net/virtio-net.c | 13 +++++++++++++ hw/virtio/virtio.c | 32 ++++++++++++++++++++++++-------- include/hw/virtio/virtio.h | 6 ++++++ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 86a6fe5b91..b7ac5e8278 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3843,12 +3843,19 @@ static void virtio_net_save_cleanup(void *opaque) static int virtio_net_load_setup(QEMUFile *f, void *opaque, Error **errp) { + VirtIONet *n = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(n); + vdev->migration = g_new0(VirtIODevMigration, 1); + vdev->migration->iterative_vmstate_loaded = false; + return 0; } static int virtio_net_load_state(QEMUFile *f, void *opaque, int version_id) { VirtIONet *n = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(n); + VirtIODevMigration *mig = vdev->migration; uint64_t flag; flag = qemu_get_be64(f); @@ -3861,6 +3868,7 @@ static int virtio_net_load_state(QEMUFile *f, void *opaque, int version_id) case VNET_MIG_F_INIT_STATE: { vmstate_load_state(f, &vmstate_virtio_net, n, VIRTIO_NET_VM_VERSION); + mig->iterative_vmstate_loaded = true; break; } default: @@ -3875,6 +3883,11 @@ static int virtio_net_load_state(QEMUFile *f, void *opaque, int version_id) static int virtio_net_load_cleanup(void *opaque) { + VirtIONet *n = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(n); + g_free(vdev->migration); + vdev->migration = NULL; + return 0; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 5534251e01..68957ee7d1 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3222,6 +3222,7 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) int32_t config_len; uint32_t num; uint32_t features; + bool inconsistent_indices; BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); @@ -3365,6 +3366,16 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) if (vdev->vq[i].vring.desc) { uint16_t nheads; + /* + * Ring indices will be inconsistent during iterative migration. The actual + * indices will be sent later during the stop-and-copy phase. + */ + if (vdev->migration) { + inconsistent_indices = !vdev->migration->iterative_vmstate_loaded; + } else { + inconsistent_indices = false; + } + /* * VIRTIO-1 devices migrate desc, used, and avail ring addresses so * only the region cache needs to be set up. Legacy devices need @@ -3384,14 +3395,19 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) 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) { - virtio_error(vdev, "VQ %d size 0x%x Guest index 0x%x " - "inconsistent with Host index 0x%x: delta 0x%x", - i, vdev->vq[i].vring.num, - vring_avail_idx(&vdev->vq[i]), - vdev->vq[i].last_avail_idx, nheads); + if (!inconsistent_indices) { + 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) { + virtio_error(vdev, "VQ %d size 0x%x Guest index 0x%x " + "inconsistent with Host index 0x%x: delta 0x%x", + i, vdev->vq[i].vring.num, + vring_avail_idx(&vdev->vq[i]), + vdev->vq[i].last_avail_idx, nheads); + inconsistent_indices = true; + } + } + if (inconsistent_indices) { vdev->vq[i].used_idx = 0; vdev->vq[i].shadow_avail_idx = 0; vdev->vq[i].inuse = 0; diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 214d4a77e9..06b6e6ba65 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -98,6 +98,11 @@ enum virtio_device_endian { VIRTIO_DEVICE_ENDIAN_BIG, }; +/* VirtIODevice iterative live migration data structure */ +typedef struct VirtIODevMigration { + bool iterative_vmstate_loaded; +} VirtIODevMigration; + /** * struct VirtIODevice - common VirtIO structure * @name: name of the device @@ -151,6 +156,7 @@ struct VirtIODevice bool disable_legacy_check; bool vhost_started; VMChangeStateEntry *vmstate; + VirtIODevMigration *migration; char *bus_name; uint8_t device_endian; /** -- 2.47.1