To avoid accidental removal of an active IOMMU driver module, take a reference to the driver module in 'iommu_probe_device()' immediately prior to invoking the '->add_device()' callback and hold it until the after the device has been removed by '->remove_device()'.
Unified · Split
| @@ -22,6 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <linux/bitops.h> |
| 23 | 23 | #include <linux/property.h> |
| 24 | 24 | #include <linux/fsl/mc.h> |
| 25 | +#include <linux/module.h> | |
| 25 | 26 | #include <trace/events/iommu.h> |
| 26 | 27 | |
| 27 | 28 | static struct kset *iommu_group_kset; |
| @@ -185,10 +186,21 @@ int iommu_probe_device(struct device *dev) · 157 unmodified lines | ||
| 185 | 186 | if (!iommu_get_dev_param(dev)) |
| 186 | 187 | return -ENOMEM; |
| 187 | 188 | |
| 189 | + if (!try_module_get(ops->owner)) { | |
| 190 | + ret = -EINVAL; | |
| 191 | + goto err_free_dev_param; | |
| 192 | + } | |
| 193 | + | |
| 188 | 194 | ret = ops->add_device(dev); |
| 189 | 195 | if (ret) |
| 190 | − iommu_free_dev_param(dev); | |
| 196 | + goto err_module_put; | |
| 197 | + | |
| 198 | + return 0; | |
| 191 | 199 | |
| 200 | +err_module_put: | |
| 201 | + module_put(ops->owner); | |
| 202 | +err_free_dev_param: | |
| 203 | + iommu_free_dev_param(dev); | |
| 192 | 204 | return ret; |
| 193 | 205 | } |
| 194 | 206 | |
| @@ -199,7 +211,10 @@ void iommu_release_device(struct device *dev) · 4 unmodified lines | ||
| 199 | 211 | if (dev->iommu_group) |
| 200 | 212 | ops->remove_device(dev); |
| 201 | 213 | |
| 202 | − iommu_free_dev_param(dev); | |
| 214 | + if (dev->iommu_param) { | |
| 215 | + module_put(ops->owner); | |
| 216 | + iommu_free_dev_param(dev); | |
| 217 | + } | |
| 203 | 218 | } |
| 204 | 219 | |
| 205 | 220 | static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, |
| @@ -246,9 +246,10 @@ struct iommu_iotlb_gather { · 245 unmodified lines | ||
| 246 | 246 | * @sva_get_pasid: Get PASID associated to a SVA handle |
| 247 | 247 | * @page_response: handle page request response |
| 248 | 248 | * @cache_invalidate: invalidate translation caches |
| 249 | − * @pgsize_bitmap: bitmap of all possible supported page sizes | |
| 250 | 249 | * @sva_bind_gpasid: bind guest pasid and mm |
| 251 | 250 | * @sva_unbind_gpasid: unbind guest pasid and mm |
| 251 | + * @pgsize_bitmap: bitmap of all possible supported page sizes | |
| 252 | + * @owner: Driver module providing these ops | |
| 252 | 253 | */ |
| 253 | 254 | struct iommu_ops { |
| 254 | 255 | bool (*capable)(enum iommu_cap); |
| @@ -318,6 +319,7 @@ struct iommu_ops { · 63 unmodified lines | ||
| 318 | 319 | int (*sva_unbind_gpasid)(struct device *dev, int pasid); |
| 319 | 320 | |
| 320 | 321 | unsigned long pgsize_bitmap; |
| 322 | + struct module *owner; | |
| 321 | 323 | }; |
| 322 | 324 | |
| 323 | 325 | /** |