Skip to content

Commit

Permalink
iommu/amd: Only unmap large pages from the first pte
Browse files Browse the repository at this point in the history
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 <[email protected]>
Cc: [email protected]
Signed-off-by: Joerg Roedel <[email protected]>
  • Loading branch information
awilliam authored and joergroedel committed Jun 23, 2013
1 parent 5c34c40 commit 60d0ca3
Showing 1 changed file with 5 additions and 1 deletion.
6 changes: 5 additions & 1 deletion drivers/iommu/amd_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1484,6 +1484,10 @@ static unsigned long iommu_unmap_page(struct protection_domain *dom,

/* Large PTE found which maps this address */
unmap_size = PTE_PAGE_SIZE(*pte);

/* Only unmap from the first pte in the page */
if ((unmap_size - 1) & bus_addr)
break;
count = PAGE_SIZE_PTE_COUNT(unmap_size);
for (i = 0; i < count; i++)
pte[i] = 0ULL;
Expand All @@ -1493,7 +1497,7 @@ static unsigned long iommu_unmap_page(struct protection_domain *dom,
unmapped += unmap_size;
}

BUG_ON(!is_power_of_2(unmapped));
BUG_ON(unmapped && !is_power_of_2(unmapped));

return unmapped;
}
Expand Down

0 comments on commit 60d0ca3

Please sign in to comment.