On Tue, 19 Jan 2021 09:48:24 -0800 Steve Sistare <steven.sistare@xxxxxxxxxx> wrote: > Implement VFIO_DMA_UNMAP_FLAG_ALL. > > Signed-off-by: Steve Sistare <steven.sistare@xxxxxxxxxx> > --- > drivers/vfio/vfio_iommu_type1.c | 22 +++++++++++++++++----- > 1 file changed, 17 insertions(+), 5 deletions(-) > > diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c > index c687174..ef83018 100644 > --- a/drivers/vfio/vfio_iommu_type1.c > +++ b/drivers/vfio/vfio_iommu_type1.c > @@ -1100,6 +1100,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu, > unsigned long pgshift; > dma_addr_t iova = unmap->iova; > unsigned long size = unmap->size; > + bool unmap_all = !!(unmap->flags & VFIO_DMA_UNMAP_FLAG_ALL); > > mutex_lock(&iommu->lock); > > @@ -1109,8 +1110,13 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu, > if (iova & (pgsize - 1)) > goto unlock; > > - if (!size || size & (pgsize - 1)) > + if (unmap_all) { > + if (iova || size) > + goto unlock; > + size = SIZE_MAX; > + } else if (!size || size & (pgsize - 1)) { > goto unlock; > + } > > if (iova + size - 1 < iova || size > SIZE_MAX) > goto unlock; > @@ -1154,7 +1160,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu, > * will only return success and a size of zero if there were no > * mappings within the range. > */ > - if (iommu->v2) { > + if (iommu->v2 && !unmap_all) { > dma = vfio_find_dma(iommu, iova, 1); > if (dma && dma->iova != iova) > goto unlock; > @@ -1165,7 +1171,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu, > } > > ret = 0; > - while ((dma = vfio_find_dma(iommu, iova, size))) { > + while ((dma = vfio_find_dma_first(iommu, iova, size))) { Why is this necessary? Isn't vfio_find_dma_first() O(logN) for this operation while vfio_find_dma() is O(1)? > if (!iommu->v2 && iova > dma->iova) > break; > /* > @@ -2538,6 +2544,7 @@ static int vfio_iommu_type1_check_extension(struct vfio_iommu *iommu, > case VFIO_TYPE1_IOMMU: > case VFIO_TYPE1v2_IOMMU: > case VFIO_TYPE1_NESTING_IOMMU: > + case VFIO_UNMAP_ALL: > return 1; > case VFIO_DMA_CC_IOMMU: > if (!iommu) > @@ -2710,6 +2717,8 @@ 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_ALL; > unsigned long minsz; > int ret; > > @@ -2718,8 +2727,11 @@ static int vfio_iommu_type1_unmap_dma(struct vfio_iommu *iommu, > if (copy_from_user(&unmap, (void __user *)arg, minsz)) > return -EFAULT; > > - if (unmap.argsz < minsz || > - unmap.flags & ~VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) > + if (unmap.argsz < minsz || unmap.flags & ~mask) > + return -EINVAL; > + > + if ((unmap.flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) && > + (unmap.flags & ~VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP)) Somehow we're jumping from unmap-all and dirty-bitmap being mutually exclusive to dirty-bitmap is absolutely exclusive, which seems like a future bug or maintenance issue. Let's just test specifically what we're deciding is unsupported. Thanks, Alex > return -EINVAL; > > if (unmap.flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) {