ddf19c
From c477581ccc6962651d4d6c702a6c3e2fcc5e4205 Mon Sep 17 00:00:00 2001
ddf19c
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
ddf19c
Date: Thu, 2 Jan 2020 11:56:51 +0000
ddf19c
Subject: [PATCH 2/2] kvm: Reallocate dirty_bmap when we change a slot
ddf19c
ddf19c
RH-Author: Dr. David Alan Gilbert <dgilbert@redhat.com>
ddf19c
Message-id: <20200102115651.140177-1-dgilbert@redhat.com>
ddf19c
Patchwork-id: 93256
ddf19c
O-Subject: [RHEL-AV-8.2.0 qemu-kvm PATCH 1/1] kvm: Reallocate dirty_bmap when we change a slot
ddf19c
Bugzilla: 1772774
ddf19c
RH-Acked-by: Peter Xu <peterx@redhat.com>
ddf19c
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
ddf19c
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
ddf19c
ddf19c
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
ddf19c
ddf19c
bz: https://bugzilla.redhat.com/show_bug.cgi?id=1772774
ddf19c
brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=25575691
ddf19c
branch: rhel-av-8.2.0
ddf19c
ddf19c
kvm_set_phys_mem can be called to reallocate a slot by something the
ddf19c
guest does (e.g. writing to PAM and other chipset registers).
ddf19c
This can happen in the middle of a migration, and if we're unlucky
ddf19c
it can now happen between the split 'sync' and 'clear'; the clear
ddf19c
asserts if there's no bmap to clear.   Recreate the bmap whenever
ddf19c
we change the slot, keeping the clear path happy.
ddf19c
ddf19c
Typically this is triggered by the guest rebooting during a migrate.
ddf19c
ddf19c
Corresponds to:
ddf19c
https://bugzilla.redhat.com/show_bug.cgi?id=1772774
ddf19c
https://bugzilla.redhat.com/show_bug.cgi?id=1771032
ddf19c
ddf19c
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
ddf19c
Reviewed-by: Peter Xu <peterx@redhat.com>
ddf19c
(cherry picked from commit 9b3a31c745b61758aaa5466a3a9fc0526d409188)
ddf19c
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
ddf19c
---
ddf19c
 accel/kvm/kvm-all.c | 44 +++++++++++++++++++++++++++++---------------
ddf19c
 1 file changed, 29 insertions(+), 15 deletions(-)
ddf19c
ddf19c
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
ddf19c
index dc3ed7f..5007bda 100644
ddf19c
--- a/accel/kvm/kvm-all.c
ddf19c
+++ b/accel/kvm/kvm-all.c
ddf19c
@@ -518,6 +518,27 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
ddf19c
 
ddf19c
 #define ALIGN(x, y)  (((x)+(y)-1) & ~((y)-1))
ddf19c
 
ddf19c
+/* Allocate the dirty bitmap for a slot  */
ddf19c
+static void kvm_memslot_init_dirty_bitmap(KVMSlot *mem)
ddf19c
+{
ddf19c
+    /*
ddf19c
+     * XXX bad kernel interface alert
ddf19c
+     * For dirty bitmap, kernel allocates array of size aligned to
ddf19c
+     * bits-per-long.  But for case when the kernel is 64bits and
ddf19c
+     * the userspace is 32bits, userspace can't align to the same
ddf19c
+     * bits-per-long, since sizeof(long) is different between kernel
ddf19c
+     * and user space.  This way, userspace will provide buffer which
ddf19c
+     * may be 4 bytes less than the kernel will use, resulting in
ddf19c
+     * userspace memory corruption (which is not detectable by valgrind
ddf19c
+     * too, in most cases).
ddf19c
+     * So for now, let's align to 64 instead of HOST_LONG_BITS here, in
ddf19c
+     * a hope that sizeof(long) won't become >8 any time soon.
ddf19c
+     */
ddf19c
+    hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS),
ddf19c
+                                        /*HOST_LONG_BITS*/ 64) / 8;
ddf19c
+    mem->dirty_bmap = g_malloc0(bitmap_size);
ddf19c
+}
ddf19c
+
ddf19c
 /**
ddf19c
  * kvm_physical_sync_dirty_bitmap - Sync dirty bitmap from kernel space
ddf19c
  *
ddf19c
@@ -550,23 +571,9 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml,
ddf19c
             goto out;
ddf19c
         }
ddf19c
 
ddf19c
-        /* XXX bad kernel interface alert
ddf19c
-         * For dirty bitmap, kernel allocates array of size aligned to
ddf19c
-         * bits-per-long.  But for case when the kernel is 64bits and
ddf19c
-         * the userspace is 32bits, userspace can't align to the same
ddf19c
-         * bits-per-long, since sizeof(long) is different between kernel
ddf19c
-         * and user space.  This way, userspace will provide buffer which
ddf19c
-         * may be 4 bytes less than the kernel will use, resulting in
ddf19c
-         * userspace memory corruption (which is not detectable by valgrind
ddf19c
-         * too, in most cases).
ddf19c
-         * So for now, let's align to 64 instead of HOST_LONG_BITS here, in
ddf19c
-         * a hope that sizeof(long) won't become >8 any time soon.
ddf19c
-         */
ddf19c
         if (!mem->dirty_bmap) {
ddf19c
-            hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS),
ddf19c
-                                        /*HOST_LONG_BITS*/ 64) / 8;
ddf19c
             /* Allocate on the first log_sync, once and for all */
ddf19c
-            mem->dirty_bmap = g_malloc0(bitmap_size);
ddf19c
+            kvm_memslot_init_dirty_bitmap(mem);
ddf19c
         }
ddf19c
 
ddf19c
         d.dirty_bitmap = mem->dirty_bmap;
ddf19c
@@ -1067,6 +1074,13 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
ddf19c
         mem->ram = ram;
ddf19c
         mem->flags = kvm_mem_flags(mr);
ddf19c
 
ddf19c
+        if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) {
ddf19c
+            /*
ddf19c
+             * Reallocate the bmap; it means it doesn't disappear in
ddf19c
+             * middle of a migrate.
ddf19c
+             */
ddf19c
+            kvm_memslot_init_dirty_bitmap(mem);
ddf19c
+        }
ddf19c
         err = kvm_set_user_memory_region(kml, mem, true);
ddf19c
         if (err) {
ddf19c
             fprintf(stderr, "%s: error registering slot: %s\n", __func__,
ddf19c
-- 
ddf19c
1.8.3.1
ddf19c