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