qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC v2 3/6] memory: support unmapping of MemoryRegion mapp


From: Igor Mammedov
Subject: [Qemu-devel] [RFC v2 3/6] memory: support unmapping of MemoryRegion mapped into HVA parent
Date: Mon, 8 Jun 2015 17:19:14 +0200

due to need to preserve HVA reserved range continous (make it atomic),
unmap subregion's host memory by placing reservation mapping
on it's range and invalidate subregion since it can't be reused
anymore.

Also add memory_region_is_hva_mapped() to let backend check if
MemoryRegion should be recreated instead of returning invalidated
region.

Signed-off-by: Igor Mammedov <address@hidden>
---
 exec.c                    | 17 ++++++++++++++++-
 include/exec/cpu-common.h |  1 +
 include/exec/memory.h     | 13 +++++++++++++
 memory.c                  | 16 ++++++++++++++++
 4 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/exec.c b/exec.c
index 7e47f64..7bef7f9 100644
--- a/exec.c
+++ b/exec.c
@@ -1332,11 +1332,22 @@ void *qemu_ram_reserve_hva(ram_addr_t length)
                 MAP_NORESERVE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 }
 
+void qemu_ram_unmap_hva(ram_addr_t addr)
+{
+    RAMBlock *block = find_ram_block(addr);
+
+    assert(block);
+    mmap(block->host, block->used_length, PROT_NONE,
+         MAP_FIXED | MAP_NORESERVE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+}
+
 void qemu_ram_remap_hva(ram_addr_t addr, void *new_hva)
 {
     RAMBlock *block = find_ram_block(addr);
 
     assert(block);
+    assert(!(block->flags & RAM_PREALLOC));
+    block->flags |= RAM_PREALLOC;
     block->host = mremap(block->host, block->used_length,
                       block->used_length,
                       MREMAP_MAYMOVE | MREMAP_FIXED, new_hva);
@@ -1595,11 +1606,15 @@ static void reclaim_ramblock(RAMBlock *block)
 #ifndef _WIN32
     } else if (block->fd >= 0) {
         munmap(block->host, block->max_length);
-        close(block->fd);
 #endif
     } else {
         qemu_anon_ram_free(block->host, block->max_length);
     }
+#ifndef _WIN32
+    if (block->fd >= 0) {
+        close(block->fd);
+    }
+#endif
     g_free(block);
 }
 
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index ec077ee..817762c 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -62,6 +62,7 @@ typedef uint32_t CPUReadMemoryFunc(void *opaque, hwaddr addr);
 void qemu_ram_remap(ram_addr_t addr, ram_addr_t length);
 void *qemu_ram_reserve_hva(ram_addr_t length);
 void qemu_ram_remap_hva(ram_addr_t addr, void *new_hva);
+void qemu_ram_unmap_hva(ram_addr_t addr);
 /* This should not be used by devices.  */
 MemoryRegion *qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr);
 void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev);
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 5e16026..f9e86d6 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -175,6 +175,7 @@ struct MemoryRegion {
     bool romd_mode;
     bool ram;
     void *rsvd_hva;
+    bool hva_mapped;
     bool skip_dump;
     bool readonly; /* For RAM regions */
     bool enabled;
@@ -902,6 +903,10 @@ void memory_region_add_subregion(MemoryRegion *mr,
  * memory_region_del_subregion()); use memory_region_init_alias() if you
  * want a region to be a subregion in multiple locations.
  *
+ * if @subregion has HVA container as parent, the call rereseves HVA
+ * range ocicupied by @subregion, freeing host memory along the way
+ * and invalidates @subregion so it coudn't be reused.
+ *
  * @mr: the region to contain the new subregion; must be a container
  *      initialized with memory_region_init().
  * @offset: the offset relative to @mr where @subregion is added.
@@ -1003,6 +1008,14 @@ bool memory_region_present(MemoryRegion *container, 
hwaddr addr);
 bool memory_region_is_mapped(MemoryRegion *mr);
 
 /**
+ * memory_region_is_hva_mapped: returns true if #MemoryRegion is/was
+ * mapped into HVA container.
+ *
+ * @mr: a #MemoryRegion which should be checked if it's HVA parent
+ */
+bool memory_region_is_hva_mapped(MemoryRegion *mr);
+
+/**
  * memory_region_find: translate an address/size relative to a
  * MemoryRegion into a #MemoryRegionSection.
  *
diff --git a/memory.c b/memory.c
index f9b8a60..ab6d41b 100644
--- a/memory.c
+++ b/memory.c
@@ -1754,7 +1754,9 @@ static void 
memory_region_add_subregion_common(MemoryRegion *mr,
     if (mr->ram) {
        MemoryRegionSection rsvd_hva = memory_region_find_hva_range(mr);
 
+        assert(!subregion->hva_mapped);
         if (rsvd_hva.mr) {
+            subregion->hva_mapped = true;
             qemu_ram_remap_hva(mr->ram_addr,
                 memory_region_get_ram_ptr(rsvd_hva.mr) +
                     rsvd_hva.offset_within_region);
@@ -1788,6 +1790,15 @@ void memory_region_del_subregion(MemoryRegion *mr,
 {
     memory_region_transaction_begin();
     assert(subregion->container == mr);
+
+    if (mr->ram) {
+        MemoryRegionSection rsvd_hva = memory_region_find_hva_range(mr);
+
+        if (rsvd_hva.mr) {
+            qemu_ram_unmap_hva(mr->ram_addr);
+        }
+    }
+
     subregion->container = NULL;
     QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link);
     memory_region_unref(subregion);
@@ -1903,6 +1914,11 @@ bool memory_region_is_mapped(MemoryRegion *mr)
     return mr->container ? true : false;
 }
 
+bool memory_region_is_hva_mapped(MemoryRegion *mr)
+{
+    return mr->hva_mapped ? true : false;
+}
+
 MemoryRegionSection memory_region_find_hva_range(MemoryRegion *mr)
 {
     MemoryRegionSection ret = { .mr = NULL };
-- 
1.8.3.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]