@samitouri / QOSamiQemu / commits / 3c11e33016

migration: Run final save_query_pending at switchover

Before switchover, the source needs one last exact pending query so modules can flush dirty state. This is currently done ad hoc in modules handlers. For example, RAM syncs its dirty bitmap in its save_complete handler. This should be a general concept relevant for any module, so extract it to migration core instead by running a final save_query_pending before switchover. The final query requires special handling by modules (e.g., it's called with BQL locked, during VM stop), so extend save_query_pending SaveVMHandlers callback and qemu_savevm_query_pending() with a "final" flag so migration modules can tell the last pending query during switchover from periodic iteration queries. Call final pending query also in COLO checkpoint, which needs to flush dirty state before the checkpoint's live state is saved. Unlike a regular switchover, COLO reaches completion repeatedly for every checkpoint, so this must be done on each one. Signed-off-by: Avihai Horon <avihaih@nvidia.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20260706085211.13905-4-avihaih@nvidia.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Avihai Horon committed Jul 6, 2026 at 11:51 UTC 3c11e33016639adf58530d9463cf720743c639f8
11 files changed +104 -52
hw/s390x/s390-stattrib.c
+1 -1
@@ -190,7 +190,7 @@ static int cmma_save_setup(QEMUFile *f, void *opaque, Error **errp)
190 }
191
192 static void cmma_state_pending(void *opaque, MigPendingData *pending,
193 - bool exact)
193 + bool exact, bool final)
194 {
195 S390StAttribState *sas = S390_STATTRIB(opaque);
196 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
hw/vfio/migration.c
+8 -3
@@ -622,13 +622,18 @@ static void vfio_state_pending_sync(VFIODevice *vbasedev)
622 }
623
624 static void vfio_state_pending(void *opaque, MigPendingData *pending,
625 - bool exact)
625 + bool exact, bool final)
626 {
627 VFIODevice *vbasedev = opaque;
628 VFIOMigration *migration = vbasedev->migration;
629 uint64_t precopy_size, stopcopy_size;
630
631 - if (exact) {
631 + /*
632 + * The final pending query runs during switchover downtime. VFIO does not
633 + * need a fresh device pending-data query then to get the latest dirty
634 + * data, so avoid the extra work and report the cached counters below.
635 + */
636 + if (exact && !final) {
637 vfio_state_pending_sync(vbasedev);
638 }
639
@@ -646,7 +651,7 @@ static void vfio_state_pending(void *opaque, MigPendingData *pending,
651
652 trace_vfio_state_pending(vbasedev->name, migration->stopcopy_size,
653 migration->precopy_init_size,
649 - migration->precopy_dirty_size, exact);
654 + migration->precopy_dirty_size, exact, final);
655 }
656
657 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) " (%s) stopcopy size %"PRIu64" precopy initial size %"PRIu64" precopy dirty size %"PRIu64 " exact %d"
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"
180 vfio_vmstate_change(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s"
181 vfio_vmstate_change_prepare(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s"
182
include/migration/register.h
+22 -19
@@ -171,6 +171,28 @@ typedef struct SaveVMHandlers {
171 */
172 bool (*is_active_iterate)(void *opaque);
173
174 + /**
175 + * @save_query_pending
176 + *
177 + * This estimates the remaining data to transfer on the source side.
178 + *
179 + * When @exact is true, a module must report accurate results. When
180 + * @exact is false, a module may report estimates.
181 + *
182 + * It's highly recommended that modules implement a faster version of
183 + * the query path (for example, by proper caching on the counters) if
184 + * an accurate query will be time-consuming.
185 + *
186 + * @opaque: data pointer passed to register_savevm_live()
187 + * @pending: pointer to a MigPendingData struct
188 + * @exact: set to true for an accurate (slow) query
189 + * @final: set to true for the final query during switchover. When final is
190 + * true, the query is called with BQL locked. Otherwise, it's called with
191 + * BQL unlocked.
192 + */
193 + void (*save_query_pending)(void *opaque, MigPendingData *pending,
194 + bool exact, bool final);
195 +
196 /* This runs outside the BQL in the migration case, and
197 * within the lock in the savevm case. The callback had better only
198 * use data that is local to the migration thread or protected
@@ -210,25 +232,6 @@ typedef struct SaveVMHandlers {
232 */
233 bool (*save_postcopy_prepare)(QEMUFile *f, void *opaque, Error **errp);
234
213 - /**
214 - * @save_query_pending
215 - *
216 - * This estimates the remaining data to transfer on the source side.
217 - *
218 - * When @exact is true, a module must report accurate results. When
219 - * @exact is false, a module may report estimates.
220 - *
221 - * It's highly recommended that modules implement a faster version of
222 - * the query path (for example, by proper caching on the counters) if
223 - * an accurate query will be time-consuming.
224 - *
225 - * @opaque: data pointer passed to register_savevm_live()
226 - * @pending: pointer to a MigPendingData struct
227 - * @exact: set to true for an accurate (slow) query
228 - */
229 - void (*save_query_pending)(void *opaque, MigPendingData *pending,
230 - bool exact);
231 -
235 /**
236 * @load_state
237 *
migration/block-dirty-bitmap.c
+8 -3
@@ -767,13 +767,16 @@ static int dirty_bitmap_save_complete(QEMUFile *f, void *opaque)
767 }
768
769 static void dirty_bitmap_state_pending(void *opaque, MigPendingData *data,
770 - bool exact)
770 + bool exact, bool final)
771 {
772 DBMSaveState *s = &((DBMState *)opaque)->save;
773 SaveBitmapState *dbms;
774 uint64_t pending = 0;
775
776 - bql_lock();
776 + /* Final pending query is called with BQL locked */
777 + if (!final) {
778 + bql_lock();
779 + }
780
781 QSIMPLEQ_FOREACH(dbms, &s->dbms_list, entry) {
782 uint64_t gran = bdrv_dirty_bitmap_granularity(dbms->bitmap);
@@ -783,7 +786,9 @@ static void dirty_bitmap_state_pending(void *opaque, MigPendingData *data,
786 pending += DIV_ROUND_UP(sectors * BDRV_SECTOR_SIZE, gran);
787 }
788
786 - bql_unlock();
789 + if (!final) {
790 + bql_unlock();
791 + }
792
793 trace_dirty_bitmap_state_pending(pending);
794
migration/colo.c
+10
@@ -409,6 +409,7 @@ static int colo_do_checkpoint_transaction(MigrationState *s,
409 QEMUFile *fb)
410 {
411 Error *local_err = NULL;
412 + MigPendingData pending = {};
413 int ret = -1;
414
415 colo_send_message(s->to_dst_file, COLO_MESSAGE_CHECKPOINT_REQUEST,
@@ -465,6 +466,15 @@ static int colo_do_checkpoint_transaction(MigrationState *s,
466 if (migrate_auto_converge()) {
467 mig_throttle_counter_reset();
468 }
469 +
470 + /*
471 + * Run the final pending query so migration modules can flush their dirty
472 + * state (e.g., RAM syncs its dirty bitmap) before this checkpoint's live
473 + * state is saved. Unlike a regular switchover, COLO reaches completion
474 + * repeatedly for every checkpoint, so this must be done on each one.
475 + */
476 + qemu_savevm_query_pending_final(&pending);
477 +
478 /*
479 * Only save VM's live state, which not including device state.
480 * TODO: We may need a timeout mechanism to prevent COLO process
migration/migration.c
+12 -2
@@ -2793,12 +2793,22 @@ static bool migration_switchover_prepare(MigrationState *s)
2793 static bool migration_switchover_start(MigrationState *s, Error **errp)
2794 {
2795 ERRP_GUARD();
2796 + MigPendingData pending = {};
2797
2798 if (!migration_switchover_prepare(s)) {
2799 error_setg(errp, "Switchover is interrupted");
2800 return false;
2801 }
2802
2803 + /*
2804 + * The final query to the whole system on dirty data to make sure we
2805 + * collect the latest status of the VM. For precopy, source QEMU will
2806 + * dump all the dirty data during switchover. For postcopy, this will
2807 + * properly update all the dirty bitmaps to finally generate the
2808 + * correct discard bitmaps; see ram_postcopy_send_discard_bitmap().
2809 + */
2810 + qemu_savevm_query_pending_final(&pending);
2811 +
2812 /* Inactivate disks except in COLO */
2813 if (!migrate_colo()) {
2814 /*
@@ -3291,7 +3301,7 @@ static void migration_iteration_go_next(MigPendingData *pending)
3301 /*
3302 * Do a slow sync first before boosting the iteration count.
3303 */
3294 - qemu_savevm_query_pending(pending, true);
3304 + qemu_savevm_query_pending_iter(pending, true);
3305
3306 /*
3307 * Update the dirty information for the whole system for this
@@ -3342,7 +3352,7 @@ static MigIterateState migration_iteration_run(MigrationState *s)
3352 bool complete_ready;
3353
3354 /* Fast path - get the estimated amount of pending data */
3345 - qemu_savevm_query_pending(&pending, false);
3355 + qemu_savevm_query_pending_iter(&pending, false);
3356
3357 if (in_postcopy) {
3358 /*
migration/ram.c
+23 -17
@@ -2686,9 +2686,6 @@ void ram_postcopy_send_discard_bitmap(MigrationState *ms)
2686
2687 RCU_READ_LOCK_GUARD();
2688
2689 - /* This should be our last sync, the src is now paused */
2690 - migration_bitmap_sync_precopy(true);
2691 -
2689 /* Easiest way to make sure we don't resume in the middle of a host-page */
2690 rs->pss[RAM_CHANNEL_PRECOPY].last_sent_block = NULL;
2691 rs->last_seen_block = NULL;
@@ -3376,10 +3373,6 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
3373 rs->last_stage = !migration_in_colo_state();
3374
3375 WITH_RCU_READ_LOCK_GUARD() {
3379 - if (!migration_in_postcopy()) {
3380 - migration_bitmap_sync_precopy(true);
3381 - }
3382 -
3376 ret = rdma_registration_start(f, RAM_CONTROL_FINISH);
3377 if (ret < 0) {
3378 qemu_file_set_error(f, ret);
@@ -3442,25 +3435,38 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
3435 return qemu_fflush(f);
3436 }
3437
3445 -static void ram_state_pending(void *opaque, MigPendingData *pending,
3446 - bool exact)
3438 +static void ram_state_pending_sync(bool exact, bool final)
3439 {
3448 - RAMState **temp = opaque;
3449 - RAMState *rs = *temp;
3450 - uint64_t remaining_size;
3451 -
3440 /*
3441 * Sync is not needed either with: (1) a fast query, or (2) after
3442 * postcopy has started (no new dirty will generate anymore).
3443 */
3456 - if (exact && !migration_in_postcopy()) {
3444 + if (!exact || migration_in_postcopy()) {
3445 + return;
3446 + }
3447 +
3448 + /* Final pending query is called with BQL locked */
3449 + if (!final) {
3450 bql_lock();
3458 - WITH_RCU_READ_LOCK_GUARD() {
3459 - migration_bitmap_sync_precopy(false);
3460 - }
3451 + }
3452 +
3453 + WITH_RCU_READ_LOCK_GUARD() {
3454 + migration_bitmap_sync_precopy(final);
3455 + }
3456 +
3457 + if (!final) {
3458 bql_unlock();
3459 }
3460 +}
3461 +
3462 +static void ram_state_pending(void *opaque, MigPendingData *pending,
3463 + bool exact, bool final)
3464 +{
3465 + RAMState **temp = opaque;
3466 + RAMState *rs = *temp;
3467 + uint64_t remaining_size;
3468
3469 + ram_state_pending_sync(exact, final);
3470 remaining_size = rs->migration_dirty_pages * TARGET_PAGE_SIZE;
3471
3472 if (migrate_postcopy_ram()) {
migration/savevm.c
+16 -4
@@ -1801,7 +1801,8 @@ int qemu_savevm_state_complete_precopy(MigrationState *s, Error **errp)
1801 return 0;
1802 }
1803
1804 -void qemu_savevm_query_pending(MigPendingData *pending, bool exact)
1804 +static void qemu_savevm_query_pending(MigPendingData *pending, bool exact,
1805 + bool final)
1806 {
1807 SaveStateEntry *se;
1808
@@ -1814,7 +1815,7 @@ void qemu_savevm_query_pending(MigPendingData *pending, bool exact)
1815 if (!qemu_savevm_state_active(se)) {
1816 continue;
1817 }
1817 - se->ops->save_query_pending(se->opaque, pending, exact);
1818 + se->ops->save_query_pending(se->opaque, pending, exact, final);
1819 }
1820
1821 pending->total_bytes = pending->precopy_bytes +
@@ -1826,13 +1827,24 @@ void qemu_savevm_query_pending(MigPendingData *pending, bool exact)
1827 * close to reality when this got invoked frequently while iterating.
1828 */
1829 mig_stats.dirty_bytes_total = pending->total_bytes;
1829 -
1830 - trace_qemu_savevm_query_pending(exact, pending->precopy_bytes,
1830 + trace_qemu_savevm_query_pending(exact, final, pending->precopy_bytes,
1831 pending->stopcopy_bytes,
1832 pending->postcopy_bytes,
1833 pending->total_bytes);
1834 }
1835
1836 +void qemu_savevm_query_pending_iter(MigPendingData *pending, bool exact)
1837 +{
1838 + qemu_savevm_query_pending(pending, exact, false);
1839 +}
1840 +
1841 +void qemu_savevm_query_pending_final(MigPendingData *pending)
1842 +{
1843 + g_assert(bql_locked());
1844 +
1845 + qemu_savevm_query_pending(pending, true, true);
1846 +}
1847 +
1848 void qemu_savevm_state_cleanup(void)
1849 {
1850 SaveStateEntry *se;
migration/savevm.h
+2 -1
@@ -45,7 +45,8 @@ int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy);
45 void qemu_savevm_state_cleanup(void);
46 void qemu_savevm_state_complete_postcopy(QEMUFile *f);
47 int qemu_savevm_state_complete_precopy(MigrationState *s, Error **errp);
48 -void qemu_savevm_query_pending(MigPendingData *pending, bool exact);
48 +void qemu_savevm_query_pending_iter(MigPendingData *pending, bool exact);
49 +void qemu_savevm_query_pending_final(MigPendingData *pending);
50 int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy);
51 bool qemu_savevm_state_postcopy_prepare(QEMUFile *f, Error **errp);
52 void qemu_savevm_state_end(QEMUFile *f);
migration/trace-events
+1 -1
@@ -7,7 +7,7 @@ qemu_loadvm_state_section_partend(uint32_t section_id) "%u"
7 qemu_loadvm_state_post_main(int ret) "%d"
8 qemu_loadvm_state_section_startfull(uint32_t section_id, const char *idstr, uint32_t instance_id, uint32_t version_id) "%u(%s) %u %u"
9 qemu_savevm_send_packaged(void) ""
10 -qemu_savevm_query_pending(bool exact, uint64_t precopy, uint64_t stopcopy, uint64_t postcopy, uint64_t total) "exact=%d, precopy=%"PRIu64", stopcopy=%"PRIu64", postcopy=%"PRIu64", total=%"PRIu64
10 +qemu_savevm_query_pending(bool exact, bool final, uint64_t precopy, uint64_t stopcopy, uint64_t postcopy, uint64_t total) "exact=%d, final=%d, precopy=%"PRIu64", stopcopy=%"PRIu64", postcopy=%"PRIu64", total=%"PRIu64
11 loadvm_state_switchover_ack_needed(unsigned int switchover_ack_pending_num) "Switchover ack pending num=%u"
12 loadvm_state_setup(void) ""
13 loadvm_state_cleanup(void) ""