clk: Fix memory leak in clk_unregister()
PATCH 1/1 clk: Fix memory leak in clk_unregister()
Memory allocated in alloc_clk() for 'struct clk' and 'const char *con_id' while invoking clk_register() is never freed in clk_unregister(), resulting in kmemleak showing the following backtrace.
backtrace:
[<00000000546f5dd0>] kmem_cache_alloc+0x18c/0x270
[<0000000073a32862>] alloc_clk+0x30/0x70
[<0000000082942480>] __clk_register+0xc8/0x760
[<000000005c859fca>] devm_clk_register+0x54/0xb0
[<00000000868834a8>] 0xffff800008c60950
[<00000000d5a80534>] platform_drv_probe+0x50/0xa0
[<000000001b3889fc>] really_probe+0x108/0x348
[<00000000953fa60a>] driver_probe_device+0x58/0x100
[<0000000008acc17c>] device_driver_attach+0x6c/0x90
[<0000000022813df3>] __driver_attach+0x84/0xc8
[<00000000448d5443>] bus_for_each_dev+0x74/0xc8
[<00000000294aa93f>] driver_attach+0x20/0x28
[<00000000e5e52626>] bus_add_driver+0x148/0x1f0
[<000000001de21efc>] driver_register+0x60/0x110
[<00000000af07c068>] __platform_driver_register+0x40/0x48
[<0000000060fa80ee>] 0xffff800008c66020Fix it here.
--- drivers/clk/clk.c | 1 + 1 file changed, 1 insertion(+)
drivers/clk/clk.c +1 -0
@@ -3879,6 +3879,7 @@ void clk_unregister(struct clk *clk) __func__, clk->core->name);kref_put (&clk->core->ref, __clk_release); +free_clk (clk); unlock:clk_prepare_unlock (); }
Signature · 1 line
2.17.1
Stephen Boyd
maintainerQuoting Kishon Vijay Abraham I (2019-10-22 00:11:53)
Quoted 23 lines
Memory allocated in
alloc_clk()for 'struct clk' and 'const char*con_id' while invokingclk_register()is never freed inclk_unregister(), resulting in kmemleak showing the following backtrace.backtrace:
[<00000000546f5dd0>] kmem_cache_alloc+0x18c/0x270 [<0000000073a32862>] alloc_clk+0x30/0x70 [<0000000082942480>] __clk_register+0xc8/0x760 [<000000005c859fca>] devm_clk_register+0x54/0xb0 [<00000000868834a8>] 0xffff800008c60950 [<00000000d5a80534>] platform_drv_probe+0x50/0xa0 [<000000001b3889fc>] really_probe+0x108/0x348 [<00000000953fa60a>] driver_probe_device+0x58/0x100 [<0000000008acc17c>] device_driver_attach+0x6c/0x90 [<0000000022813df3>] __driver_attach+0x84/0xc8 [<00000000448d5443>] bus_for_each_dev+0x74/0xc8 [<00000000294aa93f>] driver_attach+0x20/0x28 [<00000000e5e52626>] bus_add_driver+0x148/0x1f0 [<000000001de21efc>] driver_register+0x60/0x110 [<00000000af07c068>] __platform_driver_register+0x40/0x48 [<0000000060fa80ee>] 0xffff800008c66020
Quoted 1 line
Fix it here.
Do you have some Fixes tag for this? Looks OK to me, but I wonder if we should also assign hw->clk to NULL after unregister frees it. There are probably other problems around unregistration and reference counting that we haven't found so far so I'm worried this doesn't solve all the problems by just freeing the clk pointer.
For example, anything referencing the clk pointer freed here will now start trying to dereference freed memory. For most cases we've replaced struct clk with struct clk_core in the clk framework so I hope this pointer isn't used very much at all. A quick grep shows that it is returned from clk_get_parent() and __clk_lookup(). We really need to kill off __clk_lookup() and replace it with something else, and clk_get_parent() needs to generate a different clk and have callers call clk_put() on the returned pointer. Long story short I think this is OK!
PATCH v2 1/1 clk: Fix memory leak in clk_unregister()
Memory allocated in alloc_clk() for 'struct clk' and 'const char *con_id' while invoking clk_register() is never freed in clk_unregister(), resulting in kmemleak showing the following backtrace.
backtrace:
[<00000000546f5dd0>] kmem_cache_alloc+0x18c/0x270
[<0000000073a32862>] alloc_clk+0x30/0x70
[<0000000082942480>] __clk_register+0xc8/0x760
[<000000005c859fca>] devm_clk_register+0x54/0xb0
[<00000000868834a8>] 0xffff800008c60950
[<00000000d5a80534>] platform_drv_probe+0x50/0xa0
[<000000001b3889fc>] really_probe+0x108/0x348
[<00000000953fa60a>] driver_probe_device+0x58/0x100
[<0000000008acc17c>] device_driver_attach+0x6c/0x90
[<0000000022813df3>] __driver_attach+0x84/0xc8
[<00000000448d5443>] bus_for_each_dev+0x74/0xc8
[<00000000294aa93f>] driver_attach+0x20/0x28
[<00000000e5e52626>] bus_add_driver+0x148/0x1f0
[<000000001de21efc>] driver_register+0x60/0x110
[<00000000af07c068>] __platform_driver_register+0x40/0x48
[<0000000060fa80ee>] 0xffff800008c66020Fix it here.
--- drivers/clk/clk.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/clk/clk.c +4 -0
@@ -3835,6 +3835,7 @@ static void clk_core_evict_parent_cache(struct clk_core *core)void clk_unregister (struct clk *clk) {unsigned long flags; +struct clk_hw *hw;if (!clk ||WARN_ON_ONCE (IS_ERR (clk)))return ;
@@ -3879,6 +3880,9 @@ void clk_unregister(struct clk *clk) __func__, clk->core->name);kref_put (&clk->core->ref, __clk_release); + hw = clk->core->hw; +free_clk (clk); + hw->clk =NULL ; unlock:clk_prepare_unlock (); }
Signature · 1 line
2.17.1
Hi Stephen,
Quoted 23 lines · Kishon Vijay Abraham I
Memory allocated in
alloc_clk()for 'struct clk' and 'const char*con_id' while invokingclk_register()is never freed inclk_unregister(), resulting in kmemleak showing the following backtrace.backtrace:
[<00000000546f5dd0>] kmem_cache_alloc+0x18c/0x270 [<0000000073a32862>] alloc_clk+0x30/0x70 [<0000000082942480>] __clk_register+0xc8/0x760 [<000000005c859fca>] devm_clk_register+0x54/0xb0 [<00000000868834a8>] 0xffff800008c60950 [<00000000d5a80534>] platform_drv_probe+0x50/0xa0 [<000000001b3889fc>] really_probe+0x108/0x348 [<00000000953fa60a>] driver_probe_device+0x58/0x100 [<0000000008acc17c>] device_driver_attach+0x6c/0x90 [<0000000022813df3>] __driver_attach+0x84/0xc8 [<00000000448d5443>] bus_for_each_dev+0x74/0xc8 [<00000000294aa93f>] driver_attach+0x20/0x28 [<00000000e5e52626>] bus_add_driver+0x148/0x1f0 [<000000001de21efc>] driver_register+0x60/0x110 [<00000000af07c068>] __platform_driver_register+0x40/0x48 [<0000000060fa80ee>] 0xffff800008c66020
Quoted 6 lines
Fix it here.
Fixes fcb0ee6a3d331fb ("clk: Implement clk_unregister")Cc Tomi Valkeinen <[email protected]>Cc Tero Kristo <[email protected]>Signed-off-by Kishon Vijay Abraham I <[email protected]>
Ignore the v2 of this patch. Sent this patch a bit early. Sorry for the noise.
Thanks
Kishon
Quoted 27 lines
--- drivers/clk/clk.c | 4 ++++ 1 file changed, 4 insertions(+)drivers/clk/clk.c +4
-0@@ -3835,6 +3835,7 @@ static void clk_core_evict_parent_cache(struct clk_core *core)void clk_unregister (struct clk *clk) {unsigned long flags; +struct clk_hw *hw;if (!clk ||WARN_ON_ONCE (IS_ERR (clk)))return ;@@ -3879,6 +3880,9 @@ void clk_unregister(struct clk *clk) __func__, clk->core->name);kref_put (&clk->core->ref, __clk_release); + hw = clk->core->hw; +free_clk (clk); + hw->clk =NULL ; unlock:clk_prepare_unlock (); }
Quoting Kishon Vijay Abraham I (2019-10-22 00:11:53)
Quoted 23 lines
Memory allocated in
alloc_clk()for 'struct clk' and 'const char*con_id' while invokingclk_register()is never freed inclk_unregister(), resulting in kmemleak showing the following backtrace.backtrace:
[<00000000546f5dd0>] kmem_cache_alloc+0x18c/0x270 [<0000000073a32862>] alloc_clk+0x30/0x70 [<0000000082942480>] __clk_register+0xc8/0x760 [<000000005c859fca>] devm_clk_register+0x54/0xb0 [<00000000868834a8>] 0xffff800008c60950 [<00000000d5a80534>] platform_drv_probe+0x50/0xa0 [<000000001b3889fc>] really_probe+0x108/0x348 [<00000000953fa60a>] driver_probe_device+0x58/0x100 [<0000000008acc17c>] device_driver_attach+0x6c/0x90 [<0000000022813df3>] __driver_attach+0x84/0xc8 [<00000000448d5443>] bus_for_each_dev+0x74/0xc8 [<00000000294aa93f>] driver_attach+0x20/0x28 [<00000000e5e52626>] bus_add_driver+0x148/0x1f0 [<000000001de21efc>] driver_register+0x60/0x110 [<00000000af07c068>] __platform_driver_register+0x40/0x48 [<0000000060fa80ee>] 0xffff800008c66020
Quoted 6 lines
Fix it here.
Cc Tomi Valkeinen <[email protected]>Cc Tero Kristo <[email protected]>Signed-off-by Kishon Vijay Abraham I <[email protected]>---
Applied to clk-next
I also added a fixes tag for the best I could guess.