diff --git a/kvm-all.c b/kvm-all.c index f64a8e92a3..f4851c0078 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -58,6 +58,7 @@ struct KVMState int vmfd; int coalesced_mmio; int broken_set_mem_region; + int migration_log; #ifdef KVM_CAP_SET_GUEST_DEBUG struct kvm_sw_breakpoint_head kvm_sw_breakpoints; #endif @@ -135,7 +136,9 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) mem.memory_size = slot->memory_size; mem.userspace_addr = (unsigned long)qemu_get_ram_ptr(slot->phys_offset); mem.flags = slot->flags; - + if (s->migration_log) { + mem.flags |= KVM_MEM_LOG_DIRTY_PAGES; + } return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem); } @@ -196,11 +199,12 @@ int kvm_sync_vcpus(void) * dirty pages logging control */ static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr, - ram_addr_t size, unsigned flags, - unsigned mask) + ram_addr_t size, int flags, int mask) { KVMState *s = kvm_state; KVMSlot *mem = kvm_lookup_matching_slot(s, phys_addr, phys_addr + size); + int old_flags; + if (mem == NULL) { fprintf(stderr, "BUG: %s: invalid parameters " TARGET_FMT_plx "-" TARGET_FMT_plx "\n", __func__, phys_addr, @@ -208,13 +212,19 @@ static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr, return -EINVAL; } - flags = (mem->flags & ~mask) | flags; - /* Nothing changed, no need to issue ioctl */ - if (flags == mem->flags) - return 0; + old_flags = mem->flags; + flags = (mem->flags & ~mask) | flags; mem->flags = flags; + /* If nothing changed effectively, no need to issue ioctl */ + if (s->migration_log) { + flags |= KVM_MEM_LOG_DIRTY_PAGES; + } + if (flags == old_flags) { + return 0; + } + return kvm_set_user_memory_region(s, mem); } @@ -232,6 +242,28 @@ int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size) KVM_MEM_LOG_DIRTY_PAGES); } +int kvm_set_migration_log(int enable) +{ + KVMState *s = kvm_state; + KVMSlot *mem; + int i, err; + + s->migration_log = enable; + + for (i = 0; i < ARRAY_SIZE(s->slots); i++) { + mem = &s->slots[i]; + + if (!!(mem->flags & KVM_MEM_LOG_DIRTY_PAGES) == enable) { + continue; + } + err = kvm_set_user_memory_region(s, mem); + if (err) { + return err; + } + } + return 0; +} + /** * kvm_physical_sync_dirty_bitmap - Grab dirty bitmap from kernel space * This function updates qemu's dirty bitmap using cpu_physical_memory_set_dirty(). diff --git a/kvm.h b/kvm.h index 4cf754962a..1d247e093e 100644 --- a/kvm.h +++ b/kvm.h @@ -45,6 +45,7 @@ void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_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); +int kvm_set_migration_log(int enable); int kvm_has_sync_mmu(void);