diff options
| -rw-r--r-- | drivers/vfio/vfio_iommu_type1.c | 40 |
1 files changed, 21 insertions, 19 deletions
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index a9807dea3887..4fb7a8f83c8a 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c | |||
| @@ -545,6 +545,8 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, | |||
| 545 | long npage; | 545 | long npage; |
| 546 | int ret = 0, prot = 0; | 546 | int ret = 0, prot = 0; |
| 547 | uint64_t mask; | 547 | uint64_t mask; |
| 548 | struct vfio_dma *dma = NULL; | ||
| 549 | unsigned long pfn; | ||
| 548 | 550 | ||
| 549 | end = map->iova + map->size; | 551 | end = map->iova + map->size; |
| 550 | 552 | ||
| @@ -587,8 +589,6 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, | |||
| 587 | } | 589 | } |
| 588 | 590 | ||
| 589 | for (iova = map->iova; iova < end; iova += size, vaddr += size) { | 591 | for (iova = map->iova; iova < end; iova += size, vaddr += size) { |
| 590 | struct vfio_dma *dma = NULL; | ||
| 591 | unsigned long pfn; | ||
| 592 | long i; | 592 | long i; |
| 593 | 593 | ||
| 594 | /* Pin a contiguous chunk of memory */ | 594 | /* Pin a contiguous chunk of memory */ |
| @@ -597,16 +597,15 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, | |||
| 597 | if (npage <= 0) { | 597 | if (npage <= 0) { |
| 598 | WARN_ON(!npage); | 598 | WARN_ON(!npage); |
| 599 | ret = (int)npage; | 599 | ret = (int)npage; |
| 600 | break; | 600 | goto out; |
| 601 | } | 601 | } |
| 602 | 602 | ||
| 603 | /* Verify pages are not already mapped */ | 603 | /* Verify pages are not already mapped */ |
| 604 | for (i = 0; i < npage; i++) { | 604 | for (i = 0; i < npage; i++) { |
| 605 | if (iommu_iova_to_phys(iommu->domain, | 605 | if (iommu_iova_to_phys(iommu->domain, |
| 606 | iova + (i << PAGE_SHIFT))) { | 606 | iova + (i << PAGE_SHIFT))) { |
| 607 | vfio_unpin_pages(pfn, npage, prot, true); | ||
| 608 | ret = -EBUSY; | 607 | ret = -EBUSY; |
| 609 | break; | 608 | goto out_unpin; |
| 610 | } | 609 | } |
| 611 | } | 610 | } |
| 612 | 611 | ||
| @@ -616,8 +615,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, | |||
| 616 | if (ret) { | 615 | if (ret) { |
| 617 | if (ret != -EBUSY || | 616 | if (ret != -EBUSY || |
| 618 | map_try_harder(iommu, iova, pfn, npage, prot)) { | 617 | map_try_harder(iommu, iova, pfn, npage, prot)) { |
| 619 | vfio_unpin_pages(pfn, npage, prot, true); | 618 | goto out_unpin; |
| 620 | break; | ||
| 621 | } | 619 | } |
| 622 | } | 620 | } |
| 623 | 621 | ||
| @@ -672,9 +670,8 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, | |||
| 672 | dma = kzalloc(sizeof(*dma), GFP_KERNEL); | 670 | dma = kzalloc(sizeof(*dma), GFP_KERNEL); |
| 673 | if (!dma) { | 671 | if (!dma) { |
| 674 | iommu_unmap(iommu->domain, iova, size); | 672 | iommu_unmap(iommu->domain, iova, size); |
| 675 | vfio_unpin_pages(pfn, npage, prot, true); | ||
| 676 | ret = -ENOMEM; | 673 | ret = -ENOMEM; |
| 677 | break; | 674 | goto out_unpin; |
| 678 | } | 675 | } |
| 679 | 676 | ||
| 680 | dma->size = size; | 677 | dma->size = size; |
| @@ -685,16 +682,21 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, | |||
| 685 | } | 682 | } |
| 686 | } | 683 | } |
| 687 | 684 | ||
| 688 | if (ret) { | 685 | WARN_ON(ret); |
| 689 | struct vfio_dma *tmp; | 686 | mutex_unlock(&iommu->lock); |
| 690 | iova = map->iova; | 687 | return ret; |
| 691 | size = map->size; | 688 | |
| 692 | while ((tmp = vfio_find_dma(iommu, iova, size))) { | 689 | out_unpin: |
| 693 | int r = vfio_remove_dma_overlap(iommu, iova, | 690 | vfio_unpin_pages(pfn, npage, prot, true); |
| 694 | &size, tmp); | 691 | |
| 695 | if (WARN_ON(r || !size)) | 692 | out: |
| 696 | break; | 693 | iova = map->iova; |
| 697 | } | 694 | size = map->size; |
| 695 | while ((dma = vfio_find_dma(iommu, iova, size))) { | ||
| 696 | int r = vfio_remove_dma_overlap(iommu, iova, | ||
| 697 | &size, dma); | ||
| 698 | if (WARN_ON(r || !size)) | ||
| 699 | break; | ||
| 698 | } | 700 | } |
| 699 | 701 | ||
| 700 | mutex_unlock(&iommu->lock); | 702 | mutex_unlock(&iommu->lock); |
