Add pending_bmap field per RAMBlock which is a Bitmap to store internal state of which pages have been read by some thread to ensure coordination between fault thread and eager load thread.
Modify parse_ramblock_mapped_ram(), to not load the actual RAMBlocks data in postcopy case as that will be loaded by fault thread and eager thread after the VM starts running. Change ram_load() to use new function ram_should_load_postcopy_pages() to decide how to load/read RAM. Signed-off-by: Aadeshveer Singh <[email protected]> --- include/system/ramblock.h | 6 ++++ migration/ram.c | 59 +++++++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/include/system/ramblock.h b/include/system/ramblock.h index 4435f8d55f..83187bf44c 100644 --- a/include/system/ramblock.h +++ b/include/system/ramblock.h @@ -60,6 +60,12 @@ struct RAMBlock { /* Bitmap of already received pages. Only used on destination side. */ unsigned long *receivedmap; + /* + * Bitmap for pages that are yet to be read from disk. It is required for + * fault thread and eager thread to keep note of which pages are currently + * being read. Used by fast snapshot load. + */ + unsigned long *pending_bmap; /* * bitmap to track already cleared dirty bitmap. When the bit is diff --git a/migration/ram.c b/migration/ram.c index 4728f14d73..ffd60b2ac8 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -263,6 +263,18 @@ static void ramblock_file_bmap_init(void) } } +static void ramblock_pending_bmap_init(void) +{ + RAMBlock *rb; + + RAMBLOCK_FOREACH_NOT_IGNORED(rb) { + assert(!rb->pending_bmap); + size_t size = rb->max_length >> qemu_target_page_bits(); + rb->pending_bmap = bitmap_new(size); + bitmap_set(rb->pending_bmap, 0, size); + } +} + static void ramblock_recv_map_init(void) { RAMBlock *rb; @@ -3762,6 +3774,10 @@ static int ram_load_setup(QEMUFile *f, void *opaque, Error **errp) ramblock_recv_map_init(); if (migrate_mapped_ram()) { ramblock_file_bmap_init(); + if (migrate_postcopy_ram()) { + /* fast snapshot load */ + ramblock_pending_bmap_init(); + } } return 0; @@ -3782,6 +3798,7 @@ static int ram_load_cleanup(void *opaque) RAMBLOCK_FOREACH_NOT_IGNORED(rb) { g_clear_pointer(&rb->receivedmap, g_free); g_clear_pointer(&rb->file_bmap, g_free); + g_clear_pointer(&rb->pending_bmap, g_free); } return 0; @@ -4201,9 +4218,12 @@ static void parse_ramblock_mapped_ram(QEMUFile *f, RAMBlock *block, return; } - if (!read_ramblock_mapped_ram(f, block, num_pages, block->file_bmap, - errp)) { - return; + if (!migrate_postcopy_ram()) { + /* Do not load RAM during setup for fast snapshot load */ + if (!read_ramblock_mapped_ram(f, block, num_pages, block->file_bmap, + errp)) { + return; + } } /* Skip pages array */ @@ -4475,15 +4495,42 @@ static int ram_load_precopy(QEMUFile *f) return ret; } +static bool ram_should_load_postcopy_pages(void) +{ + /* This is pure precopy, we don't need to load pages in postcopy way */ + if (!postcopy_is_running()) { + return false; + } + + /* + * This is postcopy, but when with mapped-ram, pages are not loaded in the + * migration stream here, but done separately in a thread eagerly reading + * pages from the snapshot. Here, we only need to read the ram headers, + * reusing the precopy code. + * TODO: when we have separate function to parse RAM headers we should + * switch to that. + */ + if (migrate_mapped_ram()) { + return false; + } + + /* + * Genuine network postcopy, we will load pages in this current stream and + * they need to be done in postcopy way. + */ + return true; +} + static int ram_load(QEMUFile *f, void *opaque, int version_id) { int ret = 0; static uint64_t seq_iter; /* * If system is running in postcopy mode, page inserts to host memory must - * be atomic + * be atomic. However, fast snapshot load uses the mapped ram precopy like + * path to read block headers and populating bitmaps. */ - bool postcopy_running = postcopy_is_running(); + bool load_postcopy_pages = ram_should_load_postcopy_pages(); seq_iter++; @@ -4499,7 +4546,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) */ trace_ram_load_start(); WITH_RCU_READ_LOCK_GUARD() { - if (postcopy_running) { + if (load_postcopy_pages) { /* * Note! Here RAM_CHANNEL_PRECOPY is the precopy channel of * postcopy migration, we have another RAM_CHANNEL_POSTCOPY to -- 2.54.0
