aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpu-all.h3
-rw-r--r--exec.c8
-rw-r--r--kvm-all.c73
-rw-r--r--kvm.h4
4 files changed, 52 insertions, 36 deletions
diff --git a/cpu-all.h b/cpu-all.h
index b23be6094..dc9b034cb 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 c5c92809e..544fb4307 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 3b6b5ed42..eb4b9eab8 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 1d247e093..d0738f5fa 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);