Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'vfio-v3.12-rc5' of git://github.com/awilliam/linux-vfio

Pull vfio fix from Alex Williamson:
"Fix an incorrect break out of nested loop in iommu mapping code"

* tag 'vfio-v3.12-rc5' of git://github.com/awilliam/linux-vfio:
VFIO: vfio_iommu_type1: fix bug caused by break in nested loop

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