@samitouri / QOSamiQemu / commits / 941f269923

vfio/migration: Check VFIO_PRECOPY_INFO_REINIT during switchover

VFIO_REPCOPY_INFO_REINIT is checked only during precopy, before the switchover decision. However, the switchover decision and guest stop are not atomic, so a VFIO device may want to set VFIO_PRECOPY_INFO_REINIT and request another switchover ACK in the gap after switchover decision has been made but before the guest is stopped. This would be missed and may increase downtime. Solve this by checking if VFIO_PRECOPY_INFO_REINIT was set during that gap, and request a new switchover-ack in the final save_state_pending call. Query precopy info after vCPUs are stopped but before transitioning from PRE_COPY state, when its valid to call the ioctl. Acked-by: Peter Xu <peterx@redhat.com> Signed-off-by: Avihai Horon <avihaih@nvidia.com> Link: https://lore.kernel.org/qemu-devel/20260706085211.13905-14-avihaih@nvidia.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Avihai Horon committed Jul 6, 2026 at 11:52 UTC 941f269923929042b3569cd5b4ce547ec33bfd4a
1 file changed +32
hw/vfio/migration.c
+32
@@ -685,6 +685,9 @@ static void vfio_state_pending(void *opaque, MigPendingData *pending,
685 * The final pending query runs during switchover downtime. VFIO does not
686 * need a fresh device pending-data query then to get the latest dirty
687 * data, so avoid the extra work and report the cached counters below.
688 + * On the other hand, precopy sync is needed to check if switchover ACK was
689 + * requested, but that's already done during guest stop when device is in
690 + * PRE_COPY state.
691 */
692 if (exact && !final) {
693 vfio_state_pending_sync(vbasedev);
@@ -964,6 +967,26 @@ static const SaveVMHandlers savevm_vfio_handlers = {
967
968 /* ---------------------------------------------------------------------- */
969
970 +static void vfio_final_precopy_reinit_check(VFIODevice *vbasedev)
971 +{
972 + VFIOMigration *migration = vbasedev->migration;
973 + int ret;
974 +
975 + if (!migration->precopy_info_v2_used || !migrate_switchover_ack() ||
976 + migrate_switchover_ack_legacy()) {
977 + return;
978 + }
979 +
980 + ret = vfio_query_precopy_size(migration);
981 + if (ret) {
982 + error_report("%s: Final precopy reinit check failed (err: %d)",
983 + vbasedev->name, ret);
984 + /* If query failed, assume reinit and request switchover-ack */
985 + migration->request_switchover_ack = true;
986 + migration->initial_data_sent = false;
987 + }
988 +}
989 +
990 static void vfio_vmstate_change_prepare(void *opaque, bool running,
991 RunState state)
992 {
@@ -977,6 +1000,15 @@ static void vfio_vmstate_change_prepare(void *opaque, bool running,
1000 VFIO_DEVICE_STATE_PRE_COPY_P2P :
1001 VFIO_DEVICE_STATE_RUNNING_P2P;
1002
1003 + if (migration->device_state == VFIO_DEVICE_STATE_PRE_COPY) {
1004 + /*
1005 + * Now that vCPUs are stopped, check if new init_bytes are available
1006 + * since switchover decision, to be reported in the final
1007 + * save_query_pending.
1008 + */
1009 + vfio_final_precopy_reinit_check(vbasedev);
1010 + }
1011 +
1012 ret = vfio_migration_set_state_or_reset(vbasedev, new_state, &local_err);
1013 if (ret) {
1014 /*