Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

leds: pca995x: Fix device child node usage in pca995x_probe()

The current implementation accesses the `child` fwnode handle outside of
device_for_each_child_node() without incrementing its refcount.

Add the missing call to `fwnode_handle_get(child)`.

The cleanup process where `child` is accessed is not right either
because a single call to `fwnode_handle_put()` is carried out in case of
an error, ignoring unasigned nodes at the point when the error happens.

Keep `child` inside of the first loop, and use the helper pointer that
receives references via `fwnode_handle_get()` to handle the child nodes
within the second loop. Keeping `child` inside the first node has also
the advantage that the scoped version of the loop can be used.

Fixes: ee4e80b2962e ("leds: pca995x: Add support for PCA995X chips")
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://lore.kernel.org/r/20240807-leds-pca995x-fix-fwnode-usage-v1-1-8057c84dc583@gmail.com
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Javier Carrasco and committed by
Lee Jones
82c5ada1 616dbed6

+5 -5
+5 -5
drivers/leds/leds-pca995x.c
··· 120 120 static int pca995x_probe(struct i2c_client *client) 121 121 { 122 122 struct fwnode_handle *led_fwnodes[PCA995X_MAX_OUTPUTS] = { 0 }; 123 - struct fwnode_handle *child; 124 123 struct device *dev = &client->dev; 125 124 const struct pca995x_chipdef *chipdef; 126 125 struct pca995x_chip *chip; 127 126 struct pca995x_led *led; 128 - int i, reg, ret; 127 + int i, j, reg, ret; 129 128 130 129 chipdef = device_get_match_data(&client->dev); 131 130 ··· 142 143 143 144 i2c_set_clientdata(client, chip); 144 145 145 - device_for_each_child_node(dev, child) { 146 + device_for_each_child_node_scoped(dev, child) { 146 147 ret = fwnode_property_read_u32(child, "reg", &reg); 147 148 if (ret) 148 149 return ret; ··· 151 152 return -EINVAL; 152 153 153 154 led = &chip->leds[reg]; 154 - led_fwnodes[reg] = child; 155 + led_fwnodes[reg] = fwnode_handle_get(child); 155 156 led->chip = chip; 156 157 led->led_no = reg; 157 158 led->ldev.brightness_set_blocking = pca995x_brightness_set; ··· 170 171 &chip->leds[i].ldev, 171 172 &init_data); 172 173 if (ret < 0) { 173 - fwnode_handle_put(child); 174 + for (j = i; j < PCA995X_MAX_OUTPUTS; j++) 175 + fwnode_handle_put(led_fwnodes[j]); 174 176 return dev_err_probe(dev, ret, 175 177 "Could not register LED %s\n", 176 178 chip->leds[i].ldev.name);