[PATCH stable 6.12 2/2] iommu/dma: sync IOTLB before releasing IOVA on sg unmap

From: avinash pal

Date: Thu Apr 23 2026 - 06:14:27 EST


On the lazy-flush path, __iommu_dma_unmap_sg() calls free_iova_fast()
before iommu_iotlb_sync() has drained the old mapping from hardware.
A concurrent dma_map_sg() can then allocate the same IOVA and hit the
stale-PTE WARN_ON in __domain_mapping() / intel_iommu_map_pages():

CPU 0 (unmap, lazy) CPU 1 (map)
─────────────────── ─────────────────────────────
iommu_unmap(iova)
free_iova_fast(iova) ← live!
alloc_iova_fast() → same iova
__domain_mapping()
dma_pte_present() == true ← WARN

Fix: insert iommu_iotlb_sync() immediately before free_iova_fast() on
the lazy path so the IOTLB is fully drained before IOVA reuse.

The strict-mode path already serialises here; this closes the same gap
for lazy/deferred flushing (regression introduced between v6.12.74 and
v6.12.76 — confirmed by reporter).

Reported-by: Giovanni Pancotti <giovanni.pancotti@xxxxxxxxxxx>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=221389
Fixes: <run: git log v6.12.74..v6.12.76 -- drivers/iommu/dma-iommu.c>
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: avinash pal <avinashpal441@xxxxxxxxx>
---
drivers/iommu/dma-iommu.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 0f0caf590..90071cf4a 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -159,6 +159,15 @@ static void fq_ring_free_locked(struct iommu_dma_cookie *cookie, struct iova_fq
break;

iommu_put_pages_list(&fq->entries[idx].freelist);
+/*
+ * Bug fix (Bugzilla #221389, regression v6.12.75/v6.12.76):
+ * Drain the IOTLB before handing the IOVA back to the allocator.
+ * On the lazy-flush path, free_iova_fast() makes the IOVA
+ * immediately reusable. A concurrent map() call can then receive
+ * the same IOVA while the old PTE is still live in hardware,
+ * triggering a stale-PTE WARN in __domain_mapping().
+ */
+iommu_iotlb_sync(domain, &iotlb_gather);
free_iova_fast(&cookie->iovad,
fq->entries[idx].iova_pfn,
fq->entries[idx].pages);
--
2.53.0