mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-12-11 16:00:50 -07:00
memory: add support getting and using a dirty bitmap copy.
This patch adds support for getting and using a local copy of the dirty bitmap. memory_region_snapshot_and_clear_dirty() will create a snapshot of the dirty bitmap for the specified range, clear the dirty bitmap and return the copy. The returned bitmap can be a bit larger than requested, the range is expanded so the code can copy unsigned longs from the bitmap and avoid atomic bit update operations. memory_region_snapshot_get_dirty() will return the dirty status of pages, pretty much like memory_region_get_dirty(), but using the copy returned by memory_region_copy_and_clear_dirty(). Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Message-id: 20170421091632.30900-3-kraxel@redhat.com Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
d6eb141392
commit
8deaf12ca1
5 changed files with 147 additions and 0 deletions
75
exec.c
75
exec.c
|
|
@ -223,6 +223,12 @@ struct CPUAddressSpace {
|
|||
MemoryListener tcg_as_listener;
|
||||
};
|
||||
|
||||
struct DirtyBitmapSnapshot {
|
||||
ram_addr_t start;
|
||||
ram_addr_t end;
|
||||
unsigned long dirty[];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
|
@ -1061,6 +1067,75 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
|
|||
return dirty;
|
||||
}
|
||||
|
||||
DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
|
||||
(ram_addr_t start, ram_addr_t length, unsigned client)
|
||||
{
|
||||
DirtyMemoryBlocks *blocks;
|
||||
unsigned long align = 1UL << (TARGET_PAGE_BITS + BITS_PER_LEVEL);
|
||||
ram_addr_t first = QEMU_ALIGN_DOWN(start, align);
|
||||
ram_addr_t last = QEMU_ALIGN_UP(start + length, align);
|
||||
DirtyBitmapSnapshot *snap;
|
||||
unsigned long page, end, dest;
|
||||
|
||||
snap = g_malloc0(sizeof(*snap) +
|
||||
((last - first) >> (TARGET_PAGE_BITS + 3)));
|
||||
snap->start = first;
|
||||
snap->end = last;
|
||||
|
||||
page = first >> TARGET_PAGE_BITS;
|
||||
end = last >> TARGET_PAGE_BITS;
|
||||
dest = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
blocks = atomic_rcu_read(&ram_list.dirty_memory[client]);
|
||||
|
||||
while (page < end) {
|
||||
unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE;
|
||||
unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE;
|
||||
unsigned long num = MIN(end - page, DIRTY_MEMORY_BLOCK_SIZE - offset);
|
||||
|
||||
assert(QEMU_IS_ALIGNED(offset, (1 << BITS_PER_LEVEL)));
|
||||
assert(QEMU_IS_ALIGNED(num, (1 << BITS_PER_LEVEL)));
|
||||
offset >>= BITS_PER_LEVEL;
|
||||
|
||||
bitmap_copy_and_clear_atomic(snap->dirty + dest,
|
||||
blocks->blocks[idx] + offset,
|
||||
num);
|
||||
page += num;
|
||||
dest += num >> BITS_PER_LEVEL;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (tcg_enabled()) {
|
||||
tlb_reset_dirty_range_all(start, length);
|
||||
}
|
||||
|
||||
return snap;
|
||||
}
|
||||
|
||||
bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
|
||||
ram_addr_t start,
|
||||
ram_addr_t length)
|
||||
{
|
||||
unsigned long page, end;
|
||||
|
||||
assert(start >= snap->start);
|
||||
assert(start + length <= snap->end);
|
||||
|
||||
end = TARGET_PAGE_ALIGN(start + length - snap->start) >> TARGET_PAGE_BITS;
|
||||
page = (start - snap->start) >> TARGET_PAGE_BITS;
|
||||
|
||||
while (page < end) {
|
||||
if (test_bit(page, snap->dirty)) {
|
||||
return true;
|
||||
}
|
||||
page++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Called from RCU critical section */
|
||||
hwaddr memory_region_section_get_iotlb(CPUState *cpu,
|
||||
MemoryRegionSection *section,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue