summaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>2022-03-13 21:43:21 -0500
committerJoerg Roedel <jroedel@suse.de>2022-05-04 10:32:11 +0200
commit5edde870d3283edeaa27ab62ac4fac5ee8cae35a (patch)
treed8adaaf61e3a5436dd02c2cbb9734fec8b8f8204 /drivers/iommu
parentaf2d861d4cd2a4da5137f795ee3509e6f944a25b (diff)
downloadlinux-5edde870d3283edeaa27ab62ac4fac5ee8cae35a.tar.gz
linux-5edde870d3283edeaa27ab62ac4fac5ee8cae35a.tar.bz2
linux-5edde870d3283edeaa27ab62ac4fac5ee8cae35a.zip
iommu/amd: Do not call sleep while holding spinlock
Smatch static checker warns: drivers/iommu/amd/iommu_v2.c:133 free_device_state() warn: sleeping in atomic context Fixes by storing the list of struct device_state in a temporary list, and then free the memory after releasing the spinlock. Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Fixes: 9f968fc70d85 ("iommu/amd: Improve amd_iommu_v2_exit()") Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> Link: https://lore.kernel.org/r/20220314024321.37411-1-suravee.suthikulpanit@amd.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/amd/iommu_v2.c12
1 files changed, 11 insertions, 1 deletions
diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c
index e56b137ceabd..afb3efd565b7 100644
--- a/drivers/iommu/amd/iommu_v2.c
+++ b/drivers/iommu/amd/iommu_v2.c
@@ -956,6 +956,7 @@ static void __exit amd_iommu_v2_exit(void)
{
struct device_state *dev_state, *next;
unsigned long flags;
+ LIST_HEAD(freelist);
if (!amd_iommu_v2_supported())
return;
@@ -975,11 +976,20 @@ static void __exit amd_iommu_v2_exit(void)
put_device_state(dev_state);
list_del(&dev_state->list);
- free_device_state(dev_state);
+ list_add_tail(&dev_state->list, &freelist);
}
spin_unlock_irqrestore(&state_lock, flags);
+ /*
+ * Since free_device_state waits on the count to be zero,
+ * we need to free dev_state outside the spinlock.
+ */
+ list_for_each_entry_safe(dev_state, next, &freelist, list) {
+ list_del(&dev_state->list);
+ free_device_state(dev_state);
+ }
+
destroy_workqueue(iommu_wq);
}