diff options
author | Joerg Roedel <jroedel@suse.de> | 2016-11-08 09:08:26 -0500 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2016-11-08 09:08:26 -0500 |
commit | bea64033dd7b5fb6296eda8266acab6364ce1554 (patch) | |
tree | cb561548adf7e4712f9c055f22b7c10122402f38 | |
parent | 8c82d6ec5abcf9691d37f329bf5f42f6868405db (diff) |
iommu/vt-d: Fix dead-locks in disable_dmar_iommu() path
It turns out that the disable_dmar_iommu() code-path tried
to get the device_domain_lock recursivly, which will
dead-lock when this code runs on dmar removal. Fix both
code-paths that could lead to the dead-lock.
Fixes: 55d940430ab9 ('iommu/vt-d: Get rid of domain->iommu_lock')
Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r-- | drivers/iommu/intel-iommu.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index a4407eabf0e6..3965e73db51c 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c | |||
@@ -1711,6 +1711,7 @@ static void disable_dmar_iommu(struct intel_iommu *iommu) | |||
1711 | if (!iommu->domains || !iommu->domain_ids) | 1711 | if (!iommu->domains || !iommu->domain_ids) |
1712 | return; | 1712 | return; |
1713 | 1713 | ||
1714 | again: | ||
1714 | spin_lock_irqsave(&device_domain_lock, flags); | 1715 | spin_lock_irqsave(&device_domain_lock, flags); |
1715 | list_for_each_entry_safe(info, tmp, &device_domain_list, global) { | 1716 | list_for_each_entry_safe(info, tmp, &device_domain_list, global) { |
1716 | struct dmar_domain *domain; | 1717 | struct dmar_domain *domain; |
@@ -1723,10 +1724,19 @@ static void disable_dmar_iommu(struct intel_iommu *iommu) | |||
1723 | 1724 | ||
1724 | domain = info->domain; | 1725 | domain = info->domain; |
1725 | 1726 | ||
1726 | dmar_remove_one_dev_info(domain, info->dev); | 1727 | __dmar_remove_one_dev_info(info); |
1727 | 1728 | ||
1728 | if (!domain_type_is_vm_or_si(domain)) | 1729 | if (!domain_type_is_vm_or_si(domain)) { |
1730 | /* | ||
1731 | * The domain_exit() function can't be called under | ||
1732 | * device_domain_lock, as it takes this lock itself. | ||
1733 | * So release the lock here and re-run the loop | ||
1734 | * afterwards. | ||
1735 | */ | ||
1736 | spin_unlock_irqrestore(&device_domain_lock, flags); | ||
1729 | domain_exit(domain); | 1737 | domain_exit(domain); |
1738 | goto again; | ||
1739 | } | ||
1730 | } | 1740 | } |
1731 | spin_unlock_irqrestore(&device_domain_lock, flags); | 1741 | spin_unlock_irqrestore(&device_domain_lock, flags); |
1732 | 1742 | ||