On Sun, Aug 16, 2026 at 11:16:20PM +0530, Aadeshveer Singh wrote: > This series implements a "fast snapshot load" mechanism to > significantly reduce the perceived resume time of a VM from a snapshot > file.
This series breaks Windows builds... we'll need three fixups into three patches to fix it. Attached at the end. For Aadeshveer: in the future you can check Windows build of your own patches locally by running this: $ make docker-test-build@fedora-win64-cross I do hit Rust build failures nowadays with Windows, though, so you may need this if you have enabled rust builds instead (I also normally use J=N for concurrency): $ J=8 EXTRA_CONFIGURE_OPTS=--disable-rust make docker-test-build@fedora-win64-cross For Fabiano: if you want, you can also directly pick up the relevant patches I queued in my -next branch, or squash the fixups attached, or pick your own fix. I'll leave that to you to decide. https://gitlab.com/peterx/qemu/-/tree/next Thanks, ===8<=== >From 572b0f8b611e430e5ed8651d99851975878624c7 Mon Sep 17 00:00:00 2001 From: Peter Xu <[email protected]> Date: Tue, 18 Aug 2026 16:38:08 -0400 Subject: [PATCH 1/3] fixup! migration: Propagate error in postcopy setup functions Signed-off-by: Peter Xu <[email protected]> --- migration/postcopy-ram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 81d06917fe..3c85fa1b19 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -1906,7 +1906,7 @@ int postcopy_request_shared_page(struct PostCopyFD *pcfd, RAMBlock *rb, g_assert_not_reached(); } -int postcopy_ram_incoming_setup(MigrationIncomingState *mis) +int postcopy_ram_incoming_setup(MigrationIncomingState *mis, Error **errp) { g_assert_not_reached(); } -- 2.54.0 >From 4273cc6ed223de1781513af9a62c1672c3f5591b Mon Sep 17 00:00:00 2001 From: Peter Xu <[email protected]> Date: Wed, 19 Aug 2026 10:30:35 -0400 Subject: [PATCH 2/3] fixup! migration: Extract blocktime marking helper Signed-off-by: Peter Xu <[email protected]> --- migration/postcopy-ram.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 3c85fa1b19..fdc65c3545 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -1934,6 +1934,14 @@ void mark_postcopy_blocktime_begin(uintptr_t addr, uint32_t ptid, RAMBlock *rb) { } + +bool try_mark_postcopy_blocktime_begin(MigrationIncomingState *mis, + RAMBlock *rb, ram_addr_t start, + uint64_t haddr, uint32_t tid) +{ + g_assert_not_reached(); + return false; +} #endif /* ------------------------------------------------------------------------- */ -- 2.54.0 >From d2d397de73fe39b424b2871fe4ba0df7937cc680 Mon Sep 17 00:00:00 2001 From: Peter Xu <[email protected]> Date: Tue, 18 Aug 2026 16:43:29 -0400 Subject: [PATCH 3/3] fixup! migration: add eager load thread and setup for fast snapshot load Signed-off-by: Peter Xu <[email protected]> --- migration/postcopy-ram.c | 135 ++++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 64 deletions(-) diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index fdc65c3545..885ab58fca 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -39,6 +39,8 @@ #include "qemu/mmap-alloc.h" #include "options.h" +static void postcopy_incoming_complete_bh(void *opaque); + /* Arbitrary limit on size of each discard command, * keeps them around ~200 bytes */ @@ -1872,6 +1874,70 @@ int postcopy_place_page_zero(MigrationIncomingState *mis, void *host, } } +/* + * Called by postcopy_ram_eager_load_thread over all blocks to load in all the + * pending pages of given ram block + */ +static int ram_block_load_eager(RAMBlock *rb, void *opaque) +{ + MigrationIncomingState *mis = migration_incoming_get_current(); + MigrationState *s = migrate_get_current(); + Error *errp = NULL; + void *host = qemu_ram_get_host_addr(rb); + void *target; + + for (ram_addr_t page_loc = 0; page_loc < rb->used_length; + page_loc += qemu_ram_pagesize(rb)) { + target = (uint8_t *)host + page_loc; + if (!postcopy_mapped_ram_load_page(mis, rb, page_loc, (uint64_t)target, + RAM_CHANNEL_PRECOPY, &errp)) { + migrate_error_propagate(s, errp); + return -1; + } + } + return 0; +} + +/* + * Used by fast snapshot load to eagerly load in all pages of RAM and schedule + * cleanup after entire RAM is loaded + */ +static void *postcopy_ram_eager_load_thread(void *opaque) +{ + MigrationIncomingState *mis = opaque; + MigrationStatus next_state; + + trace_postcopy_ram_eager_load_thread_entry(); + rcu_register_thread(); + qemu_event_set(&mis->thread_sync_event); + + if (foreach_not_ignored_block(ram_block_load_eager, NULL)) { + next_state = MIGRATION_STATUS_FAILED; + } else { + next_state = MIGRATION_STATUS_COMPLETED; + } + migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE, + next_state); + + postcopy_state_set(POSTCOPY_INCOMING_END); + migration_bh_schedule(postcopy_incoming_complete_bh, mis); + + rcu_unregister_thread(); + trace_postcopy_ram_eager_load_thread_exit(); + return NULL; +} + +/* + * Create thread for eager loading in fast snapshot load case + */ +void postcopy_ram_eager_load_setup(MigrationIncomingState *mis) +{ + postcopy_thread_create( + mis, &mis->eager_load_thread, MIGRATION_THREAD_DST_SNAPSHOT_LOAD, + postcopy_ram_eager_load_thread, QEMU_THREAD_JOINABLE); + mis->have_eager_load_thread = true; +} + #else /* No target OS support, stubs just fail */ void fill_destination_postcopy_migration_info(MigrationInfo *info) @@ -1942,6 +2008,11 @@ bool try_mark_postcopy_blocktime_begin(MigrationIncomingState *mis, g_assert_not_reached(); return false; } + +void postcopy_ram_eager_load_setup(MigrationIncomingState *mis) +{ + g_assert_not_reached(); +} #endif /* ------------------------------------------------------------------------- */ @@ -2426,67 +2497,3 @@ int postcopy_incoming_cleanup(MigrationIncomingState *mis) return rc; } - -/* - * Called by postcopy_ram_eager_load_thread over all blocks to load in all the - * pending pages of given ram block - */ -static int ram_block_load_eager(RAMBlock *rb, void *opaque) -{ - MigrationIncomingState *mis = migration_incoming_get_current(); - MigrationState *s = migrate_get_current(); - Error *errp = NULL; - void *host = qemu_ram_get_host_addr(rb); - void *target; - - for (ram_addr_t page_loc = 0; page_loc < rb->used_length; - page_loc += qemu_ram_pagesize(rb)) { - target = (uint8_t *)host + page_loc; - if (!postcopy_mapped_ram_load_page(mis, rb, page_loc, (uint64_t)target, - RAM_CHANNEL_PRECOPY, &errp)) { - migrate_error_propagate(s, errp); - return -1; - } - } - return 0; -} - -/* - * Used by fast snapshot load to eagerly load in all pages of RAM and schedule - * cleanup after entire RAM is loaded - */ -static void *postcopy_ram_eager_load_thread(void *opaque) -{ - MigrationIncomingState *mis = opaque; - MigrationStatus next_state; - - trace_postcopy_ram_eager_load_thread_entry(); - rcu_register_thread(); - qemu_event_set(&mis->thread_sync_event); - - if (foreach_not_ignored_block(ram_block_load_eager, NULL)) { - next_state = MIGRATION_STATUS_FAILED; - } else { - next_state = MIGRATION_STATUS_COMPLETED; - } - migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE, - next_state); - - postcopy_state_set(POSTCOPY_INCOMING_END); - migration_bh_schedule(postcopy_incoming_complete_bh, mis); - - rcu_unregister_thread(); - trace_postcopy_ram_eager_load_thread_exit(); - return NULL; -} - -/* - * Create thread for eager loading in fast snapshot load case - */ -void postcopy_ram_eager_load_setup(MigrationIncomingState *mis) -{ - postcopy_thread_create( - mis, &mis->eager_load_thread, MIGRATION_THREAD_DST_SNAPSHOT_LOAD, - postcopy_ram_eager_load_thread, QEMU_THREAD_JOINABLE); - mis->have_eager_load_thread = true; -} -- 2.54.0 -- Peter Xu
