kvm: Reallocate dirty_bmap when we change a slot
kvm_set_phys_mem can be called to reallocate a slot by something the guest does (e.g. writing to PAM and other chipset registers). This can happen in the middle of a migration, and if we're unlucky it can now happen between the split 'sync' and 'clear'; the clear asserts if there's no bmap to clear. Recreate the bmap whenever we change the slot, keeping the clear path happy. Typically this is triggered by the guest rebooting during a migrate. Corresponds to: https://bugzilla.redhat.com/show_bug.cgi?id=1772774 https://bugzilla.redhat.com/show_bug.cgi?id=1771032 Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Reviewed-by: Peter Xu <peterx@redhat.com> Signed-off-by: Kunkun Jiang <jiangkunkun@huawei.com>
This commit is contained in:
parent
6af46536db
commit
0412463a76
99
kvm-Reallocate-dirty_bmap-when-we-change-a-slot.patch
Normal file
99
kvm-Reallocate-dirty_bmap-when-we-change-a-slot.patch
Normal file
@ -0,0 +1,99 @@
|
||||
From ccfc5c99103e2f633084c906197075392f625a80 Mon Sep 17 00:00:00 2001
|
||||
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
|
||||
Date: Thu, 21 Nov 2019 16:56:45 +0000
|
||||
Subject: [PATCH] kvm: Reallocate dirty_bmap when we change a slot
|
||||
|
||||
kvm_set_phys_mem can be called to reallocate a slot by something the
|
||||
guest does (e.g. writing to PAM and other chipset registers).
|
||||
This can happen in the middle of a migration, and if we're unlucky
|
||||
it can now happen between the split 'sync' and 'clear'; the clear
|
||||
asserts if there's no bmap to clear. Recreate the bmap whenever
|
||||
we change the slot, keeping the clear path happy.
|
||||
|
||||
Typically this is triggered by the guest rebooting during a migrate.
|
||||
|
||||
Corresponds to:
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1772774
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1771032
|
||||
|
||||
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
Reviewed-by: Peter Xu <peterx@redhat.com>
|
||||
Signed-off-by: Kunkun Jiang <jiangkunkun@huawei.com>
|
||||
---
|
||||
accel/kvm/kvm-all.c | 44 +++++++++++++++++++++++++++++---------------
|
||||
1 file changed, 29 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
|
||||
index 6828f6a1f9..5a6b89cc2a 100644
|
||||
--- a/accel/kvm/kvm-all.c
|
||||
+++ b/accel/kvm/kvm-all.c
|
||||
@@ -536,6 +536,27 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
|
||||
|
||||
#define ALIGN(x, y) (((x)+(y)-1) & ~((y)-1))
|
||||
|
||||
+/* Allocate the dirty bitmap for a slot */
|
||||
+static void kvm_memslot_init_dirty_bitmap(KVMSlot *mem)
|
||||
+{
|
||||
+ /*
|
||||
+ * XXX bad kernel interface alert
|
||||
+ * For dirty bitmap, kernel allocates array of size aligned to
|
||||
+ * bits-per-long. But for case when the kernel is 64bits and
|
||||
+ * the userspace is 32bits, userspace can't align to the same
|
||||
+ * bits-per-long, since sizeof(long) is different between kernel
|
||||
+ * and user space. This way, userspace will provide buffer which
|
||||
+ * may be 4 bytes less than the kernel will use, resulting in
|
||||
+ * userspace memory corruption (which is not detectable by valgrind
|
||||
+ * too, in most cases).
|
||||
+ * So for now, let's align to 64 instead of HOST_LONG_BITS here, in
|
||||
+ * a hope that sizeof(long) won't become >8 any time soon.
|
||||
+ */
|
||||
+ hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS),
|
||||
+ /*HOST_LONG_BITS*/ 64) / 8;
|
||||
+ mem->dirty_bmap = g_malloc0(bitmap_size);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* kvm_physical_sync_dirty_bitmap - Sync dirty bitmap from kernel space
|
||||
*
|
||||
@@ -568,23 +589,9 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- /* XXX bad kernel interface alert
|
||||
- * For dirty bitmap, kernel allocates array of size aligned to
|
||||
- * bits-per-long. But for case when the kernel is 64bits and
|
||||
- * the userspace is 32bits, userspace can't align to the same
|
||||
- * bits-per-long, since sizeof(long) is different between kernel
|
||||
- * and user space. This way, userspace will provide buffer which
|
||||
- * may be 4 bytes less than the kernel will use, resulting in
|
||||
- * userspace memory corruption (which is not detectable by valgrind
|
||||
- * too, in most cases).
|
||||
- * So for now, let's align to 64 instead of HOST_LONG_BITS here, in
|
||||
- * a hope that sizeof(long) won't become >8 any time soon.
|
||||
- */
|
||||
if (!mem->dirty_bmap) {
|
||||
- hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS),
|
||||
- /*HOST_LONG_BITS*/ 64) / 8;
|
||||
/* Allocate on the first log_sync, once and for all */
|
||||
- mem->dirty_bmap = g_malloc0(bitmap_size);
|
||||
+ kvm_memslot_init_dirty_bitmap(mem);
|
||||
}
|
||||
|
||||
d.dirty_bitmap = mem->dirty_bmap;
|
||||
@@ -1066,6 +1073,13 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
||||
mem->ram = ram;
|
||||
mem->flags = kvm_mem_flags(mr);
|
||||
|
||||
+ if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) {
|
||||
+ /*
|
||||
+ * Reallocate the bmap; it means it doesn't disappear in
|
||||
+ * middle of a migrate.
|
||||
+ */
|
||||
+ kvm_memslot_init_dirty_bitmap(mem);
|
||||
+ }
|
||||
err = kvm_set_user_memory_region(kml, mem, true);
|
||||
if (err) {
|
||||
fprintf(stderr, "%s: error registering slot: %s\n", __func__,
|
||||
--
|
||||
2.27.0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user