|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [patch-4.16] arm/smmuv1,v2: Protect smmu master list with a lock
If a device is added to SMMUv1/v2 from DT and PCI
at the same time, there is a concurrent access
to a smmu master list. This could lead to a
scenario where one is looking into a list that
is being modified at the same time. Add a lock
to prevent this issue.
Reuse the existing spinlock arm_smmu_devices_lock
as it is already protecting find_smmu_master.
ipmmu-smmu and smmuv3 are not impacted by this
issue as there is no access or modification of
a global resource during add_device.
Signed-off-by: Michal Orzel <michal.orzel@xxxxxxx>
---
This patch aims for 4.16 release.
Benefits:
Remove a bug that could lead to a corruption of the
smmu master list, which would be very hard to debug.
Risks:
Overall the risk is low as we are touching init code
rather than a runtime one. In case of any issue, the
problem would be catched during system boot or guest
start.
---
xen/drivers/passthrough/arm/smmu.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/xen/drivers/passthrough/arm/smmu.c
b/xen/drivers/passthrough/arm/smmu.c
index c9dfc4caa0..be62a66a28 100644
--- a/xen/drivers/passthrough/arm/smmu.c
+++ b/xen/drivers/passthrough/arm/smmu.c
@@ -820,21 +820,25 @@ static int arm_smmu_dt_add_device_legacy(struct
arm_smmu_device *smmu,
struct device *dev,
struct iommu_fwspec *fwspec)
{
- int i;
+ int i, ret;
struct arm_smmu_master *master;
struct device_node *dev_node = dev_get_dev_node(dev);
+ spin_lock(&arm_smmu_devices_lock);
master = find_smmu_master(smmu, dev_node);
if (master) {
dev_err(dev,
"rejecting multiple registrations for master device
%s\n",
dev_node->name);
- return -EBUSY;
+ ret = -EBUSY;
+ goto out_unlock;
}
master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL);
- if (!master)
- return -ENOMEM;
+ if (!master) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
master->of_node = dev_node;
/* Xen: Let Xen know that the device is protected by an SMMU */
@@ -846,11 +850,17 @@ static int arm_smmu_dt_add_device_legacy(struct
arm_smmu_device *smmu,
dev_err(dev,
"stream ID for master device %s greater than
maximum allowed (%d)\n",
dev_node->name, smmu->num_mapping_groups);
- return -ERANGE;
+ ret = -ERANGE;
+ goto out_unlock;
}
master->cfg.smendx[i] = INVALID_SMENDX;
}
- return insert_smmu_master(smmu, master);
+
+ ret = insert_smmu_master(smmu, master);
+
+out_unlock:
+ spin_unlock(&arm_smmu_devices_lock);
+ return ret;
}
static int register_smmu_master(struct arm_smmu_device *smmu,
@@ -2056,7 +2066,10 @@ static int arm_smmu_add_device(struct device *dev)
} else {
struct arm_smmu_master *master;
+ spin_lock(&arm_smmu_devices_lock);
master = find_smmu_master(smmu, dev->of_node);
+ spin_unlock(&arm_smmu_devices_lock);
+
if (!master) {
return -ENODEV;
}
--
2.29.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |