vhost: track VFIO mappings

If more than one controller is added to guest the same memory table is
set multiple times making VFIO registration/unregistration failures

Change-Id: Ib55c38e292495e549c070beb0234e73f269e63d5
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
This commit is contained in:
Pawel Wodkowski 2017-05-04 20:43:40 +02:00 committed by Piotr Pelplinski
parent f2c8d0dc11
commit 82d26c4f20

View File

@ -42,9 +42,21 @@
#include "vhost_iommu.h"
struct vfio_map {
uint64_t iova;
uint64_t size;
size_t ref;
};
static struct {
int need_init;
int container_fd;
pthread_mutex_t map_lock;
struct vfio_map *maps;
size_t maps_count;
size_t maps_max_count;
} vfio_cfg = { 1, -1 };
/* Internal DPDK function forward declaration */
@ -96,6 +108,7 @@ vfio_cfg_init(void)
return -1;
}
pthread_mutex_init(&vfio_cfg.map_lock, NULL);
return 0;
}
@ -146,16 +159,70 @@ vfio_pci_memory_region_unmap(int vfio_container_fd, uint64_t phys_addr, uint64_t
static int
vfio_pci_memory_region_op(uint64_t vaddr, uint64_t phys_addr, uint64_t size, int op)
{
int ret = 0;
size_t idx;
struct vfio_map *map = vfio_cfg.maps;
bool found = false;
if (vfio_cfg.container_fd == -1) {
return 0;
}
if (op == VFIO_IOMMU_MAP_DMA) {
return vfio_pci_memory_region_map(vfio_cfg.container_fd, vaddr, phys_addr, size);
} else {
return vfio_pci_memory_region_unmap(vfio_cfg.container_fd, phys_addr, size);
for (idx = 0; idx < vfio_cfg.maps_count; idx++, map++) {
assert(map->ref);
if (map->iova == phys_addr && map->size == size) {
found = true;
break;
}
}
if (op == VFIO_IOMMU_MAP_DMA) {
if (found) {
map->ref++;
return 0;
}
ret = vfio_pci_memory_region_map(vfio_cfg.container_fd, vaddr, phys_addr, size);
if (ret) {
return ret;
}
if (vfio_cfg.maps_count == vfio_cfg.maps_max_count) {
vfio_cfg.maps_max_count += 128;
vfio_cfg.maps = realloc(vfio_cfg.maps, vfio_cfg.maps_max_count * sizeof(vfio_cfg.maps[0]));
map = &vfio_cfg.maps[idx];
}
vfio_cfg.maps_count++;
map->iova = phys_addr;
map->size = size;
map->ref = 1;
} else {
if (!found) {
SPDK_ERRLOG("Region vaddr=%p phys_addr=%p len=%#"PRIx64" not VFIO DMA mapped\n",
(void *)vaddr, (void *)phys_addr, size);
return -1;
}
map->ref--;
if (!map->ref) {
vfio_cfg.maps_count--;
if (vfio_cfg.maps_count != idx) {
memmove(map, map + 1, (vfio_cfg.maps_count - idx) * sizeof(map[0]));
}
if (vfio_cfg.maps_count == 0) {
free(vfio_cfg.maps);
vfio_cfg.maps = NULL;
vfio_cfg.maps_count = 0;
vfio_cfg.maps_max_count = 0;
}
ret = vfio_pci_memory_region_unmap(vfio_cfg.container_fd, phys_addr, size);
}
}
return ret;
}
@ -177,6 +244,8 @@ spdk_vfio_mem_op(uint64_t addr, uint64_t len, int dma_op)
return 0;
}
pthread_mutex_lock(&vfio_cfg.map_lock);
vaddr = addr;
while (len > 0) {
vlen = spdk_min(len_2mb - (vaddr & MASK_2MB), len);
@ -213,6 +282,7 @@ spdk_vfio_mem_op(uint64_t addr, uint64_t len, int dma_op)
spdk_vfio_mem_op(addr, vaddr - addr, VFIO_IOMMU_UNMAP_DMA);
}
pthread_mutex_unlock(&vfio_cfg.map_lock);
return ret;
}