beside reducing code size 2x times, it also makes function faster and easier to read.
Signed-off-by: Igor Mammedov <imamm...@redhat.com> --- 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