* [PATCH v2] leds: netxbig: Fix platform device reference leak on successful probe
2026-09-22 16:03 ` Lee Jones
@ 2026-11-07 4:27 ` Wentao Liang
0 siblings, 0 replies; 3+ messages in thread
From: Wentao Liang @ 2026-11-07 4:27 UTC (permalink / raw)
To: Lee Jones; +Cc: linusw, linux-kernel, linux-leds, pavel, vulab, stable
of_find_device_by_node() returns the GPIO extension device with an
elevated reference count. The error paths release it through the
put_device label, but the success path returns directly, so the
reference is leaked whenever the LED driver probes successfully.
Release the reference right after its last use and remove the put_device
label and the gotos leading to it.
Fixes: 9af512e81964 ("leds: netxbig: Convert to use GPIO descriptors")
Suggested-by: Lee Jones <lee@kernel.org>
Cc: stable@vger.kernel.org
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
---
Changes in v2:
- Release the reference right after its last use and remove the put_device
label and the gotos, as suggested.
- Apologies for the very late reply.
drivers/leds/leds-netxbig.c | 74 ++++++++++++++-----------------------
1 file changed, 27 insertions(+), 47 deletions(-)
diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c
index 99df46f2d9f5..3a0456eae2c3 100644
--- a/drivers/leds/leds-netxbig.c
+++ b/drivers/leds/leds-netxbig.c
@@ -462,41 +462,36 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
gpio_ext_dev = &gpio_ext_pdev->dev;
gpio_ext = devm_kzalloc(dev, sizeof(*gpio_ext), GFP_KERNEL);
- if (!gpio_ext) {
- of_node_put(gpio_ext_np);
+ if (!gpio_ext)
ret = -ENOMEM;
- goto put_device;
- }
- ret = netxbig_gpio_ext_get(dev, gpio_ext_dev, gpio_ext);
+ else
+ ret = netxbig_gpio_ext_get(dev, gpio_ext_dev, gpio_ext);
+
of_node_put(gpio_ext_np);
+ put_device(gpio_ext_dev);
if (ret)
- goto put_device;
+ return ret;
+
pdata->gpio_ext = gpio_ext;
/* Timers (optional) */
ret = of_property_count_u32_elems(np, "timers");
if (ret > 0) {
- if (ret % 3) {
- ret = -EINVAL;
- goto put_device;
- }
+ if (ret % 3)
+ return -EINVAL;
num_timers = ret / 3;
timers = devm_kcalloc(dev, num_timers, sizeof(*timers),
GFP_KERNEL);
- if (!timers) {
- ret = -ENOMEM;
- goto put_device;
- }
+ if (!timers)
+ return -ENOMEM;
for (i = 0; i < num_timers; i++) {
u32 tmp;
of_property_read_u32_index(np, "timers", 3 * i,
&timers[i].mode);
- if (timers[i].mode >= NETXBIG_LED_MODE_NUM) {
- ret = -EINVAL;
- goto put_device;
- }
+ if (timers[i].mode >= NETXBIG_LED_MODE_NUM)
+ return -EINVAL;
of_property_read_u32_index(np, "timers",
3 * i + 1, &tmp);
timers[i].delay_on = tmp;
@@ -512,15 +507,12 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
num_leds = of_get_available_child_count(np);
if (!num_leds) {
dev_err(dev, "No LED subnodes found in DT\n");
- ret = -ENODEV;
- goto put_device;
+ return -ENODEV;
}
leds = devm_kcalloc(dev, num_leds, sizeof(*leds), GFP_KERNEL);
- if (!leds) {
- ret = -ENOMEM;
- goto put_device;
- }
+ if (!leds)
+ return -ENOMEM;
led = leds;
for_each_available_child_of_node_scoped(np, child) {
@@ -531,40 +523,34 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
ret = of_property_read_u32(child, "mode-addr",
&led->mode_addr);
if (ret)
- goto put_device;
+ return ret;
ret = of_property_read_u32(child, "bright-addr",
&led->bright_addr);
if (ret)
- goto put_device;
+ return ret;
ret = of_property_read_u32(child, "max-brightness",
&led->bright_max);
if (ret)
- goto put_device;
+ return ret;
mode_val =
devm_kcalloc(dev,
NETXBIG_LED_MODE_NUM, sizeof(*mode_val),
GFP_KERNEL);
- if (!mode_val) {
- ret = -ENOMEM;
- goto put_device;
- }
+ if (!mode_val)
+ return -ENOMEM;
for (i = 0; i < NETXBIG_LED_MODE_NUM; i++)
mode_val[i] = NETXBIG_LED_INVALID_MODE;
ret = of_property_count_u32_elems(child, "mode-val");
- if (ret < 0 || ret % 2) {
- ret = -EINVAL;
- goto put_device;
- }
+ if (ret < 0 || ret % 2)
+ return -EINVAL;
num_modes = ret / 2;
- if (num_modes > NETXBIG_LED_MODE_NUM) {
- ret = -EINVAL;
- goto put_device;
- }
+ if (num_modes > NETXBIG_LED_MODE_NUM)
+ return -EINVAL;
for (i = 0; i < num_modes; i++) {
int mode;
@@ -574,10 +560,8 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
"mode-val", 2 * i, &mode);
of_property_read_u32_index(child,
"mode-val", 2 * i + 1, &val);
- if (mode >= NETXBIG_LED_MODE_NUM) {
- ret = -EINVAL;
- goto put_device;
- }
+ if (mode >= NETXBIG_LED_MODE_NUM)
+ return -EINVAL;
mode_val[mode] = val;
}
led->mode_val = mode_val;
@@ -598,10 +582,6 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
pdata->num_leds = num_leds;
return 0;
-
-put_device:
- put_device(gpio_ext_dev);
- return ret;
}
static const struct of_device_id of_netxbig_leds_match[] = {
--
2.25.1
^ permalink raw reply related [flat|nested] 3+ messages in thread