From: Krzysztof Kozlowski Date: Thu, 12 Mar 2015 07:44:12 +0000 (+0100) Subject: power_supply: Add power_supply_put for decrementing device reference counter X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=1a352462b5377ac68f5955d674b3460c7bac52a3;p=deliverable%2Flinux.git power_supply: Add power_supply_put for decrementing device reference counter The power_supply_get_by_phandle() and power_supply_get_by_name() use function class_find_device() for obtaining the reference to power supply. Each use of class_find_device() increases the power supply's device reference counter. However the reference counter was not decreased by users of this API. Thus final device_unregister() call from power_supply_unregister() could not release the device and clean up its resources. This lead to memory leak if at least once power_supply_get_by_*() was called between registering and unregistering the power supply. Add and document new API power_supply_put() for decrementing the reference counter. Signed-off-by: Krzysztof Kozlowski Acked-by: Pavel Machek Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Sebastian Reichel Signed-off-by: Sebastian Reichel --- diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index e51405b176c8..b4ec14683b7f 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -336,6 +336,17 @@ static int power_supply_match_device_by_name(struct device *dev, const void *dat return strcmp(psy->desc->name, name) == 0; } +/** + * power_supply_get_by_name() - Search for a power supply and returns its ref + * @name: Power supply name to fetch + * + * If power supply was found, it increases reference count for the + * internal power supply's device. The user should power_supply_put() + * after usage. + * + * Return: On success returns a reference to a power supply with + * matching name equals to @name, a NULL otherwise. + */ struct power_supply *power_supply_get_by_name(const char *name) { struct device *dev = class_find_device(power_supply_class, NULL, name, @@ -345,12 +356,39 @@ struct power_supply *power_supply_get_by_name(const char *name) } EXPORT_SYMBOL_GPL(power_supply_get_by_name); +/** + * power_supply_put() - Drop reference obtained with power_supply_get_by_name + * @psy: Reference to put + * + * The reference to power supply should be put before unregistering + * the power supply. + */ +void power_supply_put(struct power_supply *psy) +{ + might_sleep(); + + put_device(&psy->dev); +} +EXPORT_SYMBOL_GPL(power_supply_put); + #ifdef CONFIG_OF static int power_supply_match_device_node(struct device *dev, const void *data) { return dev->parent && dev->parent->of_node == data; } +/** + * power_supply_get_by_phandle() - Search for a power supply and returns its ref + * @np: Pointer to device node holding phandle property + * @phandle_name: Name of property holding a power supply name + * + * If power supply was found, it increases reference count for the + * internal power supply's device. The user should power_supply_put() + * after usage. + * + * Return: On success returns a reference to a power supply with + * matching name equals to value under @property, NULL or ERR_PTR otherwise. + */ struct power_supply *power_supply_get_by_phandle(struct device_node *np, const char *property) { diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index ea15eb68f609..75a1dd8dc56e 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -282,6 +282,7 @@ extern struct atomic_notifier_head power_supply_notifier; extern int power_supply_reg_notifier(struct notifier_block *nb); extern void power_supply_unreg_notifier(struct notifier_block *nb); extern struct power_supply *power_supply_get_by_name(const char *name); +extern void power_supply_put(struct power_supply *psy); #ifdef CONFIG_OF extern struct power_supply *power_supply_get_by_phandle(struct device_node *np, const char *property);