From 32803dc7c2ffc29db15a46034d818f6e6c5775ef Mon Sep 17 00:00:00 2001 From: Ajay Garg Date: Tue, 12 Oct 2021 19:26:53 +0530 Subject: [PATCH] iommu: intel: do deep dma-unmapping, to avoid kernel-flooding. Origins at : https://lists.linuxfoundation.org/pipermail/iommu/2021-October/thread.html === Changes from v1 => v2 === a) Improved patch-description. b) A more root-level fix, as suggested by 1. Alex Williamson 2. Lu Baolu === Issue === Kernel-flooding is seen, when an x86_64 L1 guest (Ubuntu-21) is booted in qemu/kvm on a x86_64 host (Ubuntu-21), with a host-pci-device attached. Following kind of logs, along with the stacktraces, cause the flood : ...... DMAR: ERROR: DMA PTE for vPFN 0x428ec already set (to 3f6ec003 not 3f6ec003) DMAR: ERROR: DMA PTE for vPFN 0x428ed already set (to 3f6ed003 not 3f6ed003) DMAR: ERROR: DMA PTE for vPFN 0x428ee already set (to 3f6ee003 not 3f6ee003) DMAR: ERROR: DMA PTE for vPFN 0x428ef already set (to 3f6ef003 not 3f6ef003) DMAR: ERROR: DMA PTE for vPFN 0x428f0 already set (to 3f6f0003 not 3f6f0003) ...... === Current Behaviour, leading to the issue === Currently, when we do a dma-unmapping, we unmap/unlink the mappings, but the pte-entries are not cleared. Thus, following sequencing would flood the kernel-logs : i) A dma-unmapping makes the real/leaf-level pte-slot invalid, but the pte-content itself is not cleared. ii) Now, during some later dma-mapping procedure, as the pte-slot is about to hold a new pte-value, the intel-iommu checks if a prior pte-entry exists in the pte-slot. If it exists, it logs a kernel-error, along with a corresponding stacktrace. iii) Step ii) runs in abundance, and the kernel-logs run insane. === Fix === We ensure that as part of a dma-unmapping, each (unmapped) pte-slot is also cleared of its value/content (at the leaf-level, where the real mapping from a iova => pfn mapping is stored). This completes a "deep" dma-unmapping. Signed-off-by: Ajay Garg Link: https://lore.kernel.org/linux-iommu/20211012135653.3852-1-ajaygargnsit@gmail.com/ --- drivers/iommu/intel/iommu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 78f8c8e6803e9..d8da48a91ba3b 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -5092,6 +5092,8 @@ static size_t intel_iommu_unmap(struct iommu_domain *domain, gather->freelist = domain_unmap(dmar_domain, start_pfn, last_pfn, gather->freelist); + dma_pte_clear_range(dmar_domain, start_pfn, last_pfn); + if (dmar_domain->max_addr == iova + size) dmar_domain->max_addr = iova;