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 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 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 RH-Acked-by: Michael S. Tsirkin RH-Acked-by: Paolo Bonzini 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 --- hw/vhost.c | 50 +++++++++++++++++++++++++------------------------- hw/vhost.h | 7 +++++++ 2 files changed, 32 insertions(+), 25 deletions(-) Signed-off-by: Michal Novotny --- 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