vfio/type1: implement interfaces to update vaddr
Implement VFIO_DMA_UNMAP_FLAG_VADDR, VFIO_DMA_MAP_FLAG_VADDR, and VFIO_UPDATE_VADDR. This is a partial implementation. Blocking is added in a subsequent patch. Signed-off-by: Steve Sistare <steven.sistare@oracle.com> Reviewed-by: Cornelia Huck <cohuck@redhat.com> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
parent
40ae9b807b
commit
c3cbab24db
|
@ -69,6 +69,7 @@ struct vfio_iommu {
|
|||
struct rb_root dma_list;
|
||||
struct blocking_notifier_head notifier;
|
||||
unsigned int dma_avail;
|
||||
unsigned int vaddr_invalid_count;
|
||||
uint64_t pgsize_bitmap;
|
||||
bool v2;
|
||||
bool nesting;
|
||||
|
@ -92,6 +93,7 @@ struct vfio_dma {
|
|||
int prot; /* IOMMU_READ/WRITE */
|
||||
bool iommu_mapped;
|
||||
bool lock_cap; /* capable(CAP_IPC_LOCK) */
|
||||
bool vaddr_invalid;
|
||||
struct task_struct *task;
|
||||
struct rb_root pfn_list; /* Ex-user pinned pfn list */
|
||||
unsigned long *bitmap;
|
||||
|
@ -974,6 +976,8 @@ static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
|
|||
vfio_unlink_dma(iommu, dma);
|
||||
put_task_struct(dma->task);
|
||||
vfio_dma_bitmap_free(dma);
|
||||
if (dma->vaddr_invalid)
|
||||
iommu->vaddr_invalid_count--;
|
||||
kfree(dma);
|
||||
iommu->dma_avail++;
|
||||
}
|
||||
|
@ -1104,7 +1108,8 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
|
|||
dma_addr_t iova = unmap->iova;
|
||||
unsigned long size = unmap->size;
|
||||
bool unmap_all = unmap->flags & VFIO_DMA_UNMAP_FLAG_ALL;
|
||||
struct rb_node *n;
|
||||
bool invalidate_vaddr = unmap->flags & VFIO_DMA_UNMAP_FLAG_VADDR;
|
||||
struct rb_node *n, *first_n;
|
||||
|
||||
mutex_lock(&iommu->lock);
|
||||
|
||||
|
@ -1175,7 +1180,7 @@ again:
|
|||
}
|
||||
|
||||
ret = 0;
|
||||
n = vfio_find_dma_first_node(iommu, iova, size);
|
||||
n = first_n = vfio_find_dma_first_node(iommu, iova, size);
|
||||
|
||||
while (n) {
|
||||
dma = rb_entry(n, struct vfio_dma, node);
|
||||
|
@ -1191,6 +1196,27 @@ again:
|
|||
if (dma->task->mm != current->mm)
|
||||
break;
|
||||
|
||||
if (invalidate_vaddr) {
|
||||
if (dma->vaddr_invalid) {
|
||||
struct rb_node *last_n = n;
|
||||
|
||||
for (n = first_n; n != last_n; n = rb_next(n)) {
|
||||
dma = rb_entry(n,
|
||||
struct vfio_dma, node);
|
||||
dma->vaddr_invalid = false;
|
||||
iommu->vaddr_invalid_count--;
|
||||
}
|
||||
ret = -EINVAL;
|
||||
unmapped = 0;
|
||||
break;
|
||||
}
|
||||
dma->vaddr_invalid = true;
|
||||
iommu->vaddr_invalid_count++;
|
||||
unmapped += dma->size;
|
||||
n = rb_next(n);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!RB_EMPTY_ROOT(&dma->pfn_list)) {
|
||||
struct vfio_iommu_type1_dma_unmap nb_unmap;
|
||||
|
||||
|
@ -1330,6 +1356,7 @@ static bool vfio_iommu_iova_dma_valid(struct vfio_iommu *iommu,
|
|||
static int vfio_dma_do_map(struct vfio_iommu *iommu,
|
||||
struct vfio_iommu_type1_dma_map *map)
|
||||
{
|
||||
bool set_vaddr = map->flags & VFIO_DMA_MAP_FLAG_VADDR;
|
||||
dma_addr_t iova = map->iova;
|
||||
unsigned long vaddr = map->vaddr;
|
||||
size_t size = map->size;
|
||||
|
@ -1347,13 +1374,16 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
|
|||
if (map->flags & VFIO_DMA_MAP_FLAG_READ)
|
||||
prot |= IOMMU_READ;
|
||||
|
||||
if ((prot && set_vaddr) || (!prot && !set_vaddr))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&iommu->lock);
|
||||
|
||||
pgsize = (size_t)1 << __ffs(iommu->pgsize_bitmap);
|
||||
|
||||
WARN_ON((pgsize - 1) & PAGE_MASK);
|
||||
|
||||
if (!prot || !size || (size | iova | vaddr) & (pgsize - 1)) {
|
||||
if (!size || (size | iova | vaddr) & (pgsize - 1)) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
@ -1364,7 +1394,20 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (vfio_find_dma(iommu, iova, size)) {
|
||||
dma = vfio_find_dma(iommu, iova, size);
|
||||
if (set_vaddr) {
|
||||
if (!dma) {
|
||||
ret = -ENOENT;
|
||||
} else if (!dma->vaddr_invalid || dma->iova != iova ||
|
||||
dma->size != size) {
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
dma->vaddr = vaddr;
|
||||
dma->vaddr_invalid = false;
|
||||
iommu->vaddr_invalid_count--;
|
||||
}
|
||||
goto out_unlock;
|
||||
} else if (dma) {
|
||||
ret = -EEXIST;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
@ -2549,6 +2592,7 @@ static int vfio_iommu_type1_check_extension(struct vfio_iommu *iommu,
|
|||
case VFIO_TYPE1v2_IOMMU:
|
||||
case VFIO_TYPE1_NESTING_IOMMU:
|
||||
case VFIO_UNMAP_ALL:
|
||||
case VFIO_UPDATE_VADDR:
|
||||
return 1;
|
||||
case VFIO_DMA_CC_IOMMU:
|
||||
if (!iommu)
|
||||
|
@ -2720,7 +2764,8 @@ static int vfio_iommu_type1_map_dma(struct vfio_iommu *iommu,
|
|||
{
|
||||
struct vfio_iommu_type1_dma_map map;
|
||||
unsigned long minsz;
|
||||
uint32_t mask = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
|
||||
uint32_t mask = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE |
|
||||
VFIO_DMA_MAP_FLAG_VADDR;
|
||||
|
||||
minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
|
||||
|
||||
|
@ -2739,6 +2784,7 @@ static int vfio_iommu_type1_unmap_dma(struct vfio_iommu *iommu,
|
|||
struct vfio_iommu_type1_dma_unmap unmap;
|
||||
struct vfio_bitmap bitmap = { 0 };
|
||||
uint32_t mask = VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP |
|
||||
VFIO_DMA_UNMAP_FLAG_VADDR |
|
||||
VFIO_DMA_UNMAP_FLAG_ALL;
|
||||
unsigned long minsz;
|
||||
int ret;
|
||||
|
@ -2752,7 +2798,8 @@ static int vfio_iommu_type1_unmap_dma(struct vfio_iommu *iommu,
|
|||
return -EINVAL;
|
||||
|
||||
if ((unmap.flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) &&
|
||||
(unmap.flags & VFIO_DMA_UNMAP_FLAG_ALL))
|
||||
(unmap.flags & (VFIO_DMA_UNMAP_FLAG_ALL |
|
||||
VFIO_DMA_UNMAP_FLAG_VADDR)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unmap.flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) {
|
||||
|
|
Loading…
Reference in New Issue