aboutsummaryrefslogtreecommitdiff
path: root/migration
diff options
context:
space:
mode:
Diffstat (limited to 'migration')
-rw-r--r--migration/ram.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/migration/ram.c b/migration/ram.c
index ae2601bf3b..e8c06f207c 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -858,6 +858,60 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs,
return ret;
}
+static void dirty_bitmap_clear_section(MemoryRegionSection *section,
+ void *opaque)
+{
+ const hwaddr offset = section->offset_within_region;
+ const hwaddr size = int128_get64(section->size);
+ const unsigned long start = offset >> TARGET_PAGE_BITS;
+ const unsigned long npages = size >> TARGET_PAGE_BITS;
+ RAMBlock *rb = section->mr->ram_block;
+ uint64_t *cleared_bits = opaque;
+
+ /*
+ * We don't grab ram_state->bitmap_mutex because we expect to run
+ * only when starting migration or during postcopy recovery where
+ * we don't have concurrent access.
+ */
+ if (!migration_in_postcopy() && !migrate_background_snapshot()) {
+ migration_clear_memory_region_dirty_bitmap_range(rb, start, npages);
+ }
+ *cleared_bits += bitmap_count_one_with_offset(rb->bmap, start, npages);
+ bitmap_clear(rb->bmap, start, npages);
+}
+
+/*
+ * Exclude all dirty pages from migration that fall into a discarded range as
+ * managed by a RamDiscardManager responsible for the mapped memory region of
+ * the RAMBlock. Clear the corresponding bits in the dirty bitmaps.
+ *
+ * Discarded pages ("logically unplugged") have undefined content and must
+ * not get migrated, because even reading these pages for migration might
+ * result in undesired behavior.
+ *
+ * Returns the number of cleared bits in the RAMBlock dirty bitmap.
+ *
+ * Note: The result is only stable while migrating (precopy/postcopy).
+ */
+static uint64_t ramblock_dirty_bitmap_clear_discarded_pages(RAMBlock *rb)
+{
+ uint64_t cleared_bits = 0;
+
+ if (rb->mr && rb->bmap && memory_region_has_ram_discard_manager(rb->mr)) {
+ RamDiscardManager *rdm = memory_region_get_ram_discard_manager(rb->mr);
+ MemoryRegionSection section = {
+ .mr = rb->mr,
+ .offset_within_region = 0,
+ .size = int128_make64(qemu_ram_get_used_length(rb)),
+ };
+
+ ram_discard_manager_replay_discarded(rdm, &section,
+ dirty_bitmap_clear_section,
+ &cleared_bits);
+ }
+ return cleared_bits;
+}
+
/* Called with RCU critical section */
static void ramblock_sync_dirty_bitmap(RAMState *rs, RAMBlock *rb)
{
@@ -2675,6 +2729,19 @@ static void ram_list_init_bitmaps(void)
}
}
+static void migration_bitmap_clear_discarded_pages(RAMState *rs)
+{
+ unsigned long pages;
+ RAMBlock *rb;
+
+ RCU_READ_LOCK_GUARD();
+
+ RAMBLOCK_FOREACH_NOT_IGNORED(rb) {
+ pages = ramblock_dirty_bitmap_clear_discarded_pages(rb);
+ rs->migration_dirty_pages -= pages;
+ }
+}
+
static void ram_init_bitmaps(RAMState *rs)
{
/* For memory_global_dirty_log_start below. */
@@ -2691,6 +2758,12 @@ static void ram_init_bitmaps(RAMState *rs)
}
qemu_mutex_unlock_ramlist();
qemu_mutex_unlock_iothread();
+
+ /*
+ * After an eventual first bitmap sync, fixup the initial bitmap
+ * containing all 1s to exclude any discarded pages from migration.
+ */
+ migration_bitmap_clear_discarded_pages(rs);
}
static int ram_init_all(RAMState **rsp)
@@ -4119,6 +4192,10 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block)
*/
bitmap_complement(block->bmap, block->bmap, nbits);
+ /* Clear dirty bits of discarded ranges that we don't want to migrate. */
+ ramblock_dirty_bitmap_clear_discarded_pages(block);
+
+ /* We'll recalculate migration_dirty_pages in ram_state_resume_prepare(). */
trace_ram_dirty_bitmap_reload_complete(block->idstr);
/*