@samitouri / QOSamiQemu / commits / a94a867ee8

migration/treewide: Merge @state_pending_{exact|estimate} APIs

These two APIs are a slight duplication. For example, there're a few users that directly pass in the same function. It might also be error prone to provide two hooks, so that it's easier to happen one module report different things via the two hooks. In reality, they should always report the same thing, only about whether we should use a fast-path when the slow path might be too slow, as QEMU may query these information quite frequently during migration process. Merge it into one API, provide a bool showing if the query is an exact query or not. No functional change intended. Export qemu_savevm_query_pending(). We should use the new API here provided when there're new users to do the query. This will happen very soon. Cc: Halil Pasic <pasic@linux.ibm.com> Cc: Christian Borntraeger <borntraeger@linux.ibm.com> Cc: Eric Farman <farman@linux.ibm.com> Cc: Matthew Rosato <mjrosato@linux.ibm.com> Cc: Richard Henderson <richard.henderson@linaro.org> Cc: Ilya Leoshkevich <iii@linux.ibm.com> Cc: David Hildenbrand <david@kernel.org> Cc: Cornelia Huck <cohuck@redhat.com> Cc: Eric Blake <eblake@redhat.com> Cc: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> Cc: John Snow <jsnow@redhat.com> Reviewed-by: Jason J. Herne <jjherne@linux.ibm.com> Reviewed-by: Juraj Marcin <jmarcin@redhat.com> Reviewed-by: Avihai Horon <avihaih@nvidia.com> Acked-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> Link: https://lore.kernel.org/r/20260421202110.306051-6-peterx@redhat.com Signed-off-by: Peter Xu <peterx@redhat.com>

Peter Xu committed Apr 21, 2026 at 16:20 UTC a94a867ee86cedf14f9fd79a74318b667b21d4e6
10 files changed +86 -132
docs/devel/migration/main.rst
+2 -7
@@ -515,13 +515,8 @@ An iterative device must provide:
515 - A ``load_setup`` function that initialises the data structures on the
516 destination.
517
518 - - A ``state_pending_exact`` function that indicates how much more
519 - data we must save. The core migration code will use this to
520 - determine when to pause the CPUs and complete the migration.
521 -
522 - - A ``state_pending_estimate`` function that indicates how much more
523 - data we must save. When the estimated amount is smaller than the
524 - threshold, we call ``state_pending_exact``.
518 + - A ``save_query_pending`` function that indicates how much more
519 + data we must save.
520
521 - A ``save_live_iterate`` function should send a chunk of data until
522 the point that stream bandwidth limits tell it to stop. Each call
docs/devel/migration/vfio.rst
+2 -7
@@ -50,13 +50,8 @@ VFIO implements the device hooks for the iterative approach as follows:
50 * A ``load_setup`` function that sets the VFIO device on the destination in
51 _RESUMING state.
52
53 -* A ``state_pending_estimate`` function that reports an estimate of the
54 - remaining pre-copy data that the vendor driver has yet to save for the VFIO
55 - device.
56 -
57 -* A ``state_pending_exact`` function that reads pending_bytes from the vendor
58 - driver, which indicates the amount of data that the vendor driver has yet to
59 - save for the VFIO device.
53 +* A ``save_query_pending`` function that reports the remaining data that
54 + the vendor driver has yet to save for the VFIO device.
55
56 * An ``is_active_iterate`` function that indicates ``save_live_iterate`` is
57 active only when the VFIO device is in pre-copy states.
hw/s390x/s390-stattrib.c
+4 -5
@@ -187,15 +187,15 @@ static int cmma_save_setup(QEMUFile *f, void *opaque, Error **errp)
187 return 0;
188 }
189
190 -static void cmma_state_pending(void *opaque, uint64_t *must_precopy,
191 - uint64_t *can_postcopy)
190 +static void cmma_state_pending(void *opaque, MigPendingData *pending,
191 + bool exact)
192 {
193 S390StAttribState *sas = S390_STATTRIB(opaque);
194 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
195 long long res = sac->get_dirtycount(sas);
196
197 if (res >= 0) {
198 - *must_precopy += res;
198 + pending->precopy_bytes += res;
199 }
200 }
201
@@ -340,8 +340,7 @@ static SaveVMHandlers savevm_s390_stattrib_handlers = {
340 .save_setup = cmma_save_setup,
341 .save_live_iterate = cmma_save_iterate,
342 .save_complete = cmma_save_complete,
343 - .state_pending_exact = cmma_state_pending,
344 - .state_pending_estimate = cmma_state_pending,
343 + .save_query_pending = cmma_state_pending,
344 .save_cleanup = cmma_save_cleanup,
345 .load_state = cmma_load,
346 .is_active = cmma_active,
hw/vfio/migration.c
+22 -26
@@ -571,42 +571,39 @@ static void vfio_save_cleanup(void *opaque)
571 trace_vfio_save_cleanup(vbasedev->name);
572 }
573
574 -static void vfio_state_pending_estimate(void *opaque, uint64_t *must_precopy,
575 - uint64_t *can_postcopy)
574 +static void vfio_state_pending_sync(VFIODevice *vbasedev)
575 {
577 - VFIODevice *vbasedev = opaque;
576 VFIOMigration *migration = vbasedev->migration;
577
580 - if (!vfio_device_state_is_precopy(vbasedev)) {
581 - return;
582 - }
583 -
584 - *must_precopy +=
585 - migration->precopy_init_size + migration->precopy_dirty_size;
578 + vfio_query_stop_copy_size(vbasedev);
579
587 - trace_vfio_state_pending_estimate(vbasedev->name, *must_precopy,
588 - *can_postcopy,
589 - migration->precopy_init_size,
590 - migration->precopy_dirty_size);
580 + if (vfio_device_state_is_precopy(vbasedev)) {
581 + vfio_query_precopy_size(migration);
582 + }
583 }
584
593 -static void vfio_state_pending_exact(void *opaque, uint64_t *must_precopy,
594 - uint64_t *can_postcopy)
585 +static void vfio_state_pending(void *opaque, MigPendingData *pending,
586 + bool exact)
587 {
588 VFIODevice *vbasedev = opaque;
589 VFIOMigration *migration = vbasedev->migration;
590 + uint64_t remain;
591
599 - vfio_query_stop_copy_size(vbasedev);
600 - *must_precopy += migration->stopcopy_size;
601 -
602 - if (vfio_device_state_is_precopy(vbasedev)) {
603 - vfio_query_precopy_size(migration);
592 + if (exact) {
593 + vfio_state_pending_sync(vbasedev);
594 + remain = migration->stopcopy_size;
595 + } else {
596 + if (!vfio_device_state_is_precopy(vbasedev)) {
597 + return;
598 + }
599 + remain = migration->precopy_init_size + migration->precopy_dirty_size;
600 }
601
606 - trace_vfio_state_pending_exact(vbasedev->name, *must_precopy, *can_postcopy,
607 - migration->stopcopy_size,
608 - migration->precopy_init_size,
609 - migration->precopy_dirty_size);
602 + pending->precopy_bytes += remain;
603 +
604 + trace_vfio_state_pending(vbasedev->name, migration->stopcopy_size,
605 + migration->precopy_init_size,
606 + migration->precopy_dirty_size, exact);
607 }
608
609 static bool vfio_is_active_iterate(void *opaque)
@@ -851,8 +848,7 @@ static const SaveVMHandlers savevm_vfio_handlers = {
848 .save_prepare = vfio_save_prepare,
849 .save_setup = vfio_save_setup,
850 .save_cleanup = vfio_save_cleanup,
854 - .state_pending_estimate = vfio_state_pending_estimate,
855 - .state_pending_exact = vfio_state_pending_exact,
851 + .save_query_pending = vfio_state_pending,
852 .is_active_iterate = vfio_is_active_iterate,
853 .save_live_iterate = vfio_save_iterate,
854 .save_complete = vfio_save_complete_precopy,
hw/vfio/trace-events
+1 -2
@@ -173,8 +173,7 @@ vfio_save_device_config_state(const char *name) " (%s)"
173 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
174 vfio_save_iterate_start(const char *name) " (%s)"
175 vfio_save_setup(const char *name, uint64_t data_buffer_size) " (%s) data buffer size %"PRIu64
176 -vfio_state_pending_estimate(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy %"PRIu64" postcopy %"PRIu64" precopy initial size %"PRIu64" precopy dirty size %"PRIu64
177 -vfio_state_pending_exact(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t stopcopy_size, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy %"PRIu64" postcopy %"PRIu64" stopcopy size %"PRIu64" precopy initial size %"PRIu64" precopy dirty size %"PRIu64
176 +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"
177 vfio_vmstate_change(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s"
178 vfio_vmstate_change_prepare(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s"
179
include/migration/register.h
+18 -34
@@ -16,6 +16,13 @@
16
17 #include "hw/core/vmstate-if.h"
18
19 +typedef struct MigPendingData {
20 + /* Amount of pending bytes can be transferred in precopy or stopcopy */
21 + uint64_t precopy_bytes;
22 + /* Amount of pending bytes can be transferred in postcopy */
23 + uint64_t postcopy_bytes;
24 +} MigPendingData;
25 +
26 /**
27 * struct SaveVMHandlers: handler structure to finely control
28 * migration of complex subsystems and devices, such as RAM, block and
@@ -197,46 +204,23 @@ typedef struct SaveVMHandlers {
204 bool (*save_postcopy_prepare)(QEMUFile *f, void *opaque, Error **errp);
205
206 /**
200 - * @state_pending_estimate
201 - *
202 - * This estimates the remaining data to transfer
207 + * @save_query_pending
208 *
204 - * Sum of @can_postcopy and @must_postcopy is the whole amount of
205 - * pending data.
206 - *
207 - * @opaque: data pointer passed to register_savevm_live()
208 - * @must_precopy: amount of data that must be migrated in precopy
209 - * or in stopped state, i.e. that must be migrated
210 - * before target start.
211 - * @can_postcopy: amount of data that can be migrated in postcopy
212 - * or in stopped state, i.e. after target start.
213 - * Some can also be migrated during precopy (RAM).
214 - * Some must be migrated after source stops
215 - * (block-dirty-bitmap)
216 - */
217 - void (*state_pending_estimate)(void *opaque, uint64_t *must_precopy,
218 - uint64_t *can_postcopy);
219 -
220 - /**
221 - * @state_pending_exact
209 + * This estimates the remaining data to transfer on the source side.
210 *
223 - * This calculates the exact remaining data to transfer
211 + * When @exact is true, a module must report accurate results. When
212 + * @exact is false, a module may report estimates.
213 *
225 - * Sum of @can_postcopy and @must_postcopy is the whole amount of
226 - * pending data.
214 + * It's highly recommended that modules implement a faster version of
215 + * the query path (for example, by proper caching on the counters) if
216 + * an accurate query will be time-consuming.
217 *
218 * @opaque: data pointer passed to register_savevm_live()
229 - * @must_precopy: amount of data that must be migrated in precopy
230 - * or in stopped state, i.e. that must be migrated
231 - * before target start.
232 - * @can_postcopy: amount of data that can be migrated in postcopy
233 - * or in stopped state, i.e. after target start.
234 - * Some can also be migrated during precopy (RAM).
235 - * Some must be migrated after source stops
236 - * (block-dirty-bitmap)
219 + * @pending: pointer to a MigPendingData struct
220 + * @exact: set to true for an accurate (slow) query
221 */
238 - void (*state_pending_exact)(void *opaque, uint64_t *must_precopy,
239 - uint64_t *can_postcopy);
222 + void (*save_query_pending)(void *opaque, MigPendingData *pending,
223 + bool exact);
224
225 /**
226 * @load_state
migration/block-dirty-bitmap.c
+4 -6
@@ -766,9 +766,8 @@ static int dirty_bitmap_save_complete(QEMUFile *f, void *opaque)
766 return 0;
767 }
768
769 -static void dirty_bitmap_state_pending(void *opaque,
770 - uint64_t *must_precopy,
771 - uint64_t *can_postcopy)
769 +static void dirty_bitmap_state_pending(void *opaque, MigPendingData *data,
770 + bool exact)
771 {
772 DBMSaveState *s = &((DBMState *)opaque)->save;
773 SaveBitmapState *dbms;
@@ -788,7 +787,7 @@ static void dirty_bitmap_state_pending(void *opaque,
787
788 trace_dirty_bitmap_state_pending(pending);
789
791 - *can_postcopy += pending;
790 + data->postcopy_bytes += pending;
791 }
792
793 /* First occurrence of this bitmap. It should be created if doesn't exist */
@@ -1250,8 +1249,7 @@ static SaveVMHandlers savevm_dirty_bitmap_handlers = {
1249 .save_setup = dirty_bitmap_save_setup,
1250 .save_complete = dirty_bitmap_save_complete,
1251 .has_postcopy = dirty_bitmap_has_postcopy,
1253 - .state_pending_exact = dirty_bitmap_state_pending,
1254 - .state_pending_estimate = dirty_bitmap_state_pending,
1252 + .save_query_pending = dirty_bitmap_state_pending,
1253 .save_live_iterate = dirty_bitmap_save_iterate,
1254 .is_active_iterate = dirty_bitmap_is_active_iterate,
1255 .load_state = dirty_bitmap_load,
migration/ram.c
+10 -23
@@ -3449,30 +3449,18 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
3449 return qemu_fflush(f);
3450 }
3451
3452 -static void ram_state_pending_estimate(void *opaque, uint64_t *must_precopy,
3453 - uint64_t *can_postcopy)
3454 -{
3455 - RAMState **temp = opaque;
3456 - RAMState *rs = *temp;
3457 -
3458 - uint64_t remaining_size = rs->migration_dirty_pages * TARGET_PAGE_SIZE;
3459 -
3460 - if (migrate_postcopy_ram()) {
3461 - /* We can do postcopy, and all the data is postcopiable */
3462 - *can_postcopy += remaining_size;
3463 - } else {
3464 - *must_precopy += remaining_size;
3465 - }
3466 -}
3467 -
3468 -static void ram_state_pending_exact(void *opaque, uint64_t *must_precopy,
3469 - uint64_t *can_postcopy)
3452 +static void ram_state_pending(void *opaque, MigPendingData *pending,
3453 + bool exact)
3454 {
3455 RAMState **temp = opaque;
3456 RAMState *rs = *temp;
3457 uint64_t remaining_size;
3458
3475 - if (!migration_in_postcopy()) {
3459 + /*
3460 + * Sync is not needed either with: (1) a fast query, or (2) after
3461 + * postcopy has started (no new dirty will generate anymore).
3462 + */
3463 + if (exact && !migration_in_postcopy()) {
3464 bql_lock();
3465 WITH_RCU_READ_LOCK_GUARD() {
3466 migration_bitmap_sync_precopy(false);
@@ -3484,9 +3472,9 @@ static void ram_state_pending_exact(void *opaque, uint64_t *must_precopy,
3472
3473 if (migrate_postcopy_ram()) {
3474 /* We can do postcopy, and all the data is postcopiable */
3487 - *can_postcopy += remaining_size;
3475 + pending->postcopy_bytes += remaining_size;
3476 } else {
3489 - *must_precopy += remaining_size;
3477 + pending->precopy_bytes += remaining_size;
3478 }
3479 }
3480
@@ -4709,8 +4697,7 @@ static SaveVMHandlers savevm_ram_handlers = {
4697 .save_live_iterate = ram_save_iterate,
4698 .save_complete = ram_save_complete,
4699 .has_postcopy = ram_has_postcopy,
4712 - .state_pending_exact = ram_state_pending_exact,
4713 - .state_pending_estimate = ram_state_pending_estimate,
4700 + .save_query_pending = ram_state_pending,
4701 .load_state = ram_load,
4702 .save_cleanup = ram_save_cleanup,
4703 .load_setup = ram_load_setup,
migration/savevm.c
+20 -22
@@ -1796,46 +1796,44 @@ int qemu_savevm_state_complete_precopy(MigrationState *s)
1796 return qemu_fflush(f);
1797 }
1798
1799 -/* Give an estimate of the amount left to be transferred,
1800 - * the result is split into the amount for units that can and
1801 - * for units that can't do postcopy.
1802 - */
1803 -void qemu_savevm_state_pending_estimate(uint64_t *must_precopy,
1804 - uint64_t *can_postcopy)
1799 +void qemu_savevm_query_pending(MigPendingData *pending, bool exact)
1800 {
1801 SaveStateEntry *se;
1802
1808 - *must_precopy = 0;
1809 - *can_postcopy = 0;
1803 + pending->precopy_bytes = 0;
1804 + pending->postcopy_bytes = 0;
1805
1806 QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1812 - if (!se->ops || !se->ops->state_pending_estimate) {
1807 + if (!se->ops || !se->ops->save_query_pending) {
1808 continue;
1809 }
1810 if (!qemu_savevm_state_active(se)) {
1811 continue;
1812 }
1818 - se->ops->state_pending_estimate(se->opaque, must_precopy, can_postcopy);
1813 + se->ops->save_query_pending(se->opaque, pending, exact);
1814 }
1815 }
1816
1817 +void qemu_savevm_state_pending_estimate(uint64_t *must_precopy,
1818 + uint64_t *can_postcopy)
1819 +{
1820 + MigPendingData pending;
1821 +
1822 + qemu_savevm_query_pending(&pending, false);
1823 +
1824 + *must_precopy = pending.precopy_bytes;
1825 + *can_postcopy = pending.postcopy_bytes;
1826 +}
1827 +
1828 void qemu_savevm_state_pending_exact(uint64_t *must_precopy,
1829 uint64_t *can_postcopy)
1830 {
1825 - SaveStateEntry *se;
1831 + MigPendingData pending;
1832
1827 - *must_precopy = 0;
1828 - *can_postcopy = 0;
1833 + qemu_savevm_query_pending(&pending, true);
1834
1830 - QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1831 - if (!se->ops || !se->ops->state_pending_exact) {
1832 - continue;
1833 - }
1834 - if (!qemu_savevm_state_active(se)) {
1835 - continue;
1836 - }
1837 - se->ops->state_pending_exact(se->opaque, must_precopy, can_postcopy);
1838 - }
1835 + *must_precopy = pending.precopy_bytes;
1836 + *can_postcopy = pending.postcopy_bytes;
1837 }
1838
1839 void qemu_savevm_state_cleanup(void)
migration/savevm.h
+3
@@ -14,6 +14,8 @@
14 #ifndef MIGRATION_SAVEVM_H
15 #define MIGRATION_SAVEVM_H
16
17 +#include "migration/register.h"
18 +
19 #define QEMU_VM_FILE_MAGIC 0x5145564d
20 #define QEMU_VM_FILE_VERSION_COMPAT 0x00000002
21 #define QEMU_VM_FILE_VERSION 0x00000003
@@ -43,6 +45,7 @@ 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);
48 +void qemu_savevm_query_pending(MigPendingData *pending, bool exact);
49 void qemu_savevm_state_pending_exact(uint64_t *must_precopy,
50 uint64_t *can_postcopy);
51 void qemu_savevm_state_pending_estimate(uint64_t *must_precopy,