vfio/migration: Add new switchover-ack mechanism
Add support for the new switchover-ack mechanism. This includes requesting a switchover ACK on the first save_query_pending call (with exact=false) if VFIO precopy is supported. This achieves the same functionality of legacy switchover-ack but with the new switchover-ack mechanism. Keep legacy switchover-ack functionality for backward compatibility. Reviewed-by: Peter Xu <peterx@redhat.com> Signed-off-by: Avihai Horon <avihaih@nvidia.com> Link: https://lore.kernel.org/qemu-devel/20260706085211.13905-12-avihaih@nvidia.com Signed-off-by: Cédric Le Goater <clg@redhat.com>
Avihai Horon committed
Jul 6, 2026 at 11:52 UTC
f4ba2df1d99de5a583c2c5c02443a7782603a51a
3 files changed
+14
-2
hw/vfio/migration.c
+12
-1
@@ -582,6 +582,9 @@ static int vfio_save_setup(QEMUFile *f, void *opaque, Error **errp)
582
}
583
584
vfio_query_precopy_size(migration);
585
+ if (migrate_switchover_ack() && !migrate_switchover_ack_legacy()) {
586
+ migration->request_switchover_ack = true;
587
+ }
588
589
break;
590
case VFIO_DEVICE_STATE_STOP:
@@ -634,6 +637,7 @@ static void vfio_save_cleanup(void *opaque)
637
migration->precopy_init_size = 0;
638
migration->precopy_dirty_size = 0;
639
migration->initial_data_sent = false;
640
+ migration->request_switchover_ack = false;
641
vfio_migration_cleanup(vbasedev);
642
trace_vfio_save_cleanup(vbasedev->name);
643
}
@@ -655,6 +659,7 @@ static void vfio_state_pending(void *opaque, MigPendingData *pending,
659
VFIODevice *vbasedev = opaque;
660
VFIOMigration *migration = vbasedev->migration;
661
uint64_t precopy_size, stopcopy_size;
662
+ bool request_switchover_ack = false;
663
664
/*
665
* The final pending query runs during switchover downtime. VFIO does not
@@ -676,10 +681,16 @@ static void vfio_state_pending(void *opaque, MigPendingData *pending,
681
682
pending->precopy_bytes += precopy_size;
683
pending->stopcopy_bytes += stopcopy_size;
684
+ if (migration->request_switchover_ack) {
685
+ pending->switchover_ack_pending++;
686
+ request_switchover_ack = true;
687
+ migration->request_switchover_ack = false;
688
+ }
689
690
trace_vfio_state_pending(vbasedev->name, migration->stopcopy_size,
691
migration->precopy_init_size,
682
- migration->precopy_dirty_size, exact, final);
692
+ migration->precopy_dirty_size,
693
+ request_switchover_ack, exact, final);
694
}
695
696
static bool vfio_is_active_iterate(void *opaque)
hw/vfio/trace-events
+1
-1
@@ -176,7 +176,7 @@ vfio_save_device_config_state(const char *name) " (%s)"
176
vfio_save_iterate(const char *name, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy initial size %"PRIu64" precopy dirty size %"PRIu64
177
vfio_save_iterate_start(const char *name) " (%s)"
178
vfio_save_setup(const char *name, uint64_t data_buffer_size) " (%s) data buffer size %"PRIu64
179
-vfio_state_pending(const char *name, uint64_t stopcopy_size, uint64_t precopy_init_size, uint64_t precopy_dirty_size, bool exact, bool final) " (%s) stopcopy size %"PRIu64", precopy initial size %"PRIu64", precopy dirty size %"PRIu64", exact %d, final %d"
179
+vfio_state_pending(const char *name, uint64_t stopcopy_size, uint64_t precopy_init_size, uint64_t precopy_dirty_size, bool request_switchover_ack, bool exact, bool final) " (%s) stopcopy size %"PRIu64", precopy initial size %"PRIu64", precopy dirty size %"PRIu64", request switchover ack %d, exact %d, final %d"
180
vfio_send_init_data_flag(const char *name) " (%s)"
181
vfio_vmstate_change(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s"
182
vfio_vmstate_change_prepare(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s"
hw/vfio/vfio-migration-internal.h
+1
@@ -58,6 +58,7 @@ typedef struct VFIOMigration {
58
bool multifd_transfer;
59
VFIOMultifd *multifd;
60
bool initial_data_sent;
61
+ bool request_switchover_ack;
62
63
bool event_save_iterate_started;
64
bool event_precopy_empty_hit;