regulator: Fully clean up on error in of_regulator_bulk_get_all()
Currently in of_regulator_bulk_get_all(), if any regulator request fails, the error path releases all regulators already requested, but leaves the |struct regulator_bulk_data| memory to the caller to free, and also leaves the regulator consumer pointers dangling. The latter behavior is not documented, and may not be what the caller is expecting. Instead, explicitly clean up everything on error, and make it clear that the result pointer is only update if the whole request succeeds. Signed-off-by: Chen-Yu Tsai <wenst@chromium.org> Link: https://patch.msgid.link/20240822072047.3097740-4-wenst@chromium.org Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
395a41a1d3
commit
bfefa214d1
@ -747,19 +747,19 @@ static int is_supply_name(const char *name)
|
|||||||
* This helper function allows drivers to get several regulator
|
* This helper function allows drivers to get several regulator
|
||||||
* consumers in one operation. If any of the regulators cannot be
|
* consumers in one operation. If any of the regulators cannot be
|
||||||
* acquired then any regulators that were allocated will be freed
|
* acquired then any regulators that were allocated will be freed
|
||||||
* before returning to the caller.
|
* before returning to the caller, and @consumers will not be
|
||||||
|
* changed.
|
||||||
*/
|
*/
|
||||||
int of_regulator_bulk_get_all(struct device *dev, struct device_node *np,
|
int of_regulator_bulk_get_all(struct device *dev, struct device_node *np,
|
||||||
struct regulator_bulk_data **consumers)
|
struct regulator_bulk_data **consumers)
|
||||||
{
|
{
|
||||||
int num_consumers = 0;
|
int num_consumers = 0;
|
||||||
struct regulator *tmp;
|
struct regulator *tmp;
|
||||||
|
struct regulator_bulk_data *_consumers = NULL;
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
int i, n = 0, ret;
|
int i, n = 0, ret;
|
||||||
char name[64];
|
char name[64];
|
||||||
|
|
||||||
*consumers = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* first pass: get numbers of xxx-supply
|
* first pass: get numbers of xxx-supply
|
||||||
* second pass: fill consumers
|
* second pass: fill consumers
|
||||||
@ -769,7 +769,7 @@ restart:
|
|||||||
i = is_supply_name(prop->name);
|
i = is_supply_name(prop->name);
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
continue;
|
continue;
|
||||||
if (!*consumers) {
|
if (!_consumers) {
|
||||||
num_consumers++;
|
num_consumers++;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
@ -780,25 +780,28 @@ restart:
|
|||||||
ret = PTR_ERR(tmp);
|
ret = PTR_ERR(tmp);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
(*consumers)[n].consumer = tmp;
|
_consumers[n].consumer = tmp;
|
||||||
n++;
|
n++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (*consumers)
|
if (_consumers) {
|
||||||
|
*consumers = _consumers;
|
||||||
return num_consumers;
|
return num_consumers;
|
||||||
|
}
|
||||||
if (num_consumers == 0)
|
if (num_consumers == 0)
|
||||||
return 0;
|
return 0;
|
||||||
*consumers = kmalloc_array(num_consumers,
|
_consumers = kmalloc_array(num_consumers,
|
||||||
sizeof(struct regulator_bulk_data),
|
sizeof(struct regulator_bulk_data),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!*consumers)
|
if (!_consumers)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
goto restart;
|
goto restart;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
while (--n >= 0)
|
while (--n >= 0)
|
||||||
regulator_put(consumers[n]->consumer);
|
regulator_put(_consumers[n].consumer);
|
||||||
|
kfree(_consumers);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(of_regulator_bulk_get_all);
|
EXPORT_SYMBOL_GPL(of_regulator_bulk_get_all);
|
||||||
|
Loading…
Reference in New Issue
Block a user