Skip to content

Commit 618541a

Browse files
LGA1150gregkh
authored andcommitted
net: phy: leds: fix memory leak
[ Upstream commit b7f0ee992adf601aa00c252418266177eb7ac2bc ] A network restart test on a router led to an out-of-memory condition, which was traced to a memory leak in the PHY LED trigger code. The root cause is misuse of the devm API. The registration function (phy_led_triggers_register) is called from phy_attach_direct, not phy_probe, and the unregister function (phy_led_triggers_unregister) is called from phy_detach, not phy_remove. This means the register and unregister functions can be called multiple times for the same PHY device, but devm-allocated memory is not freed until the driver is unbound. This also prevents kmemleak from detecting the leak, as the devm API internally stores the allocated pointer. Fix this by replacing devm_kzalloc/devm_kcalloc with standard kzalloc/kcalloc, and add the corresponding kfree calls in the unregister path. Fixes: 3928ee6 ("net: phy: leds: Add support for "link" trigger") Fixes: 2e0bc45 ("net: phy: leds: add support for led triggers on phy link state change") Signed-off-by: Hao Guan <[email protected]> Signed-off-by: Qingfang Deng <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent d5093d6 commit 618541a

File tree

1 file changed

+13
-10
lines changed

1 file changed

+13
-10
lines changed

drivers/net/phy/phy_led_triggers.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,8 @@ int phy_led_triggers_register(struct phy_device *phy)
9191
if (!phy->phy_num_led_triggers)
9292
return 0;
9393

94-
phy->led_link_trigger = devm_kzalloc(&phy->mdio.dev,
95-
sizeof(*phy->led_link_trigger),
96-
GFP_KERNEL);
94+
phy->led_link_trigger = kzalloc(sizeof(*phy->led_link_trigger),
95+
GFP_KERNEL);
9796
if (!phy->led_link_trigger) {
9897
err = -ENOMEM;
9998
goto out_clear;
@@ -103,10 +102,9 @@ int phy_led_triggers_register(struct phy_device *phy)
103102
if (err)
104103
goto out_free_link;
105104

106-
phy->phy_led_triggers = devm_kcalloc(&phy->mdio.dev,
107-
phy->phy_num_led_triggers,
108-
sizeof(struct phy_led_trigger),
109-
GFP_KERNEL);
105+
phy->phy_led_triggers = kcalloc(phy->phy_num_led_triggers,
106+
sizeof(struct phy_led_trigger),
107+
GFP_KERNEL);
110108
if (!phy->phy_led_triggers) {
111109
err = -ENOMEM;
112110
goto out_unreg_link;
@@ -127,11 +125,11 @@ int phy_led_triggers_register(struct phy_device *phy)
127125
out_unreg:
128126
while (i--)
129127
phy_led_trigger_unregister(&phy->phy_led_triggers[i]);
130-
devm_kfree(&phy->mdio.dev, phy->phy_led_triggers);
128+
kfree(phy->phy_led_triggers);
131129
out_unreg_link:
132130
phy_led_trigger_unregister(phy->led_link_trigger);
133131
out_free_link:
134-
devm_kfree(&phy->mdio.dev, phy->led_link_trigger);
132+
kfree(phy->led_link_trigger);
135133
phy->led_link_trigger = NULL;
136134
out_clear:
137135
phy->phy_num_led_triggers = 0;
@@ -145,8 +143,13 @@ void phy_led_triggers_unregister(struct phy_device *phy)
145143

146144
for (i = 0; i < phy->phy_num_led_triggers; i++)
147145
phy_led_trigger_unregister(&phy->phy_led_triggers[i]);
146+
kfree(phy->phy_led_triggers);
147+
phy->phy_led_triggers = NULL;
148148

149-
if (phy->led_link_trigger)
149+
if (phy->led_link_trigger) {
150150
phy_led_trigger_unregister(phy->led_link_trigger);
151+
kfree(phy->led_link_trigger);
152+
phy->led_link_trigger = NULL;
153+
}
151154
}
152155
EXPORT_SYMBOL_GPL(phy_led_triggers_unregister);

0 commit comments

Comments
 (0)