From 151f7749f26e8b0eaca517376a89c01430c584e5 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 1 May 2009 20:52:47 +0200 Subject: [PATCH] kvm: Rework dirty bitmap synchronization Extend kvm_physical_sync_dirty_bitmap() so that is can sync across multiple slots. Useful for updating the whole dirty log during migration. Moreover, properly pass down errors the whole call chain. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- cpu-all.h | 3 ++- exec.c | 8 +++++-- kvm-all.c | 73 ++++++++++++++++++++++++++++++++++++--------------------------- kvm.h | 4 ++-- 4 files changed, 52 insertions(+), 36 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index b23be60945..dc9b034cbc 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -901,7 +901,8 @@ int cpu_physical_memory_set_dirty_tracking(int enable); int cpu_physical_memory_get_dirty_tracking(void); -void cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr); +int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr); void dump_exec_info(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); diff --git a/exec.c b/exec.c index c5c92809eb..544fb43074 100644 --- a/exec.c +++ b/exec.c @@ -1931,10 +1931,14 @@ int cpu_physical_memory_get_dirty_tracking(void) return in_migration; } -void cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr) +int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr) { + int ret = 0; + if (kvm_enabled()) - kvm_physical_sync_dirty_bitmap(start_addr, end_addr); + ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr); + return ret; } static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) diff --git a/kvm-all.c b/kvm-all.c index 3b6b5ed423..eb4b9eab82 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -272,47 +272,58 @@ int kvm_set_migration_log(int enable) * @start_add: start of logged region. * @end_addr: end of logged region. */ -void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, - target_phys_addr_t end_addr) +int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr) { KVMState *s = kvm_state; - KVMDirtyLog d; - KVMSlot *mem = kvm_lookup_matching_slot(s, start_addr, end_addr); - unsigned long alloc_size; + unsigned long size, allocated_size = 0; + target_phys_addr_t phys_addr; ram_addr_t addr; - target_phys_addr_t phys_addr = start_addr; + KVMDirtyLog d; + KVMSlot *mem; + int ret = 0; - dprintf("sync addr: " TARGET_FMT_lx " into %lx\n", start_addr, - mem->phys_offset); - if (mem == NULL) { - fprintf(stderr, "BUG: %s: invalid parameters " TARGET_FMT_plx "-" - TARGET_FMT_plx "\n", __func__, phys_addr, end_addr - 1); - return; - } + d.dirty_bitmap = NULL; + while (start_addr < end_addr) { + mem = kvm_lookup_overlapping_slot(s, start_addr, end_addr); + if (mem == NULL) { + break; + } - alloc_size = ((mem->memory_size >> TARGET_PAGE_BITS) + 7) / 8; - d.dirty_bitmap = qemu_mallocz(alloc_size); + size = ((mem->memory_size >> TARGET_PAGE_BITS) + 7) / 8; + if (!d.dirty_bitmap) { + d.dirty_bitmap = qemu_malloc(size); + } else if (size > allocated_size) { + d.dirty_bitmap = qemu_realloc(d.dirty_bitmap, size); + } + allocated_size = size; + memset(d.dirty_bitmap, 0, allocated_size); - d.slot = mem->slot; - dprintf("slot %d, phys_addr %llx, uaddr: %llx\n", - d.slot, mem->start_addr, mem->phys_offset); + d.slot = mem->slot; - if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) { - dprintf("ioctl failed %d\n", errno); - goto out; - } + if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) { + dprintf("ioctl failed %d\n", errno); + ret = -1; + break; + } + + for (phys_addr = mem->start_addr, addr = mem->phys_offset; + phys_addr < mem->start_addr + mem->memory_size; + phys_addr += TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) { + unsigned long *bitmap = (unsigned long *)d.dirty_bitmap; + unsigned nr = (phys_addr - mem->start_addr) >> TARGET_PAGE_BITS; + unsigned word = nr / (sizeof(*bitmap) * 8); + unsigned bit = nr % (sizeof(*bitmap) * 8); - phys_addr = start_addr; - for (addr = mem->phys_offset; phys_addr < end_addr; phys_addr+= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) { - unsigned long *bitmap = (unsigned long *)d.dirty_bitmap; - unsigned nr = (phys_addr - start_addr) >> TARGET_PAGE_BITS; - unsigned word = nr / (sizeof(*bitmap) * 8); - unsigned bit = nr % (sizeof(*bitmap) * 8); - if ((bitmap[word] >> bit) & 1) - cpu_physical_memory_set_dirty(addr); + if ((bitmap[word] >> bit) & 1) { + cpu_physical_memory_set_dirty(addr); + } + } + start_addr = phys_addr; } -out: qemu_free(d.dirty_bitmap); + + return ret; } int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) diff --git a/kvm.h b/kvm.h index 1d247e093e..d0738f5fa0 100644 --- a/kvm.h +++ b/kvm.h @@ -40,8 +40,8 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, ram_addr_t phys_offset); -void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, - target_phys_addr_t end_addr); +int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr); int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size); int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size); -- 2.11.4.GIT