From 64bde2b77e322afd2a3daff1216b34b673f3e0eb Mon Sep 17 00:00:00 2001
Message-Id: <64bde2b77e322afd2a3daff1216b34b673f3e0eb.1357726992.git.minovotn@redhat.com>
In-Reply-To: <4f8efce613a639a3c1e3022c521d6c70b7154de8.1357726992.git.minovotn@redhat.com>
References: <4f8efce613a639a3c1e3022c521d6c70b7154de8.1357726992.git.minovotn@redhat.com>
From: Stefan Hajnoczi <stefanha@redhat.com>
Date: Wed, 2 Jan 2013 15:02:26 +0100
Subject: [PATCH 03/16] vhost: make memory region assign/unassign functions
 public

RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: <1357138959-1918-4-git-send-email-stefanha@redhat.com>
Patchwork-id: 45516
O-Subject: [RHEL6.4 qemu-kvm PATCH v5 03/16] vhost: make memory region assign/unassign functions public
Bugzilla: 877836
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>

The vhost ioctl API requires that userspace set a memory table
containing the guest RAM regions and their userspace addresses.  This
allows vhost to map guest physical addresses to userspace addresses.

The same lookup is needed by virtio-blk-data-plane.  Instead of
duplicating the memory region assign/unassign code, share the vhost
functions used to build the memory table when the memory map changes
inside QEMU.

Make the assign/unassign functions public so they can be reused by
virtio-blk-data-plane.  Only struct vhost_memory is interesting so
eliminate struct vhost_dev usage.

This patch is RHEL-only because upstream has a more generic
MemoryListener API which provides a sorted flat view of memory regions -
in that environment there's little duplication because memory regions
don't need to be split/merged.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 hw/vhost.c | 50 +++++++++++++++++++++++++-------------------------
 hw/vhost.h |  7 +++++++
 2 files changed, 32 insertions(+), 25 deletions(-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 hw/vhost.c | 50 +++++++++++++++++++++++++-------------------------
 hw/vhost.h |  7 +++++++
 2 files changed, 32 insertions(+), 25 deletions(-)

diff --git a/hw/vhost.c b/hw/vhost.c
index b16fc4c..6e1b492 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -84,24 +84,24 @@ static int vhost_client_sync_dirty_bitmap(CPUPhysMemoryClient *client,
 }
 
 /* Assign/unassign. Keep an unsorted array of non-overlapping
- * memory regions in dev->mem. */
-static void vhost_dev_unassign_memory(struct vhost_dev *dev,
-                                      uint64_t start_addr,
-                                      uint64_t size)
+ * memory regions. */
+void vhost_mem_unassign_memory(struct vhost_memory *mem,
+                               uint64_t start_addr,
+                               uint64_t size)
 {
-    int from, to, n = dev->mem->nregions;
+    int from, to, n = mem->nregions;
     /* Track overlapping/split regions for sanity checking. */
     int overlap_start = 0, overlap_end = 0, overlap_middle = 0, split = 0;
 
     for (from = 0, to = 0; from < n; ++from, ++to) {
-        struct vhost_memory_region *reg = dev->mem->regions + to;
+        struct vhost_memory_region *reg = mem->regions + to;
         uint64_t reglast;
         uint64_t memlast;
         uint64_t change;
 
         /* clone old region */
         if (to != from) {
-            memcpy(reg, dev->mem->regions + from, sizeof *reg);
+            memcpy(reg, mem->regions + from, sizeof *reg);
         }
 
         /* No overlap is simple */
@@ -120,7 +120,7 @@ static void vhost_dev_unassign_memory(struct vhost_dev *dev,
 
         /* Remove whole region */
         if (start_addr <= reg->guest_phys_addr && memlast >= reglast) {
-            --dev->mem->nregions;
+            --mem->nregions;
             --to;
             ++overlap_middle;
             continue;
@@ -154,39 +154,39 @@ static void vhost_dev_unassign_memory(struct vhost_dev *dev,
         assert(!overlap_end);
         assert(!overlap_middle);
         /* Split region: shrink first part, shift second part. */
-        memcpy(dev->mem->regions + n, reg, sizeof *reg);
+        memcpy(mem->regions + n, reg, sizeof *reg);
         reg->memory_size = start_addr - reg->guest_phys_addr;
         assert(reg->memory_size);
         change = memlast + 1 - reg->guest_phys_addr;
-        reg = dev->mem->regions + n;
+        reg = mem->regions + n;
         reg->memory_size -= change;
         assert(reg->memory_size);
         reg->guest_phys_addr += change;
         reg->userspace_addr += change;
         /* Never add more than 1 region */
-        assert(dev->mem->nregions == n);
-        ++dev->mem->nregions;
+        assert(mem->nregions == n);
+        ++mem->nregions;
         ++split;
     }
 }
 
 /* Called after unassign, so no regions overlap the given range. */
-static void vhost_dev_assign_memory(struct vhost_dev *dev,
-                                    uint64_t start_addr,
-                                    uint64_t size,
-                                    uint64_t uaddr)
+void vhost_mem_assign_memory(struct vhost_memory *mem,
+                             uint64_t start_addr,
+                             uint64_t size,
+                             uint64_t uaddr)
 {
     int from, to;
     struct vhost_memory_region *merged = NULL;
-    for (from = 0, to = 0; from < dev->mem->nregions; ++from, ++to) {
-        struct vhost_memory_region *reg = dev->mem->regions + to;
+    for (from = 0, to = 0; from < mem->nregions; ++from, ++to) {
+        struct vhost_memory_region *reg = mem->regions + to;
         uint64_t prlast, urlast;
         uint64_t pmlast, umlast;
         uint64_t s, e, u;
 
         /* clone old region */
         if (to != from) {
-            memcpy(reg, dev->mem->regions + from, sizeof *reg);
+            memcpy(reg, mem->regions + from, sizeof *reg);
         }
         prlast = range_get_last(reg->guest_phys_addr, reg->memory_size);
         pmlast = range_get_last(start_addr, size);
@@ -218,7 +218,7 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev,
     }
 
     if (!merged) {
-        struct vhost_memory_region *reg = dev->mem->regions + to;
+        struct vhost_memory_region *reg = mem->regions + to;
         memset(reg, 0, sizeof *reg);
         reg->memory_size = size;
         assert(reg->memory_size);
@@ -226,8 +226,8 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev,
         reg->userspace_addr = uaddr;
         ++to;
     }
-    assert(to <= dev->mem->nregions + 1);
-    dev->mem->nregions = to;
+    assert(to <= mem->nregions + 1);
+    mem->nregions = to;
 }
 
 static uint64_t vhost_get_log_size(struct vhost_dev *dev)
@@ -324,14 +324,14 @@ static void vhost_client_set_memory(CPUPhysMemoryClient *client,
 
     assert(size);
 
-    vhost_dev_unassign_memory(dev, start_addr, size);
+    vhost_mem_unassign_memory(dev->mem, start_addr, size);
     if (flags == IO_MEM_RAM) {
         /* Add given mapping, merging adjacent regions if any */
-        vhost_dev_assign_memory(dev, start_addr, size,
+        vhost_mem_assign_memory(dev->mem, start_addr, size,
                                 (uintptr_t)qemu_get_ram_ptr(phys_offset));
     } else {
         /* Remove old mapping for this memory, if any. */
-        vhost_dev_unassign_memory(dev, start_addr, size);
+        vhost_mem_unassign_memory(dev->mem, start_addr, size);
     }
 
     if (!dev->started) {
diff --git a/hw/vhost.h b/hw/vhost.h
index c9452f0..d283797 100644
--- a/hw/vhost.h
+++ b/hw/vhost.h
@@ -49,4 +49,11 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev);
 int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
 void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
 
+void vhost_mem_unassign_memory(struct vhost_memory *mem,
+                               uint64_t start_addr,
+                               uint64_t size);
+void vhost_mem_assign_memory(struct vhost_memory *mem,
+                             uint64_t start_addr,
+                             uint64_t size,
+                             uint64_t uaddr);
 #endif
-- 
1.7.11.7

