[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH for-2.5 4/4] vhost: simplify/speedify vhost_dev_unas
From: |
Igor Mammedov |
Subject: |
[Qemu-devel] [PATCH for-2.5 4/4] vhost: simplify/speedify vhost_dev_unassign_memory() |
Date: |
Tue, 28 Jul 2015 16:52:53 +0200 |
beside reducing code size 2x times, it also makes
function faster and easier to read.
Signed-off-by: Igor Mammedov <address@hidden>
---
hw/virtio/vhost.c | 111 ++++++++++++++++++------------------------------------
1 file changed, 37 insertions(+), 74 deletions(-)
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 5b8598b..e2585e3 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -160,91 +160,54 @@ static int memory_range_bsearch(const struct vhost_dev
*dev,
return start;
}
-/* 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)
{
- int from, to, n = dev->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;
- uint64_t reglast;
- uint64_t memlast;
- uint64_t change;
-
- /* clone old region */
- if (to != from) {
- memcpy(reg, dev->mem->regions + from, sizeof *reg);
- }
-
- /* No overlap is simple */
- if (!ranges_overlap(reg->guest_phys_addr, reg->memory_size,
- start_addr, size)) {
- continue;
- }
-
- /* Split only happens if supplied region
- * is in the middle of an existing one. Thus it can not
- * overlap with any other existing region. */
- assert(!split);
+ uint64_t reglast, memlast;
+ struct vhost_memory_region *reg;
+ int idx = memory_range_bsearch(dev, start_addr);
- reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
- memlast = range_get_last(start_addr, size);
+ if (idx == dev->mem->nregions) { /* not found any range */
+ return;
+ }
- /* Remove whole region */
- if (start_addr <= reg->guest_phys_addr && memlast >= reglast) {
- --dev->mem->nregions;
- --to;
- ++overlap_middle;
- continue;
- }
+ reg = dev->mem->regions + idx;
+ reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
+ memlast = range_get_last(start_addr, size);
- /* Shrink region */
- if (memlast >= reglast) {
- reg->memory_size = start_addr - reg->guest_phys_addr;
- assert(reg->memory_size);
- assert(!overlap_end);
- ++overlap_end;
- continue;
- }
+ /* Remove whole region */
+ if (start_addr == reg->guest_phys_addr && memlast == reglast) {
+ memmove(reg, reg + 1, (dev->mem->nregions - idx - 1) *
+ sizeof dev->mem->regions[0]);
+ dev->mem->nregions--;
+ return;
+ }
- /* Shift region */
- if (start_addr <= reg->guest_phys_addr) {
- change = memlast + 1 - reg->guest_phys_addr;
- reg->memory_size -= change;
- reg->guest_phys_addr += change;
- reg->userspace_addr += change;
- assert(reg->memory_size);
- assert(!overlap_start);
- ++overlap_start;
- continue;
- }
+ /* Split region */
+ if (start_addr > reg->guest_phys_addr && memlast < reglast) {
+ memmove(reg + 1, reg, (dev->mem->nregions - idx) *
+ sizeof dev->mem->regions[0]);
+ reg->guest_phys_addr = memlast + 1;
+ reg->memory_size = reglast - reg->guest_phys_addr + 1;
+ reg++;
+ reg->memory_size = start_addr - reg->guest_phys_addr;
+ dev->mem->nregions++;
+ return;
+ }
- /* This only happens if supplied region
- * is in the middle of an existing one. Thus it can not
- * overlap with any other existing region. */
- assert(!overlap_start);
- assert(!overlap_end);
- assert(!overlap_middle);
- /* Split region: shrink first part, shift second part. */
- memcpy(dev->mem->regions + n, reg, sizeof *reg);
+ /* Shrink region */
+ if (memlast == reglast) { /* shrink end side */
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->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;
- ++split;
+ return;
+ } else if (start_addr == reg->guest_phys_addr) { /* shrink start side */
+ reg->guest_phys_addr = memlast + 1;
+ reg->memory_size = reglast - reg->guest_phys_addr + 1;
+ return;
}
+ /* there shouldn't be any overlapped ranges by now */
+ assert(!ranges_overlap(reg->guest_phys_addr, reg->memory_size,
+ start_addr, size));
}
/* Called after unassign, so no regions overlap the given range. */
--
1.8.3.1