aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2015-03-04 13:30:10 -0500
committerJoerg Roedel <jroedel@suse.de>2015-03-23 10:22:08 -0400
commit71684406905f98f86a85e008b51f5c4c5d83af5a (patch)
treeb3b57570c4526a386149d4d3c3d914fe5e63ffa8
parent83a60ed8f0b5ce550afd5802b60468578db4e055 (diff)
iommu/vt-d: Detach domain *only* from attached iommus
Device domains never span IOMMU hardware units, which allows the domain ID space for each IOMMU to be an independent address space. Therefore we can have multiple, independent domains, each with the same domain->id, but attached to different hardware units. This is also why we need to do a heavy-weight search for VM domains since they can span multiple IOMMUs hardware units and we don't require a single global ID to use for all hardware units. Therefore, if we call iommu_detach_domain() across all active IOMMU hardware units for a non-VM domain, the result is that we clear domain IDs that are not associated with our domain, allowing them to be re-allocated and causing apparent coherency issues when the device cannot access IOVAs for the intended domain. This bug was introduced in commit fb170fb4c548 ("iommu/vt-d: Introduce helper functions to make code symmetric for readability"), but is significantly exacerbated by the more recent commit 62c22167dd70 ("iommu/vt-d: Fix dmar_domain leak in iommu_attach_device") which calls domain_exit() more frequently to resolve a domain leak. Fixes: fb170fb4c548 ("iommu/vt-d: Introduce helper functions to make code symmetric for readability") Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Cc: Jiang Liu <jiang.liu@linux.intel.com> Cc: stable@vger.kernel.org # v3.17+ Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r--drivers/iommu/intel-iommu.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index ae4c1a854e57..a83c965410e0 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1743,8 +1743,8 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
1743static void domain_exit(struct dmar_domain *domain) 1743static void domain_exit(struct dmar_domain *domain)
1744{ 1744{
1745 struct dmar_drhd_unit *drhd; 1745 struct dmar_drhd_unit *drhd;
1746 struct intel_iommu *iommu;
1747 struct page *freelist = NULL; 1746 struct page *freelist = NULL;
1747 int i;
1748 1748
1749 /* Domain 0 is reserved, so dont process it */ 1749 /* Domain 0 is reserved, so dont process it */
1750 if (!domain) 1750 if (!domain)
@@ -1764,8 +1764,8 @@ static void domain_exit(struct dmar_domain *domain)
1764 1764
1765 /* clear attached or cached domains */ 1765 /* clear attached or cached domains */
1766 rcu_read_lock(); 1766 rcu_read_lock();
1767 for_each_active_iommu(iommu, drhd) 1767 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus)
1768 iommu_detach_domain(domain, iommu); 1768 iommu_detach_domain(domain, g_iommus[i]);
1769 rcu_read_unlock(); 1769 rcu_read_unlock();
1770 1770
1771 dma_free_pagelist(freelist); 1771 dma_free_pagelist(freelist);