When a battery hook returns an error when adding a new battery, then the battery hook is automatically unregistered. However the battery hook provider cannot know that, so it will later call battery_hook_unregister() on the already unregistered battery hook, resulting in a crash. Fix this by using a boolean flag to mark already unregistered battery hooks as "dead" so that they can be ignored by battery_hook_unregister(). Fixes: fa93854f7a7e ("battery: Add the battery hooking API") Signed-off-by: Armin Wolf <W_Armin@xxxxxx> --- drivers/acpi/battery.c | 11 ++++++++++- include/acpi/battery.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 10e9136897a7..b31a6183a082 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -719,6 +719,7 @@ static void battery_hook_unregister_unlocked(struct acpi_battery_hook *hook) power_supply_changed(battery->bat); } list_del(&hook->list); + hook->dead = true; pr_info("extension unregistered: %s\n", hook->name); } @@ -726,7 +727,14 @@ static void battery_hook_unregister_unlocked(struct acpi_battery_hook *hook) void battery_hook_unregister(struct acpi_battery_hook *hook) { mutex_lock(&hook_mutex); - battery_hook_unregister_unlocked(hook); + /* + * Ignore already unregistered battery hooks. This might happen + * if a battery hook was previously unloaded due to an error when + * adding a new battery. + */ + if (!hook->dead) + battery_hook_unregister_unlocked(hook); + mutex_unlock(&hook_mutex); } EXPORT_SYMBOL_GPL(battery_hook_unregister); @@ -737,6 +745,7 @@ void battery_hook_register(struct acpi_battery_hook *hook) mutex_lock(&hook_mutex); INIT_LIST_HEAD(&hook->list); + hook->dead = false; list_add(&hook->list, &battery_hook_list); /* * Now that the driver is registered, we need diff --git a/include/acpi/battery.h b/include/acpi/battery.h index c93f16dfb944..5cfe132bb7f5 100644 --- a/include/acpi/battery.h +++ b/include/acpi/battery.h @@ -16,6 +16,7 @@ struct acpi_battery_hook { int (*add_battery)(struct power_supply *battery, struct acpi_battery_hook *hook); int (*remove_battery)(struct power_supply *battery, struct acpi_battery_hook *hook); struct list_head list; + bool dead; }; void battery_hook_register(struct acpi_battery_hook *hook); -- 2.39.5