Message ID | 20250218222209.1382449-7-alex.williamson@redhat.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | vfio: Improve DMA mapping performance for huge pfnmaps | expand |
On Tue, Feb 18, 2025 at 03:22:06PM -0700, Alex Williamson wrote: > vfio-pci supports huge_fault for PCI MMIO BARs and will insert pud and > pmd mappings for well aligned mappings. follow_pfnmap_start() walks the > page table and therefore knows the page mask of the level where the > address is found and returns this through follow_pfnmap_args.pgmask. > Subsequent pfns from this address until the end of the mapping page are > necessarily consecutive. Use this information to retrieve a range of > pfnmap pfns in a single pass. > > With optimal mappings and alignment on systems with 1GB pud and 4KB > page size, this reduces iterations for DMA mapping PCI BARs by a > factor of 256K. In real world testing, the overhead of iterating > pfns for a VM DMA mapping a 32GB PCI BAR is reduced from ~1s to > sub-millisecond overhead. > > Signed-off-by: Alex Williamson <alex.williamson@redhat.com> > --- > drivers/vfio/vfio_iommu_type1.c | 23 ++++++++++++++++------- > 1 file changed, 16 insertions(+), 7 deletions(-) > > diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c > index ce661f03f139..0ac56072af9f 100644 > --- a/drivers/vfio/vfio_iommu_type1.c > +++ b/drivers/vfio/vfio_iommu_type1.c > @@ -520,7 +520,7 @@ static void vfio_batch_fini(struct vfio_batch *batch) > > static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm, > unsigned long vaddr, unsigned long *pfn, > - bool write_fault) > + unsigned long *addr_mask, bool write_fault) > { > struct follow_pfnmap_args args = { .vma = vma, .address = vaddr }; > int ret; > @@ -544,10 +544,12 @@ static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm, > return ret; > } > > - if (write_fault && !args.writable) > + if (write_fault && !args.writable) { > ret = -EFAULT; > - else > + } else { > *pfn = args.pfn; > + *addr_mask = args.addr_mask; > + } > > follow_pfnmap_end(&args); > return ret; > @@ -590,15 +592,22 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr, > vma = vma_lookup(mm, vaddr); > > if (vma && vma->vm_flags & VM_PFNMAP) { > - ret = follow_fault_pfn(vma, mm, vaddr, pfn, prot & IOMMU_WRITE); > + unsigned long addr_mask; > + > + ret = follow_fault_pfn(vma, mm, vaddr, pfn, &addr_mask, > + prot & IOMMU_WRITE); > if (ret == -EAGAIN) > goto retry; > > if (!ret) { > - if (is_invalid_reserved_pfn(*pfn)) > - ret = 1; > - else > + if (is_invalid_reserved_pfn(*pfn)) { > + unsigned long epfn; > + > + epfn = (*pfn | (~addr_mask >> PAGE_SHIFT)) + 1; > + ret = min_t(long, npages, epfn - *pfn); s/long/unsigned long/? Reviewed-by: Peter Xu <peterx@redhat.com> > + } else { > ret = -EFAULT; > + } > } > } > done: > -- > 2.48.1 >
On Tue, 18 Feb 2025 17:47:46 -0500 Peter Xu <peterx@redhat.com> wrote: > On Tue, Feb 18, 2025 at 03:22:06PM -0700, Alex Williamson wrote: > > vfio-pci supports huge_fault for PCI MMIO BARs and will insert pud and > > pmd mappings for well aligned mappings. follow_pfnmap_start() walks the > > page table and therefore knows the page mask of the level where the > > address is found and returns this through follow_pfnmap_args.pgmask. > > Subsequent pfns from this address until the end of the mapping page are > > necessarily consecutive. Use this information to retrieve a range of > > pfnmap pfns in a single pass. > > > > With optimal mappings and alignment on systems with 1GB pud and 4KB > > page size, this reduces iterations for DMA mapping PCI BARs by a > > factor of 256K. In real world testing, the overhead of iterating > > pfns for a VM DMA mapping a 32GB PCI BAR is reduced from ~1s to > > sub-millisecond overhead. > > > > Signed-off-by: Alex Williamson <alex.williamson@redhat.com> > > --- > > drivers/vfio/vfio_iommu_type1.c | 23 ++++++++++++++++------- > > 1 file changed, 16 insertions(+), 7 deletions(-) > > > > diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c > > index ce661f03f139..0ac56072af9f 100644 > > --- a/drivers/vfio/vfio_iommu_type1.c > > +++ b/drivers/vfio/vfio_iommu_type1.c > > @@ -520,7 +520,7 @@ static void vfio_batch_fini(struct vfio_batch *batch) > > > > static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm, > > unsigned long vaddr, unsigned long *pfn, > > - bool write_fault) > > + unsigned long *addr_mask, bool write_fault) > > { > > struct follow_pfnmap_args args = { .vma = vma, .address = vaddr }; > > int ret; > > @@ -544,10 +544,12 @@ static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm, > > return ret; > > } > > > > - if (write_fault && !args.writable) > > + if (write_fault && !args.writable) { > > ret = -EFAULT; > > - else > > + } else { > > *pfn = args.pfn; > > + *addr_mask = args.addr_mask; > > + } > > > > follow_pfnmap_end(&args); > > return ret; > > @@ -590,15 +592,22 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr, > > vma = vma_lookup(mm, vaddr); > > > > if (vma && vma->vm_flags & VM_PFNMAP) { > > - ret = follow_fault_pfn(vma, mm, vaddr, pfn, prot & IOMMU_WRITE); > > + unsigned long addr_mask; > > + > > + ret = follow_fault_pfn(vma, mm, vaddr, pfn, &addr_mask, > > + prot & IOMMU_WRITE); > > if (ret == -EAGAIN) > > goto retry; > > > > if (!ret) { > > - if (is_invalid_reserved_pfn(*pfn)) > > - ret = 1; > > - else > > + if (is_invalid_reserved_pfn(*pfn)) { > > + unsigned long epfn; > > + > > + epfn = (*pfn | (~addr_mask >> PAGE_SHIFT)) + 1; > > + ret = min_t(long, npages, epfn - *pfn); > > s/long/unsigned long/? ret is signed long since it's the function return and needs to be able to return -errno, so long was the intention here. Thanks, Alex > Reviewed-by: Peter Xu <peterx@redhat.com> > > > + } else { > > ret = -EFAULT; > > + } > > } > > } > > done: > > -- > > 2.48.1 > > >
/s/follow_pfnmap_args.pgmask/follow_pfnmap_args.addr_mask/ in v2 commit log. Aside from that, it works as expected. Reviewed-by: "Mitchell Augustin" <mitchell.augustin@canonical.com> Tested-by: "Mitchell Augustin" <mitchell.augustin@canonical.com> On Tue, Feb 18, 2025 at 5:14 PM Alex Williamson <alex.williamson@redhat.com> wrote: > > On Tue, 18 Feb 2025 17:47:46 -0500 > Peter Xu <peterx@redhat.com> wrote: > > > On Tue, Feb 18, 2025 at 03:22:06PM -0700, Alex Williamson wrote: > > > vfio-pci supports huge_fault for PCI MMIO BARs and will insert pud and > > > pmd mappings for well aligned mappings. follow_pfnmap_start() walks the > > > page table and therefore knows the page mask of the level where the > > > address is found and returns this through follow_pfnmap_args.pgmask. > > > Subsequent pfns from this address until the end of the mapping page are > > > necessarily consecutive. Use this information to retrieve a range of > > > pfnmap pfns in a single pass. > > > > > > With optimal mappings and alignment on systems with 1GB pud and 4KB > > > page size, this reduces iterations for DMA mapping PCI BARs by a > > > factor of 256K. In real world testing, the overhead of iterating > > > pfns for a VM DMA mapping a 32GB PCI BAR is reduced from ~1s to > > > sub-millisecond overhead. > > > > > > Signed-off-by: Alex Williamson <alex.williamson@redhat.com> > > > --- > > > drivers/vfio/vfio_iommu_type1.c | 23 ++++++++++++++++------- > > > 1 file changed, 16 insertions(+), 7 deletions(-) > > > > > > diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c > > > index ce661f03f139..0ac56072af9f 100644 > > > --- a/drivers/vfio/vfio_iommu_type1.c > > > +++ b/drivers/vfio/vfio_iommu_type1.c > > > @@ -520,7 +520,7 @@ static void vfio_batch_fini(struct vfio_batch *batch) > > > > > > static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm, > > > unsigned long vaddr, unsigned long *pfn, > > > - bool write_fault) > > > + unsigned long *addr_mask, bool write_fault) > > > { > > > struct follow_pfnmap_args args = { .vma = vma, .address = vaddr }; > > > int ret; > > > @@ -544,10 +544,12 @@ static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm, > > > return ret; > > > } > > > > > > - if (write_fault && !args.writable) > > > + if (write_fault && !args.writable) { > > > ret = -EFAULT; > > > - else > > > + } else { > > > *pfn = args.pfn; > > > + *addr_mask = args.addr_mask; > > > + } > > > > > > follow_pfnmap_end(&args); > > > return ret; > > > @@ -590,15 +592,22 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr, > > > vma = vma_lookup(mm, vaddr); > > > > > > if (vma && vma->vm_flags & VM_PFNMAP) { > > > - ret = follow_fault_pfn(vma, mm, vaddr, pfn, prot & IOMMU_WRITE); > > > + unsigned long addr_mask; > > > + > > > + ret = follow_fault_pfn(vma, mm, vaddr, pfn, &addr_mask, > > > + prot & IOMMU_WRITE); > > > if (ret == -EAGAIN) > > > goto retry; > > > > > > if (!ret) { > > > - if (is_invalid_reserved_pfn(*pfn)) > > > - ret = 1; > > > - else > > > + if (is_invalid_reserved_pfn(*pfn)) { > > > + unsigned long epfn; > > > + > > > + epfn = (*pfn | (~addr_mask >> PAGE_SHIFT)) + 1; > > > + ret = min_t(long, npages, epfn - *pfn); > > > > s/long/unsigned long/? > > ret is signed long since it's the function return and needs to be able > to return -errno, so long was the intention here. Thanks, > > Alex > > > Reviewed-by: Peter Xu <peterx@redhat.com> > > > > > + } else { > > > ret = -EFAULT; > > > + } > > > } > > > } > > > done: > > > -- > > > 2.48.1 > > > > > > -- Mitchell Augustin Software Engineer - Ubuntu Partner Engineering
On Tue, 18 Feb 2025 20:36:22 -0600 Mitchell Augustin <mitchell.augustin@canonical.com> wrote: > /s/follow_pfnmap_args.pgmask/follow_pfnmap_args.addr_mask/ in v2 > commit log. Thanks for spotting that, if there's no other cause for a re-spin I'll fix that on commit. Thanks for the review and testing! Alex > Aside from that, it works as expected. > > Reviewed-by: "Mitchell Augustin" <mitchell.augustin@canonical.com> > Tested-by: "Mitchell Augustin" <mitchell.augustin@canonical.com> > > > On Tue, Feb 18, 2025 at 5:14 PM Alex Williamson > <alex.williamson@redhat.com> wrote: > > > > On Tue, 18 Feb 2025 17:47:46 -0500 > > Peter Xu <peterx@redhat.com> wrote: > > > > > On Tue, Feb 18, 2025 at 03:22:06PM -0700, Alex Williamson wrote: > > > > vfio-pci supports huge_fault for PCI MMIO BARs and will insert pud and > > > > pmd mappings for well aligned mappings. follow_pfnmap_start() walks the > > > > page table and therefore knows the page mask of the level where the > > > > address is found and returns this through follow_pfnmap_args.pgmask. > > > > Subsequent pfns from this address until the end of the mapping page are > > > > necessarily consecutive. Use this information to retrieve a range of > > > > pfnmap pfns in a single pass. > > > > > > > > With optimal mappings and alignment on systems with 1GB pud and 4KB > > > > page size, this reduces iterations for DMA mapping PCI BARs by a > > > > factor of 256K. In real world testing, the overhead of iterating > > > > pfns for a VM DMA mapping a 32GB PCI BAR is reduced from ~1s to > > > > sub-millisecond overhead. > > > > > > > > Signed-off-by: Alex Williamson <alex.williamson@redhat.com> > > > > --- > > > > drivers/vfio/vfio_iommu_type1.c | 23 ++++++++++++++++------- > > > > 1 file changed, 16 insertions(+), 7 deletions(-) > > > > > > > > diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c > > > > index ce661f03f139..0ac56072af9f 100644 > > > > --- a/drivers/vfio/vfio_iommu_type1.c > > > > +++ b/drivers/vfio/vfio_iommu_type1.c > > > > @@ -520,7 +520,7 @@ static void vfio_batch_fini(struct vfio_batch *batch) > > > > > > > > static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm, > > > > unsigned long vaddr, unsigned long *pfn, > > > > - bool write_fault) > > > > + unsigned long *addr_mask, bool write_fault) > > > > { > > > > struct follow_pfnmap_args args = { .vma = vma, .address = vaddr }; > > > > int ret; > > > > @@ -544,10 +544,12 @@ static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm, > > > > return ret; > > > > } > > > > > > > > - if (write_fault && !args.writable) > > > > + if (write_fault && !args.writable) { > > > > ret = -EFAULT; > > > > - else > > > > + } else { > > > > *pfn = args.pfn; > > > > + *addr_mask = args.addr_mask; > > > > + } > > > > > > > > follow_pfnmap_end(&args); > > > > return ret; > > > > @@ -590,15 +592,22 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr, > > > > vma = vma_lookup(mm, vaddr); > > > > > > > > if (vma && vma->vm_flags & VM_PFNMAP) { > > > > - ret = follow_fault_pfn(vma, mm, vaddr, pfn, prot & IOMMU_WRITE); > > > > + unsigned long addr_mask; > > > > + > > > > + ret = follow_fault_pfn(vma, mm, vaddr, pfn, &addr_mask, > > > > + prot & IOMMU_WRITE); > > > > if (ret == -EAGAIN) > > > > goto retry; > > > > > > > > if (!ret) { > > > > - if (is_invalid_reserved_pfn(*pfn)) > > > > - ret = 1; > > > > - else > > > > + if (is_invalid_reserved_pfn(*pfn)) { > > > > + unsigned long epfn; > > > > + > > > > + epfn = (*pfn | (~addr_mask >> PAGE_SHIFT)) + 1; > > > > + ret = min_t(long, npages, epfn - *pfn); > > > > > > s/long/unsigned long/? > > > > ret is signed long since it's the function return and needs to be able > > to return -errno, so long was the intention here. Thanks, > > > > Alex > > > > > Reviewed-by: Peter Xu <peterx@redhat.com> > > > > > > > + } else { > > > > ret = -EFAULT; > > > > + } > > > > } > > > > } > > > > done: > > > > -- > > > > 2.48.1 > > > > > > > > > > > > -- > Mitchell Augustin > Software Engineer - Ubuntu Partner Engineering >
> Thanks for the review and testing! Sure thing, thanks for the patch set! If you happen to have a few minutes, I'm struggling to understand the epfn computation and would appreciate some insight. My current understanding (very possibly incorrect): - epfn is intended to be the last page frame number that can be represented at the mapping level corresponding to addr_mask. (so, if addr_mask == PUD_MASK, epfn would be the highest pfn still in PUD level). - ret should be == npages if all pfns in the requested vma are within the memory hierarchy level denoted by addr_mask. If npages is more than can be represented at that level, ret == the max number of page frames representable at addr_mask level. - - (if the second case is true, that means we were not able to obtain all requested pages due to running out of PFNs at the current mapping level) If the above is all correct, what is confusing me is where the "(*pfn) | " comes into this equation. If epfn is meant to be the last pfn representable at addr_mask level of the hierarchy, wouldn't that be represented by (~pgmask >> PAGE_SHIFT) alone? Thanks in advance, Mitchell Augustin On Wed, Feb 19, 2025 at 9:08 AM Alex Williamson <alex.williamson@redhat.com> wrote: > > On Tue, 18 Feb 2025 20:36:22 -0600 > Mitchell Augustin <mitchell.augustin@canonical.com> wrote: > > > /s/follow_pfnmap_args.pgmask/follow_pfnmap_args.addr_mask/ in v2 > > commit log. > > Thanks for spotting that, if there's no other cause for a re-spin I'll > fix that on commit. Thanks for the review and testing! > > Alex > > > Aside from that, it works as expected. > > > > Reviewed-by: "Mitchell Augustin" <mitchell.augustin@canonical.com> > > Tested-by: "Mitchell Augustin" <mitchell.augustin@canonical.com> > > > > > > On Tue, Feb 18, 2025 at 5:14 PM Alex Williamson > > <alex.williamson@redhat.com> wrote: > > > > > > On Tue, 18 Feb 2025 17:47:46 -0500 > > > Peter Xu <peterx@redhat.com> wrote: > > > > > > > On Tue, Feb 18, 2025 at 03:22:06PM -0700, Alex Williamson wrote: > > > > > vfio-pci supports huge_fault for PCI MMIO BARs and will insert pud and > > > > > pmd mappings for well aligned mappings. follow_pfnmap_start() walks the > > > > > page table and therefore knows the page mask of the level where the > > > > > address is found and returns this through follow_pfnmap_args.pgmask. > > > > > Subsequent pfns from this address until the end of the mapping page are > > > > > necessarily consecutive. Use this information to retrieve a range of > > > > > pfnmap pfns in a single pass. > > > > > > > > > > With optimal mappings and alignment on systems with 1GB pud and 4KB > > > > > page size, this reduces iterations for DMA mapping PCI BARs by a > > > > > factor of 256K. In real world testing, the overhead of iterating > > > > > pfns for a VM DMA mapping a 32GB PCI BAR is reduced from ~1s to > > > > > sub-millisecond overhead. > > > > > > > > > > Signed-off-by: Alex Williamson <alex.williamson@redhat.com> > > > > > --- > > > > > drivers/vfio/vfio_iommu_type1.c | 23 ++++++++++++++++------- > > > > > 1 file changed, 16 insertions(+), 7 deletions(-) > > > > > > > > > > diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c > > > > > index ce661f03f139..0ac56072af9f 100644 > > > > > --- a/drivers/vfio/vfio_iommu_type1.c > > > > > +++ b/drivers/vfio/vfio_iommu_type1.c > > > > > @@ -520,7 +520,7 @@ static void vfio_batch_fini(struct vfio_batch *batch) > > > > > > > > > > static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm, > > > > > unsigned long vaddr, unsigned long *pfn, > > > > > - bool write_fault) > > > > > + unsigned long *addr_mask, bool write_fault) > > > > > { > > > > > struct follow_pfnmap_args args = { .vma = vma, .address = vaddr }; > > > > > int ret; > > > > > @@ -544,10 +544,12 @@ static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm, > > > > > return ret; > > > > > } > > > > > > > > > > - if (write_fault && !args.writable) > > > > > + if (write_fault && !args.writable) { > > > > > ret = -EFAULT; > > > > > - else > > > > > + } else { > > > > > *pfn = args.pfn; > > > > > + *addr_mask = args.addr_mask; > > > > > + } > > > > > > > > > > follow_pfnmap_end(&args); > > > > > return ret; > > > > > @@ -590,15 +592,22 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr, > > > > > vma = vma_lookup(mm, vaddr); > > > > > > > > > > if (vma && vma->vm_flags & VM_PFNMAP) { > > > > > - ret = follow_fault_pfn(vma, mm, vaddr, pfn, prot & IOMMU_WRITE); > > > > > + unsigned long addr_mask; > > > > > + > > > > > + ret = follow_fault_pfn(vma, mm, vaddr, pfn, &addr_mask, > > > > > + prot & IOMMU_WRITE); > > > > > if (ret == -EAGAIN) > > > > > goto retry; > > > > > > > > > > if (!ret) { > > > > > - if (is_invalid_reserved_pfn(*pfn)) > > > > > - ret = 1; > > > > > - else > > > > > + if (is_invalid_reserved_pfn(*pfn)) { > > > > > + unsigned long epfn; > > > > > + > > > > > + epfn = (*pfn | (~addr_mask >> PAGE_SHIFT)) + 1; > > > > > + ret = min_t(long, npages, epfn - *pfn); > > > > > > > > s/long/unsigned long/? > > > > > > ret is signed long since it's the function return and needs to be able > > > to return -errno, so long was the intention here. Thanks, > > > > > > Alex > > > > > > > Reviewed-by: Peter Xu <peterx@redhat.com> > > > > > > > > > + } else { > > > > > ret = -EFAULT; > > > > > + } > > > > > } > > > > > } > > > > > done: > > > > > -- > > > > > 2.48.1 > > > > > > > > > > > > > > > > > > -- > > Mitchell Augustin > > Software Engineer - Ubuntu Partner Engineering > > >
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index ce661f03f139..0ac56072af9f 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -520,7 +520,7 @@ static void vfio_batch_fini(struct vfio_batch *batch) static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm, unsigned long vaddr, unsigned long *pfn, - bool write_fault) + unsigned long *addr_mask, bool write_fault) { struct follow_pfnmap_args args = { .vma = vma, .address = vaddr }; int ret; @@ -544,10 +544,12 @@ static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm, return ret; } - if (write_fault && !args.writable) + if (write_fault && !args.writable) { ret = -EFAULT; - else + } else { *pfn = args.pfn; + *addr_mask = args.addr_mask; + } follow_pfnmap_end(&args); return ret; @@ -590,15 +592,22 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr, vma = vma_lookup(mm, vaddr); if (vma && vma->vm_flags & VM_PFNMAP) { - ret = follow_fault_pfn(vma, mm, vaddr, pfn, prot & IOMMU_WRITE); + unsigned long addr_mask; + + ret = follow_fault_pfn(vma, mm, vaddr, pfn, &addr_mask, + prot & IOMMU_WRITE); if (ret == -EAGAIN) goto retry; if (!ret) { - if (is_invalid_reserved_pfn(*pfn)) - ret = 1; - else + if (is_invalid_reserved_pfn(*pfn)) { + unsigned long epfn; + + epfn = (*pfn | (~addr_mask >> PAGE_SHIFT)) + 1; + ret = min_t(long, npages, epfn - *pfn); + } else { ret = -EFAULT; + } } } done:
vfio-pci supports huge_fault for PCI MMIO BARs and will insert pud and pmd mappings for well aligned mappings. follow_pfnmap_start() walks the page table and therefore knows the page mask of the level where the address is found and returns this through follow_pfnmap_args.pgmask. Subsequent pfns from this address until the end of the mapping page are necessarily consecutive. Use this information to retrieve a range of pfnmap pfns in a single pass. With optimal mappings and alignment on systems with 1GB pud and 4KB page size, this reduces iterations for DMA mapping PCI BARs by a factor of 256K. In real world testing, the overhead of iterating pfns for a VM DMA mapping a 32GB PCI BAR is reduced from ~1s to sub-millisecond overhead. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> --- drivers/vfio/vfio_iommu_type1.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-)