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

iommu/amd: Only unmap large pages from the first pte

If we use a large mapping, the expectation is that only unmaps from
the first pte in the superpage are supported. Unmaps from offsets
into the superpage should fail (ie. return zero sized unmap). In the
current code, unmapping from an offset clears the size of the full
mapping starting from an offset. For instance, if we map a 16k
physically contiguous range at IOVA 0x0 with a large page, then
attempt to unmap 4k at offset 12k, 4 ptes are cleared (12k - 28k) and
the unmap returns 16k unmapped. This potentially incorrectly clears
valid mappings and confuses drivers like VFIO that use the unmap size
to release pinned pages.

Fix by refusing to unmap from offsets into the page.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: Joerg Roedel <joro@8bytes.org>

authored by

Alex Williamson and committed by
Joerg Roedel
60d0ca3c 5c34c403

+5 -1
+5 -1
drivers/iommu/amd_iommu.c
··· 1484 1484 1485 1485 /* Large PTE found which maps this address */ 1486 1486 unmap_size = PTE_PAGE_SIZE(*pte); 1487 + 1488 + /* Only unmap from the first pte in the page */ 1489 + if ((unmap_size - 1) & bus_addr) 1490 + break; 1487 1491 count = PAGE_SIZE_PTE_COUNT(unmap_size); 1488 1492 for (i = 0; i < count; i++) 1489 1493 pte[i] = 0ULL; ··· 1497 1493 unmapped += unmap_size; 1498 1494 } 1499 1495 1500 - BUG_ON(!is_power_of_2(unmapped)); 1496 + BUG_ON(unmapped && !is_power_of_2(unmapped)); 1501 1497 1502 1498 return unmapped; 1503 1499 }