This is a more complete solution that the first attempt here: https://lore.kernel.org/r/1698825902-10685-1-git-send-email-quic_zhenhuah@xxxxxxxxxxx I haven't been able to test this on any HW that touches these paths, so if some people with HW can help get it in shape it can become non-RFC. The iommu subsystem uses dev->iommu to store bits of information about the attached iommu driver. This has been co-opted by the ACPI/OF code to also be a place to pass around the iommu_fwspec before a driver is probed. Since both are using the same pointers without any locking it triggers races if there is concurrent driver loading: CPU0 CPU1 of_iommu_configure() iommu_device_register() .. bus_iommu_probe() iommu_fwspec_of_xlate() __iommu_probe_device() iommu_init_device() dev_iommu_get() .. ops->probe fails, no fwspec .. dev_iommu_free() dev->iommu->fwspec *crash* My first attempt get correct locking here was to use the device_lock to protect the entire *_iommu_configure() and iommu_probe() paths. This allowed safe use of dev->iommu within those paths. Unfortuately enough drivers abuse the of_iommu_configure() flow without proper locking and this approach failed. This approach removes touches of dev->iommu from the *_iommu_configure() code. The few remaining required touches are moved into iommu.c and protected with the existing iommu_probe_device_lock. To do this we change *_iommu_configure() to hold the iommu_fwspec on the stack while it is being built. Once it is fully formed the core code will install it into the dev->iommu when it calls probe. This also removes all the touches of iommu_ops from the *_iommu_configure() paths and makes that mechanism private to the iommu core. A few more lockdep assertions are added to discourage future mis-use. This is on github: https://github.com/jgunthorpe/linux/commits/iommu_fwspec Jason Gunthorpe (17): iommu: Remove struct iommu_ops *iommu from arch_setup_dma_ops() of: Do not return struct iommu_ops from of_iommu_configure() of: Use -ENODEV consistently in of_iommu_configure() acpi: Do not return struct iommu_ops from acpi_iommu_configure_id() iommu: Make iommu_fwspec->ids a distinct allocation iommu: Add iommu_fwspec_alloc/dealloc() iommu: Add iommu_probe_device_fwspec() of: Do not use dev->iommu within of_iommu_configure() iommu: Add iommu_fwspec_append_ids() acpi: Do not use dev->iommu within acpi_iommu_configure() iommu: Hold iommu_probe_device_lock while calling ops->of_xlate iommu: Make iommu_ops_from_fwnode() static iommu: Remove dev_iommu_fwspec_set() iommu: Remove pointless iommu_fwspec_free() iommu: Add ops->of_xlate_fwspec() iommu: Mark dev_iommu_get() with lockdep iommu: Mark dev_iommu_priv_set() with a lockdep arch/arc/mm/dma.c | 2 +- arch/arm/mm/dma-mapping-nommu.c | 2 +- arch/arm/mm/dma-mapping.c | 10 +- arch/arm64/mm/dma-mapping.c | 4 +- arch/mips/mm/dma-noncoherent.c | 2 +- arch/riscv/mm/dma-noncoherent.c | 2 +- drivers/acpi/arm64/iort.c | 39 ++-- drivers/acpi/scan.c | 104 +++++---- drivers/acpi/viot.c | 44 ++-- drivers/hv/hv_common.c | 2 +- drivers/iommu/amd/iommu.c | 2 - drivers/iommu/apple-dart.c | 1 - drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 +- drivers/iommu/arm/arm-smmu/arm-smmu.c | 23 +- drivers/iommu/intel/iommu.c | 2 - drivers/iommu/iommu.c | 227 +++++++++++++++----- drivers/iommu/of_iommu.c | 129 +++++------ drivers/iommu/omap-iommu.c | 1 - drivers/iommu/tegra-smmu.c | 1 - drivers/iommu/virtio-iommu.c | 8 +- drivers/of/device.c | 24 ++- include/acpi/acpi_bus.h | 8 +- include/linux/acpi_iort.h | 3 +- include/linux/acpi_viot.h | 5 +- include/linux/dma-map-ops.h | 4 +- include/linux/iommu.h | 46 ++-- include/linux/of_iommu.h | 13 +- 27 files changed, 417 insertions(+), 300 deletions(-) base-commit: ab41f1aafb43c2555b358147b14b4d7b8105b452 -- 2.42.0