Iago Abal
2016-10-17 08:54:40 UTC
From: Iago Abal <***@iagoabal.eu>
The EBA code analyzer (https://github.com/models-team/eba) reported
the following double lock:
1. In function `disable_dmar_iommu' defined at 1706;
2. the lock `device_domain_lock' is first taken in line 1714:
// FIRST
spin_lock_irqsave(&device_domain_lock, flags);
3. enter the `list_for_each_entry_safe' loop at 1715;
4. call function `dmar_remove_one_dev_info' (defined at 4851) in line 1726;
5. finally, the lock is taken a second time in line 4857:
// SECOND: DOUBLE LOCK !!!
spin_lock_irqsave(&device_domain_lock, flags);
In addition, within that same loop, there is also a call to `domain_exit', which
calls to `domain_remove_dev_info', which also spin_lock on `device_domain_lock'.
I fixed the potential deadlock by releasing the `device_domain_lock' during the
execution of the loop body. This seems to respect the locking assumptions made
by the rest of the code: both `dmar_remove_one_dev_info' and `domain_exit' will
(directly or indiretly) take that look, so they should not be called with it held.
Function `domain_type_is_vm_or_si' just checks `domain->flags' and there seem
to be no concurrent writes to this field.
Signed-off-by: Iago Abal <***@iagoabal.eu>
---
drivers/iommu/intel-iommu.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index a4407ea..05796a8 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1721,12 +1721,16 @@ static void disable_dmar_iommu(struct intel_iommu *iommu)
if (!info->dev || !info->domain)
continue;
+ spin_unlock_irqrestore(&device_domain_lock, flags);
+
domain = info->domain;
dmar_remove_one_dev_info(domain, info->dev);
if (!domain_type_is_vm_or_si(domain))
domain_exit(domain);
+
+ spin_lock_irqsave(&device_domain_lock, flags);
}
spin_unlock_irqrestore(&device_domain_lock, flags);
The EBA code analyzer (https://github.com/models-team/eba) reported
the following double lock:
1. In function `disable_dmar_iommu' defined at 1706;
2. the lock `device_domain_lock' is first taken in line 1714:
// FIRST
spin_lock_irqsave(&device_domain_lock, flags);
3. enter the `list_for_each_entry_safe' loop at 1715;
4. call function `dmar_remove_one_dev_info' (defined at 4851) in line 1726;
5. finally, the lock is taken a second time in line 4857:
// SECOND: DOUBLE LOCK !!!
spin_lock_irqsave(&device_domain_lock, flags);
In addition, within that same loop, there is also a call to `domain_exit', which
calls to `domain_remove_dev_info', which also spin_lock on `device_domain_lock'.
I fixed the potential deadlock by releasing the `device_domain_lock' during the
execution of the loop body. This seems to respect the locking assumptions made
by the rest of the code: both `dmar_remove_one_dev_info' and `domain_exit' will
(directly or indiretly) take that look, so they should not be called with it held.
Function `domain_type_is_vm_or_si' just checks `domain->flags' and there seem
to be no concurrent writes to this field.
Signed-off-by: Iago Abal <***@iagoabal.eu>
---
drivers/iommu/intel-iommu.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index a4407ea..05796a8 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1721,12 +1721,16 @@ static void disable_dmar_iommu(struct intel_iommu *iommu)
if (!info->dev || !info->domain)
continue;
+ spin_unlock_irqrestore(&device_domain_lock, flags);
+
domain = info->domain;
dmar_remove_one_dev_info(domain, info->dev);
if (!domain_type_is_vm_or_si(domain))
domain_exit(domain);
+
+ spin_lock_irqsave(&device_domain_lock, flags);
}
spin_unlock_irqrestore(&device_domain_lock, flags);
--
1.9.1
1.9.1