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