Skip to content

Commit 258edb7

Browse files
committed
vfio/type1: Use vfio_batch for vaddr_get_pfns()
jira LE-3557 Rebuild_History Non-Buildable kernel-5.14.0-570.26.1.el9_6 commit-author Alex Williamson <[email protected]> commit eb996ee Passing the vfio_batch to vaddr_get_pfns() allows for greater distinction between page backed pfns and pfnmaps. In the case of page backed pfns, vfio_batch.size is set to a positive value matching the number of pages filled in vfio_batch.pages. For a pfnmap, vfio_batch.size remains zero as vfio_batch.pages are not used. In both cases the return value continues to indicate the number of pfns and the provided pfn arg is set to the initial pfn value. This allows us to shortcut the pfnmap case, which is detected by the zero vfio_batch.size. pfnmaps do not contribute to locked memory accounting, therefore we can update counters and continue directly, which also enables a future where vaddr_get_pfns() can return a value greater than one for consecutive pfnmaps. NB. Now that we're not guessing whether the initial pfn is page backed or pfnmap, we no longer need to special case the put_pfn() and batch size reset. It's safe for vfio_batch_unpin() to handle this case. Reviewed-by: Peter Xu <[email protected]> Reviewed-by: Mitchell Augustin <[email protected]> Tested-by: Mitchell Augustin <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alex Williamson <[email protected]> (cherry picked from commit eb996ee) Signed-off-by: Jonathan Maple <[email protected]>
1 parent 7ce8549 commit 258edb7

File tree

1 file changed

+35
-28
lines changed

1 file changed

+35
-28
lines changed

drivers/vfio/vfio_iommu_type1.c

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -562,12 +562,16 @@ static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm,
562562

563563
/*
564564
* Returns the positive number of pfns successfully obtained or a negative
565-
* error code.
565+
* error code. The initial pfn is stored in the pfn arg. For page-backed
566+
* pfns, the provided batch is also updated to indicate the filled pages and
567+
* initial offset. For VM_PFNMAP pfns, only the returned number of pfns and
568+
* returned initial pfn are provided; subsequent pfns are contiguous.
566569
*/
567570
static int vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
568571
long npages, int prot, unsigned long *pfn,
569-
struct page **pages)
572+
struct vfio_batch *batch)
570573
{
574+
long pin_pages = min_t(long, npages, batch->capacity);
571575
struct vm_area_struct *vma;
572576
unsigned int flags = 0;
573577
int ret;
@@ -576,10 +580,12 @@ static int vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
576580
flags |= FOLL_WRITE;
577581

578582
mmap_read_lock(mm);
579-
ret = pin_user_pages_remote(mm, vaddr, npages, flags | FOLL_LONGTERM,
580-
pages, NULL);
583+
ret = pin_user_pages_remote(mm, vaddr, pin_pages, flags | FOLL_LONGTERM,
584+
batch->pages, NULL);
581585
if (ret > 0) {
582-
*pfn = page_to_pfn(pages[0]);
586+
*pfn = page_to_pfn(batch->pages[0]);
587+
batch->size = ret;
588+
batch->offset = 0;
583589
goto done;
584590
} else if (!ret) {
585591
ret = -EFAULT;
@@ -635,32 +641,42 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr,
635641
*pfn_base = 0;
636642
}
637643

644+
if (unlikely(disable_hugepages))
645+
npage = 1;
646+
638647
while (npage) {
639648
if (!batch->size) {
640649
/* Empty batch, so refill it. */
641-
long req_pages = min_t(long, npage, batch->capacity);
642-
643-
ret = vaddr_get_pfns(mm, vaddr, req_pages, dma->prot,
644-
&pfn, batch->pages);
650+
ret = vaddr_get_pfns(mm, vaddr, npage, dma->prot,
651+
&pfn, batch);
645652
if (ret < 0)
646653
goto unpin_out;
647654

648-
batch->size = ret;
649-
batch->offset = 0;
650-
651655
if (!*pfn_base) {
652656
*pfn_base = pfn;
653657
rsvd = is_invalid_reserved_pfn(*pfn_base);
654658
}
659+
660+
/* Handle pfnmap */
661+
if (!batch->size) {
662+
if (pfn != *pfn_base + pinned || !rsvd)
663+
goto out;
664+
665+
pinned += ret;
666+
npage -= ret;
667+
vaddr += (PAGE_SIZE * ret);
668+
iova += (PAGE_SIZE * ret);
669+
continue;
670+
}
655671
}
656672

657673
/*
658-
* pfn is preset for the first iteration of this inner loop and
659-
* updated at the end to handle a VM_PFNMAP pfn. In that case,
660-
* batch->pages isn't valid (there's no struct page), so allow
661-
* batch->pages to be touched only when there's more than one
662-
* pfn to check, which guarantees the pfns are from a
663-
* !VM_PFNMAP vma.
674+
* pfn is preset for the first iteration of this inner loop
675+
* due to the fact that vaddr_get_pfns() needs to provide the
676+
* initial pfn for pfnmaps. Therefore to reduce redundancy,
677+
* the next pfn is fetched at the end of the loop.
678+
* A PageReserved() page could still qualify as page backed
679+
* and rsvd here, and therefore continues to use the batch.
664680
*/
665681
while (true) {
666682
if (pfn != *pfn_base + pinned ||
@@ -695,21 +711,12 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr,
695711

696712
pfn = page_to_pfn(batch->pages[batch->offset]);
697713
}
698-
699-
if (unlikely(disable_hugepages))
700-
break;
701714
}
702715

703716
out:
704717
ret = vfio_lock_acct(dma, lock_acct, false);
705718

706719
unpin_out:
707-
if (batch->size == 1 && !batch->offset) {
708-
/* May be a VM_PFNMAP pfn, which the batch can't remember. */
709-
put_pfn(pfn, dma->prot);
710-
batch->size = 0;
711-
}
712-
713720
if (ret < 0) {
714721
if (pinned && !rsvd) {
715722
for (pfn = *pfn_base ; pinned ; pfn++, pinned--)
@@ -757,7 +764,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr,
757764

758765
vfio_batch_init_single(&batch);
759766

760-
ret = vaddr_get_pfns(mm, vaddr, 1, dma->prot, pfn_base, batch.pages);
767+
ret = vaddr_get_pfns(mm, vaddr, 1, dma->prot, pfn_base, &batch);
761768
if (ret != 1)
762769
goto out;
763770

0 commit comments

Comments
 (0)