Skip to content

Commit 1e52db6

Browse files
committed
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
2 parents ed8ada3 + d93b3ac commit 1e52db6

File tree

1 file changed

+21
-19
lines changed

1 file changed

+21
-19
lines changed

drivers/vfio/vfio_iommu_type1.c

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,8 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
545545
long npage;
546546
int ret = 0, prot = 0;
547547
uint64_t mask;
548+
struct vfio_dma *dma = NULL;
549+
unsigned long pfn;
548550

549551
end = map->iova + map->size;
550552

@@ -587,8 +589,6 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
587589
}
588590

589591
for (iova = map->iova; iova < end; iova += size, vaddr += size) {
590-
struct vfio_dma *dma = NULL;
591-
unsigned long pfn;
592592
long i;
593593

594594
/* Pin a contiguous chunk of memory */
@@ -597,16 +597,15 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
597597
if (npage <= 0) {
598598
WARN_ON(!npage);
599599
ret = (int)npage;
600-
break;
600+
goto out;
601601
}
602602

603603
/* Verify pages are not already mapped */
604604
for (i = 0; i < npage; i++) {
605605
if (iommu_iova_to_phys(iommu->domain,
606606
iova + (i << PAGE_SHIFT))) {
607-
vfio_unpin_pages(pfn, npage, prot, true);
608607
ret = -EBUSY;
609-
break;
608+
goto out_unpin;
610609
}
611610
}
612611

@@ -616,8 +615,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
616615
if (ret) {
617616
if (ret != -EBUSY ||
618617
map_try_harder(iommu, iova, pfn, npage, prot)) {
619-
vfio_unpin_pages(pfn, npage, prot, true);
620-
break;
618+
goto out_unpin;
621619
}
622620
}
623621

@@ -672,9 +670,8 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
672670
dma = kzalloc(sizeof(*dma), GFP_KERNEL);
673671
if (!dma) {
674672
iommu_unmap(iommu->domain, iova, size);
675-
vfio_unpin_pages(pfn, npage, prot, true);
676673
ret = -ENOMEM;
677-
break;
674+
goto out_unpin;
678675
}
679676

680677
dma->size = size;
@@ -685,16 +682,21 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
685682
}
686683
}
687684

688-
if (ret) {
689-
struct vfio_dma *tmp;
690-
iova = map->iova;
691-
size = map->size;
692-
while ((tmp = vfio_find_dma(iommu, iova, size))) {
693-
int r = vfio_remove_dma_overlap(iommu, iova,
694-
&size, tmp);
695-
if (WARN_ON(r || !size))
696-
break;
697-
}
685+
WARN_ON(ret);
686+
mutex_unlock(&iommu->lock);
687+
return ret;
688+
689+
out_unpin:
690+
vfio_unpin_pages(pfn, npage, prot, true);
691+
692+
out:
693+
iova = map->iova;
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;
698700
}
699701

700702
mutex_unlock(&iommu->lock);

0 commit comments

Comments
 (0)