We miss call to unmap in cases when vhost_memory_map() returns lenght less than requested (still we consider such cases as an error). Let's fix it in vhost_memory_map().
Signed-off-by: Vladimir Sementsov-Ogievskiy <[email protected]> --- hw/virtio/vhost.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 40440c6d68..1ef9b3ed6c 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -454,11 +454,20 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) } static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr, - hwaddr *plen, bool is_write) + hwaddr len, bool is_write) { if (!vhost_dev_has_iommu(dev)) { - return address_space_map(dev->vdev->dma_as, addr, plen, is_write, - MEMTXATTRS_UNSPECIFIED); + hwaddr mapped_len = len; + void *res = address_space_map(dev->vdev->dma_as, addr, &mapped_len, + is_write, MEMTXATTRS_UNSPECIFIED); + if (!res) { + return NULL; + } + if (len != mapped_len) { + address_space_unmap(dev->vdev->dma_as, res, mapped_len, 0, 0); + return NULL; + } + return res; } else { return (void *)(uintptr_t)addr; } @@ -1312,22 +1321,22 @@ int vhost_virtqueue_start(struct vhost_dev *dev, } l = vq->desc_size; - vq->desc = vhost_memory_map(dev, vq->desc_phys, &l, false); - if (!vq->desc || l != vq->desc_size) { + vq->desc = vhost_memory_map(dev, vq->desc_phys, l, false); + if (!vq->desc) { r = -ENOMEM; goto fail_alloc_desc; } l = vq->avail_size; - vq->avail = vhost_memory_map(dev, vq->avail_phys, &l, false); - if (!vq->avail || l != vq->avail_size) { + vq->avail = vhost_memory_map(dev, vq->avail_phys, l, false); + if (!vq->avail) { r = -ENOMEM; goto fail_alloc_avail; } l = vq->used_size; - vq->used = vhost_memory_map(dev, vq->used_phys, &l, true); - if (!vq->used || l != vq->used_size) { + vq->used = vhost_memory_map(dev, vq->used_phys, l, true); + if (!vq->used) { r = -ENOMEM; goto fail_alloc_used; } -- 2.52.0
