On 5/7/2026 11:24 AM, Cédric Le Goater wrote:
External email: Use caution opening links or attachments
Hello Avihai
On 5/5/26 10:14, Avihai Horon wrote:
When precopy initial_bytes reaches zero VFIO_MIG_FLAG_DEV_INIT_DATA_SENT
flag is sent to the destination to indicate that initial data has been
sent, so destination can indicate back to source when it finished
loading it.
To get a more accurate estimation of initial_bytes, re-query precopy
size before sending the flag. Extract the flag sending logic from
vfio_save_iterate() to a new helper for clarity.
I would prefer to separate the changes, so a patch for this new routine,
and then :
This may prevent premature sending of VFIO_MIG_FLAG_DEV_INIT_DATA_SENT
flag if, for example, the previously queried initial_bytes was lower
than actually is. Additionally, it prevents sending the flag if
vfio_query_precopy_size() failed.
Of course, will do.
Thanks.
Signed-off-by: Avihai Horon <[email protected]>
---
hw/vfio/migration.c | 37 ++++++++++++++++++++++++++++++++-----
hw/vfio/trace-events | 1 +
2 files changed, 33 insertions(+), 5 deletions(-)
diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c
index 2911583ee1..243624b5fe 100644
--- a/hw/vfio/migration.c
+++ b/hw/vfio/migration.c
@@ -456,6 +456,37 @@ static void
vfio_update_estimated_pending_data(VFIOMigration *migration,
data_size);
}
+/* Returns true if the init data flag was sent, false otherwise */
+static bool vfio_send_init_data_flag(QEMUFile *f, VFIOMigration
*migration)
+{
+ VFIODevice *vbasedev = migration->vbasedev;
+ int ret;
+
+ if (!migrate_switchover_ack()) {
+ return false;
+ }
+
+ if (migration->precopy_init_size || migration->initial_data_sent) {
+ return false;
+ }
+
+ /*
+ * precopy_init_size holds an estimation of the initial data
size, re-query
+ * precopy size to ensure it's really zero before sending init
data flag.
+ * Don't send the flag if query fails.
+ */
+ ret = vfio_query_precopy_size(migration);
+ if (ret || migration->precopy_init_size) {
+ return false;
+ }
+
+ qemu_put_be64(f, VFIO_MIG_FLAG_DEV_INIT_DATA_SENT);
+ migration->initial_data_sent = true;
+ trace_vfio_send_init_data_flag(vbasedev->name);
+
+ return true;
+}
+
static bool vfio_precopy_supported(VFIODevice *vbasedev)
{
VFIOMigration *migration = vbasedev->migration;
@@ -664,11 +695,7 @@ static int vfio_save_iterate(QEMUFile *f, void
*opaque)
vfio_update_estimated_pending_data(migration, data_size);
- if (migrate_switchover_ack() && !migration->precopy_init_size &&
- !migration->initial_data_sent) {
- qemu_put_be64(f, VFIO_MIG_FLAG_DEV_INIT_DATA_SENT);
- migration->initial_data_sent = true;
- } else {
+ if (!vfio_send_init_data_flag(f, migration)) {
qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE);
}
diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events
index ab27ff5ea2..e91858354c 100644
--- a/hw/vfio/trace-events
+++ b/hw/vfio/trace-events
@@ -176,6 +176,7 @@ vfio_save_iterate(const char *name, uint64_t
precopy_init_size, uint64_t precopy
vfio_save_iterate_start(const char *name) " (%s)"
vfio_save_setup(const char *name, uint64_t data_buffer_size) " (%s)
data buffer size %"PRIu64
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"
+vfio_send_init_data_flag(const char *name) " (%s)"
vfio_vmstate_change(const char *name, int running, const char
*reason, const char *dev_state) " (%s) running %d reason %s device
state %s"
vfio_vmstate_change_prepare(const char *name, int running, const
char *reason, const char *dev_state) " (%s) running %d reason %s
device state %s"