Commit 1891d455da for qemu.org

commit 1891d455da8cd74aa05deb7c784cb8a7bde23418
Author: Aadeshveer Singh <aadeshveer07@gmail.com>
Date:   Sun Aug 16 23:16:24 2026 +0530

    migration: Use file_bmap for RAMBlock during incoming file load

    Replace the temporary bitmap with the existing file_bmap attribute of
    the RAMBlock. This acts as a preparatory change for the upcoming fast
    snapshot load feature.

    Reusing this bitmap allows the destination to track page types during
    a postcopy load, enabling faster, direct placement of zero pages.

    Since file_bmap is currently only utilized during the migration save
    phase, it can be safely repurposed during the load phase without
    introducing conflicts.

    Signed-off-by: Aadeshveer Singh <aadeshveer07@gmail.com>
    Reviewed-by: Peter Xu <peterx@redhat.com>
    Reviewed-by: Juraj Marcin <jmarcin@redhat.com>
    Signed-off-by: Peter Xu <peterx@redhat.com>
    Signed-off-by: Fabiano Rosas <farosas@suse.de>

diff --git a/migration/ram.c b/migration/ram.c
index b6eb842746..7fa4774246 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -252,6 +252,17 @@ int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque)
     return ret;
 }

+static void ramblock_file_bmap_init(void)
+{
+    RAMBlock *rb;
+
+    RAMBLOCK_FOREACH_NOT_IGNORED(rb) {
+        assert(!rb->file_bmap);
+        size_t size = rb->max_length >> qemu_target_page_bits();
+        rb->file_bmap = bitmap_new(size);
+    }
+}
+
 static void ramblock_recv_map_init(void)
 {
     RAMBlock *rb;
@@ -3755,6 +3766,9 @@ static int ram_load_setup(QEMUFile *f, void *opaque, Error **errp)
 {
     xbzrle_load_setup();
     ramblock_recv_map_init();
+    if (migrate_mapped_ram()) {
+        ramblock_file_bmap_init();
+    }

     return 0;
 }
@@ -3772,8 +3786,8 @@ static int ram_load_cleanup(void *opaque)
     xbzrle_load_cleanup();

     RAMBLOCK_FOREACH_NOT_IGNORED(rb) {
-        g_free(rb->receivedmap);
-        rb->receivedmap = NULL;
+        g_clear_pointer(&rb->receivedmap, g_free);
+        g_clear_pointer(&rb->file_bmap, g_free);
     }

     return 0;
@@ -4148,11 +4162,18 @@ err:
 static void parse_ramblock_mapped_ram(QEMUFile *f, RAMBlock *block,
                                       ram_addr_t length, Error **errp)
 {
-    g_autofree unsigned long *bitmap = NULL;
     MappedRamHeader header;
     size_t bitmap_size;
     long num_pages;

+    if (length > block->max_length) {
+        error_setg(errp,
+                   "mapped-ram header length %" PRIu64 " exceeds "
+                   "RAMBlock(\"%s\") max_length %" PRIu64,
+                   (uint64_t)length, block->idstr, (uint64_t)block->max_length);
+        return;
+    }
+
     if (!mapped_ram_read_header(f, &header, errp)) {
         return;
     }
@@ -4180,14 +4201,14 @@ static void parse_ramblock_mapped_ram(QEMUFile *f, RAMBlock *block,
     num_pages = length / header.page_size;
     bitmap_size = BITS_TO_LONGS(num_pages) * sizeof(unsigned long);

-    bitmap = g_malloc0(bitmap_size);
-    if (qemu_get_buffer_at(f, (uint8_t *)bitmap, bitmap_size,
+    if (qemu_get_buffer_at(f, (uint8_t *)block->file_bmap, bitmap_size,
                            header.bitmap_offset) != bitmap_size) {
         error_setg(errp, "Error reading dirty bitmap");
         return;
     }

-    if (!read_ramblock_mapped_ram(f, block, num_pages, bitmap, errp)) {
+    if (!read_ramblock_mapped_ram(f, block, num_pages, block->file_bmap,
+                                  errp)) {
         return;
     }