From: Ashish Kalra <ashish.ka...@amd.com>

Page conversion call can span multiple memory regions, potentially
resulting in a conversion failure if the memory range being converted
extends beyond the boundaries of the referenced memory region.

Handle the case of page conversion call straddling across memory
regions.

Signed-off-by: Ashish Kalra <ashish.ka...@amd.com>
---
 accel/kvm/kvm-all.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 9060599cd7..54034a0568 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3054,6 +3054,8 @@ static void kvm_eat_signals(CPUState *cpu)
 int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
 {
     MemoryRegionSection section;
+    hwaddr convert_start;
+    hwaddr convert_size;
     ram_addr_t offset;
     MemoryRegion *mr;
     RAMBlock *rb;
@@ -3071,6 +3073,11 @@ int kvm_convert_memory(hwaddr start, hwaddr size, bool 
to_private)
         return ret;
     }
 
+    /*
+     * Page conversions can span multiple memory regions, for example, if two
+     * memory backends are added to support two different NUMA nodes/policies.
+     */
+next_memory_region:
     section = memory_region_find(get_system_memory(), start, size);
     mr = section.mr;
     if (!mr) {
@@ -3121,8 +3128,12 @@ int kvm_convert_memory(hwaddr start, hwaddr size, bool 
to_private)
     addr = memory_region_get_ram_ptr(mr) + section.offset_within_region;
     rb = qemu_ram_block_from_host(addr, false, &offset);
 
+    convert_start = section.offset_within_region;
+    convert_size = (convert_start + size > mr->size) ?
+                   mr->size - convert_start : size;
+
     ret = ram_block_attributes_state_change(RAM_BLOCK_ATTRIBUTES(mr->rdm),
-                                            offset, size, to_private);
+                                            offset, convert_size, to_private);
     if (ret) {
         error_report("Failed to notify the listener the state change of "
                      "(0x%"HWADDR_PRIx" + 0x%"HWADDR_PRIx") to %s",
@@ -3138,9 +3149,15 @@ int kvm_convert_memory(hwaddr start, hwaddr size, bool 
to_private)
              */
             goto out_unref;
         }
-        ret = ram_block_discard_range(rb, offset, size);
+        ret = ram_block_discard_range(rb, offset, convert_size);
     } else {
-        ret = ram_block_discard_guest_memfd_range(rb, offset, size);
+        ret = ram_block_discard_guest_memfd_range(rb, offset, convert_size);
+    }
+
+    if (size - convert_size) {
+        start += convert_size;
+        size -= convert_size;
+        goto next_memory_region;
     }
 
 out_unref:
-- 
2.34.1


Reply via email to