+static unsigned long *migration_bitmap;
+static uint64_t migration_dirty_pages;
+
+static inline bool migration_bitmap_test_and_reset_dirty(MemoryRegion *mr,
+ ram_addr_t offset)
+{
+ bool ret;
+ int nr = (mr->ram_addr + offset) >> TARGET_PAGE_BITS;
+
+ ret = test_and_clear_bit(nr, migration_bitmap);
+
+ if (ret) {
+ migration_dirty_pages--;
+ }
+ return ret;
+}
+
+static inline bool migration_bitmap_set_dirty(MemoryRegion *mr,
+ ram_addr_t offset)
+{
+ bool ret;
+ int nr = (mr->ram_addr + offset) >> TARGET_PAGE_BITS;
+
+ ret = test_and_set_bit(nr, migration_bitmap);
+
+ if (!ret) {
+ migration_dirty_pages++;
+ }
+ return ret;
+}
+
+static void migration_bitmap_sync(void)
+{
+ RAMBlock *block;
+ ram_addr_t addr;
+ uint64_t num_dirty_pages_init = migration_dirty_pages;
+ MigrationState *s = migrate_get_current();
+ static int64_t start_time;
+ static int64_t num_dirty_pages_period;
+ int64_t end_time;
+
+ if (!start_time) {
+ start_time = qemu_get_clock_ms(rt_clock);
+ }
+
+ trace_migration_bitmap_sync_start();
+ memory_global_sync_dirty_bitmap(get_system_memory());
+
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
+ if (memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_MIGRATION)) {
+ migration_bitmap_set_dirty(block->mr, addr);
+ }
+ }
+ memory_region_reset_dirty(block->mr, 0, block->length,
+ DIRTY_MEMORY_MIGRATION);
+ }
+ trace_migration_bitmap_sync_end(migration_dirty_pages
+ - num_dirty_pages_init);
+ num_dirty_pages_period += migration_dirty_pages - num_dirty_pages_init;
+ end_time = qemu_get_clock_ms(rt_clock);
+
+ /* more than 1 second = 1000 millisecons */
+ if (end_time > start_time + 1000) {
+ s->dirty_pages_rate = num_dirty_pages_period * 1000
+ / (end_time - start_time);
+ start_time = end_time;
+ num_dirty_pages_period = 0;
+ }
+}
+