diff options
author | Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> | 2022-03-13 21:43:21 -0500 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2022-05-04 10:32:11 +0200 |
commit | 5edde870d3283edeaa27ab62ac4fac5ee8cae35a (patch) | |
tree | d8adaaf61e3a5436dd02c2cbb9734fec8b8f8204 /drivers/iommu | |
parent | af2d861d4cd2a4da5137f795ee3509e6f944a25b (diff) | |
download | linux-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.c | 12 |
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); } |