When unbinding/binding a driver with DMA mapped memory, the DMA map is not freed when the driver is reloaded. This leads to a memory leak when the DMA map is overwritten when reprobing the driver. This can be reproduced with a platform driver having a dma-range: dummy { ... #address-cells = <0x2>; #size-cells = <0x2>; ranges; dma-ranges = <...>; ... }; and then unbinding/binding it: ~# echo soc:dummy >/sys/bus/platform/drivers/<driver>/unbind DMA map object 0xffffff800b0ae540 still being held by &pdev->dev ~# echo soc:dummy >/sys/bus/platform/drivers/<driver>/bind ~# echo scan > /sys/kernel/debug/kmemleak ~# cat /sys/kernel/debug/kmemleak unreferenced object 0xffffff800b0ae540 (size 64): comm "sh", pid 833, jiffies 4295174550 (age 2535.352s) hex dump (first 32 bytes): 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 80 00 00 00 00 00 00 00 80 00 00 00 00 ................ backtrace: [<ffffffefd1694708>] create_object.isra.0+0x108/0x344 [<ffffffefd1d1a850>] kmemleak_alloc+0x8c/0xd0 [<ffffffefd167e2d0>] __kmalloc+0x440/0x6f0 [<ffffffefd1a960a4>] of_dma_get_range+0x124/0x220 [<ffffffefd1a8ce90>] of_dma_configure_id+0x40/0x2d0 [<ffffffefd198b68c>] platform_dma_configure+0x5c/0xa4 [<ffffffefd198846c>] really_probe+0x8c/0x514 [<ffffffefd1988990>] __driver_probe_device+0x9c/0x19c [<ffffffefd1988cd8>] device_driver_attach+0x54/0xbc [<ffffffefd1986634>] bind_store+0xc4/0x120 [<ffffffefd19856e0>] drv_attr_store+0x30/0x44 [<ffffffefd173c9b0>] sysfs_kf_write+0x50/0x60 [<ffffffefd173c1c4>] kernfs_fop_write_iter+0x124/0x1b4 [<ffffffefd16a013c>] new_sync_write+0xdc/0x160 [<ffffffefd16a256c>] vfs_write+0x23c/0x2a0 [<ffffffefd16a2758>] ksys_write+0x64/0xec Don't get a new dma_range_map if there already is one. Check for an existing map and reuse it, or else get the map as before. This will prevent overwriting the old map which is still valid. Signed-off-by: Mårten Lindahl <marten.lindahl@xxxxxxxx> --- v2: - Reuse range map instead of getting a new and freeing the old. drivers/of/device.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/of/device.c b/drivers/of/device.c index 874f031442dc..7e5d8066ffff 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -116,9 +116,14 @@ int of_dma_configure_id(struct device *dev, struct device_node *np, u64 dma_start = 0; u64 mask, end, size = 0; bool coherent; - int ret; + int ret = 0; + + /* Don't get a new DMA range map if we already have one */ + if (dev->dma_range_map) + map = dev->dma_range_map; + else + ret = of_dma_get_range(np, &map); - ret = of_dma_get_range(np, &map); if (ret < 0) { /* * For legacy reasons, we have to assume some devices need -- 2.30.2