From 3a30014cfae7d4354503831e01b9ac1ef2b79b00 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Fri, 22 Aug 2008 20:03:35 -0300 Subject: [PATCH] Mark guest mapping as MADV_DONTFORK When qemu fork's (ssh migration, qemu-nbd, slirp), the guest memory mapping becomes shared and write-protected by parent and child, until execve switches to a new mm. get_user_pages with force=1 parameter will break COW during this window, leaving stale shadow mappings that point to the previously shared page. Fix this by madvising the range as MADV_DONTFORK, if mmu notifiers are disabled. Signed-off-by: Marcelo Tosatti Signed-off-by: Avi Kivity --- qemu-kvm.c | 14 ++++++++++++++ qemu-kvm.h | 1 + vl.c | 11 ++++++++--- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/qemu-kvm.c b/qemu-kvm.c index 3466015efb..9018b8d43a 100644 --- a/qemu-kvm.c +++ b/qemu-kvm.c @@ -25,6 +25,7 @@ int kvm_pit = 1; #include #include #include +#include #define bool _Bool #define false 0 @@ -812,6 +813,19 @@ void kvm_cpu_register_physical_memory(target_phys_addr_t start_addr, } } +int kvm_setup_guest_memory(void *area, unsigned long size) +{ + int ret = 0; + + if (kvm_enabled() && !kvm_has_sync_mmu(kvm_context)) + ret = madvise(area, size, MADV_DONTFORK); + + if (ret) + perror ("madvise"); + + return ret; +} + int kvm_qemu_check_extension(int ext) { return kvm_check_extension(kvm_context, ext); diff --git a/qemu-kvm.h b/qemu-kvm.h index 7e28428793..33bef5a449 100644 --- a/qemu-kvm.h +++ b/qemu-kvm.h @@ -45,6 +45,7 @@ void *kvm_cpu_create_phys_mem(target_phys_addr_t start_addr, void kvm_cpu_destroy_phys_mem(target_phys_addr_t start_addr, unsigned long size); +int kvm_setup_guest_memory(void *area, unsigned long size); int kvm_arch_qemu_create_context(void); diff --git a/vl.c b/vl.c index fbf6475450..17cfdfc54c 100644 --- a/vl.c +++ b/vl.c @@ -8932,7 +8932,7 @@ static int gethugepagesize(void) return hugepagesize; } -void *alloc_mem_area(unsigned long memory, const char *path) +void *alloc_mem_area(size_t memory, unsigned long *len, const char *path) { char *filename; void *area; @@ -8971,18 +8971,23 @@ void *alloc_mem_area(unsigned long memory, const char *path) return NULL; } + *len = memory; return area; } void *qemu_alloc_physram(unsigned long memory) { void *area = NULL; + unsigned long map_len = memory; if (mem_path) - area = alloc_mem_area(memory, mem_path); + area = alloc_mem_area(memory, &map_len, mem_path); if (!area) area = qemu_vmalloc(memory); - +#ifdef USE_KVM + if (kvm_setup_guest_memory(area, map_len)) + area = NULL; +#endif return area; } -- 2.11.4.GIT