opp: fix memory leak in _allocate_opp_table
In function _allocate_opp_table, opp_dev is allocated and referenced
by opp_table via _add_opp_dev. But in the case that the subsequent calls
return -EPROBE_DEFER, it will jump to err label and opp_table will be
freed. Then opp_dev becomes an unreferenced object to cause memory leak.
So let's call _remove_opp_dev to do the cleanup.
This fixes the following kmemleak report:
unreferenced object 0xffff000801524a00 (size 128):
comm "swapper/0", pid 1, jiffies 4294892465 (age 84.616s)
hex dump (first 32 bytes):
40 00 56 01 08 00 ff ff 40 00 56 01 08 00 ff ff @.V.....@.V.....
b8 52 77 7f 08 00 ff ff 00 3c 4c 00 08 00 ff ff .Rw......<L.....
backtrace:
[<00000000b1289fb1>] kmemleak_alloc+0x30/0x40
[<0000000056da48f0>] kmem_cache_alloc+0x3d4/0x588
[<00000000a84b3b0e>] _add_opp_dev+0x2c/0x88
[<0000000062a380cd>] _add_opp_table_indexed+0x124/0x268
[<000000008b4c8f1f>] dev_pm_opp_of_add_table+0x20/0x1d8
[<00000000e5316798>] dev_pm_opp_of_cpumask_add_table+0x48/0xf0
[<00000000db0a8ec2>] dt_cpufreq_probe+0x20c/0x448
[<0000000030a3a26c>] platform_probe+0x68/0xd8
[<00000000c618e78d>] really_probe+0xd0/0x3a0
[<00000000642e856f>] driver_probe_device+0x58/0xb8
[<00000000f10f5307>] device_driver_attach+0x74/0x80
[<0000000004f254b8>] __driver_attach+0x58/0xe0
[<0000000009d5d19e>] bus_for_each_dev+0x70/0xc8
[<0000000000d22e1c>] driver_attach+0x24/0x30
[<0000000001d4e952>] bus_add_driver+0x14c/0x1f0
[<0000000089928aaa>] driver_register+0x64/0x120
Cc: v5.10 <stable@vger.kernel.org> # v5.10
Fixes: dd461cd918
("opp: Allow dev_pm_opp_get_opp_table() to return -EPROBE_DEFER")
Signed-off-by: Quanyang Wang <quanyang.wang@windriver.com>
[ Viresh: Added the stable tag ]
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
This commit is contained in:
parent
5c8fe583cc
commit
976509bb31
|
@ -1092,7 +1092,7 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)
|
||||||
if (IS_ERR(opp_table->clk)) {
|
if (IS_ERR(opp_table->clk)) {
|
||||||
ret = PTR_ERR(opp_table->clk);
|
ret = PTR_ERR(opp_table->clk);
|
||||||
if (ret == -EPROBE_DEFER)
|
if (ret == -EPROBE_DEFER)
|
||||||
goto err;
|
goto remove_opp_dev;
|
||||||
|
|
||||||
dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__, ret);
|
dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__, ret);
|
||||||
}
|
}
|
||||||
|
@ -1101,7 +1101,7 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)
|
||||||
ret = dev_pm_opp_of_find_icc_paths(dev, opp_table);
|
ret = dev_pm_opp_of_find_icc_paths(dev, opp_table);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret == -EPROBE_DEFER)
|
if (ret == -EPROBE_DEFER)
|
||||||
goto err;
|
goto remove_opp_dev;
|
||||||
|
|
||||||
dev_warn(dev, "%s: Error finding interconnect paths: %d\n",
|
dev_warn(dev, "%s: Error finding interconnect paths: %d\n",
|
||||||
__func__, ret);
|
__func__, ret);
|
||||||
|
@ -1113,6 +1113,8 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)
|
||||||
|
|
||||||
return opp_table;
|
return opp_table;
|
||||||
|
|
||||||
|
remove_opp_dev:
|
||||||
|
_remove_opp_dev(opp_dev, opp_table);
|
||||||
err:
|
err:
|
||||||
kfree(opp_table);
|
kfree(opp_table);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
Loading…
Reference in New Issue