On Sun, Sep 22, 2024 at 8:40 AM Armin Wolf <W_Armin@xxxxxx> wrote: > > 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; It looks like you could do list_del_init((&hook->list); here and then do a list_emtpy() check below. > > 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) if (!list_empty(&hook->list)) > + battery_hook_unregister_unlocked(hook); > + > mutex_unlock(&hook_mutex); and the new struct field would not be necessary if I'm not mistaken. > } > 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); Also the above statement is redundant, so maybe drop it while you're at it? > + 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); > --