aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Cai (Xiang Feng) <jason.cai@linux.alibaba.com>2018-03-22 00:52:16 -0400
committerAlex Williamson <alex.williamson@redhat.com>2018-03-22 15:18:27 -0400
commit356e88ebe4473a3663cf3d14727ce293a4526d34 (patch)
treee261e27c7ed605750677e610ae7d66dec2d1157c
parentc9f89c3f87cfc026d88c08054710902dd52a7772 (diff)
vfio/type1: Improve memory pinning process for raw PFN mapping
When using vfio to pass through a PCIe device (e.g. a GPU card) that has a huge BAR (e.g. 16GB), a lot of cycles are wasted on memory pinning because PFNs of PCI BAR are not backed by struct page, and the corresponding VMA has flag VM_PFNMAP. With this change, when pinning a region which is a raw PFN mapping, it can skip unnecessary user memory pinning process, and thus, can significantly improve VM's boot up time when passing through devices via VFIO. In my test on a Xeon E5 2.6GHz, the time mapping a 16GB BAR was reduced from about 0.4s to 1.5us. Signed-off-by: Jason Cai (Xiang Feng) <jason.cai@linux.alibaba.com> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
-rw-r--r--drivers/vfio/vfio_iommu_type1.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 3c082451ab1a..5c212bf29640 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -404,7 +404,6 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr,
404{ 404{
405 unsigned long pfn = 0; 405 unsigned long pfn = 0;
406 long ret, pinned = 0, lock_acct = 0; 406 long ret, pinned = 0, lock_acct = 0;
407 bool rsvd;
408 dma_addr_t iova = vaddr - dma->vaddr + dma->iova; 407 dma_addr_t iova = vaddr - dma->vaddr + dma->iova;
409 408
410 /* This code path is only user initiated */ 409 /* This code path is only user initiated */
@@ -415,14 +414,23 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr,
415 if (ret) 414 if (ret)
416 return ret; 415 return ret;
417 416
417 if (is_invalid_reserved_pfn(*pfn_base)) {
418 struct vm_area_struct *vma;
419
420 down_read(&current->mm->mmap_sem);
421 vma = find_vma_intersection(current->mm, vaddr, vaddr + 1);
422 pinned = min_t(long, npage, vma_pages(vma));
423 up_read(&current->mm->mmap_sem);
424 return pinned;
425 }
426
418 pinned++; 427 pinned++;
419 rsvd = is_invalid_reserved_pfn(*pfn_base);
420 428
421 /* 429 /*
422 * Reserved pages aren't counted against the user, externally pinned 430 * Reserved pages aren't counted against the user, externally pinned
423 * pages are already counted against the user. 431 * pages are already counted against the user.
424 */ 432 */
425 if (!rsvd && !vfio_find_vpfn(dma, iova)) { 433 if (!vfio_find_vpfn(dma, iova)) {
426 if (!lock_cap && current->mm->locked_vm + 1 > limit) { 434 if (!lock_cap && current->mm->locked_vm + 1 > limit) {
427 put_pfn(*pfn_base, dma->prot); 435 put_pfn(*pfn_base, dma->prot);
428 pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__, 436 pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__,
@@ -442,13 +450,12 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr,
442 if (ret) 450 if (ret)
443 break; 451 break;
444 452
445 if (pfn != *pfn_base + pinned || 453 if (pfn != *pfn_base + pinned) {
446 rsvd != is_invalid_reserved_pfn(pfn)) {
447 put_pfn(pfn, dma->prot); 454 put_pfn(pfn, dma->prot);
448 break; 455 break;
449 } 456 }
450 457
451 if (!rsvd && !vfio_find_vpfn(dma, iova)) { 458 if (!vfio_find_vpfn(dma, iova)) {
452 if (!lock_cap && 459 if (!lock_cap &&
453 current->mm->locked_vm + lock_acct + 1 > limit) { 460 current->mm->locked_vm + lock_acct + 1 > limit) {
454 put_pfn(pfn, dma->prot); 461 put_pfn(pfn, dma->prot);
@@ -466,10 +473,8 @@ out:
466 473
467unpin_out: 474unpin_out:
468 if (ret) { 475 if (ret) {
469 if (!rsvd) { 476 for (pfn = *pfn_base ; pinned ; pfn++, pinned--)
470 for (pfn = *pfn_base ; pinned ; pfn++, pinned--) 477 put_pfn(pfn, dma->prot);
471 put_pfn(pfn, dma->prot);
472 }
473 478
474 return ret; 479 return ret;
475 } 480 }