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 | #include <linux/bitops.h> | 22 | #include <linux/bitops.h> |
| 23 | #include <linux/property.h> | 23 | #include <linux/property.h> |
| 24 | #include <linux/fsl/mc.h> | 24 | #include <linux/fsl/mc.h> |
| 25 | #include <linux/module.h> | ||
| 25 | #include <trace/events/iommu.h> | 26 | #include <trace/events/iommu.h> |
| 26 | 27 | ||
| 27 | static struct kset *iommu_group_kset; | 28 | static struct kset *iommu_group_kset; |
| @@ -185,10 +186,21 @@ int iommu_probe_device(struct device *dev) · 157 unmodified lines | |||
| 185 | if (!iommu_get_dev_param(dev)) | 186 | if (!iommu_get_dev_param(dev)) |
| 186 | return -ENOMEM; | 187 | return -ENOMEM; |
| 187 | 188 | ||
| 189 | if (!try_module_get(ops->owner)) { | ||
| 190 | ret = -EINVAL; | ||
| 191 | goto err_free_dev_param; | ||
| 192 | } | ||
| 193 | |||
| 188 | ret = ops->add_device(dev); | 194 | ret = ops->add_device(dev); |
| 189 | if (ret) | 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 | return ret; | 204 | return ret; |
| 193 | } | 205 | } |
| 194 | 206 | ||
| @@ -199,7 +211,10 @@ void iommu_release_device(struct device *dev) · 4 unmodified lines | |||
| 199 | if (dev->iommu_group) | 211 | if (dev->iommu_group) |
| 200 | ops->remove_device(dev); | 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 | static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, | 220 | static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, |
| @@ -246,9 +246,10 @@ struct iommu_iotlb_gather { · 245 unmodified lines | |||
| 246 | * @sva_get_pasid: Get PASID associated to a SVA handle | 246 | * @sva_get_pasid: Get PASID associated to a SVA handle |
| 247 | * @page_response: handle page request response | 247 | * @page_response: handle page request response |
| 248 | * @cache_invalidate: invalidate translation caches | 248 | * @cache_invalidate: invalidate translation caches |
| 249 | * @pgsize_bitmap: bitmap of all possible supported page sizes | ||
| 250 | * @sva_bind_gpasid: bind guest pasid and mm | 249 | * @sva_bind_gpasid: bind guest pasid and mm |
| 251 | * @sva_unbind_gpasid: unbind guest pasid and mm | 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 | struct iommu_ops { | 254 | struct iommu_ops { |
| 254 | bool (*capable)(enum iommu_cap); | 255 | bool (*capable)(enum iommu_cap); |
| @@ -318,6 +319,7 @@ struct iommu_ops { · 63 unmodified lines | |||
| 318 | int (*sva_unbind_gpasid)(struct device *dev, int pasid); | 319 | int (*sva_unbind_gpasid)(struct device *dev, int pasid); |
| 319 | 320 | ||
| 320 | unsigned long pgsize_bitmap; | 321 | unsigned long pgsize_bitmap; |
| 322 | struct module *owner; | ||
| 321 | }; | 323 | }; |
| 322 | 324 | ||
| 323 | /** | 325 | /** |