Message ID | 1611078509-181959-5-git-send-email-steven.sistare@oracle.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | vfio virtual address update | expand |
On Tue, 19 Jan 2021 09:48:24 -0800 Steve Sistare <steven.sistare@oracle.com> wrote: > Implement VFIO_DMA_UNMAP_FLAG_ALL. > > Signed-off-by: Steve Sistare <steven.sistare@oracle.com> > --- > 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) {
On 1/22/2021 4:22 PM, Alex Williamson wrote: > On Tue, 19 Jan 2021 09:48:24 -0800 > Steve Sistare <steven.sistare@oracle.com> wrote: > >> Implement VFIO_DMA_UNMAP_FLAG_ALL. >> >> Signed-off-by: Steve Sistare <steven.sistare@oracle.com> >> --- >> 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)? True, vfio_find_dma is O(1) for unmap-all, and find-first is not needed until a later patch. I'll continue discussing this issue in my response to your next email. >> 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, OK, I will make it future proof. - Steve return -EINVAL; >> >> if (unmap.flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) { >
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))) { 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)) return -EINVAL; if (unmap.flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) {
Implement VFIO_DMA_UNMAP_FLAG_ALL. Signed-off-by: Steve Sistare <steven.sistare@oracle.com> --- drivers/vfio/vfio_iommu_type1.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)