* [PATCH] platform/x86: dell-ddv: Fix taking the psy->extensions_sem lock twice
@ 2025-06-20 17:58 Hans de Goede
2025-06-22 18:41 ` Armin Wolf
0 siblings, 1 reply; 5+ messages in thread
From: Hans de Goede @ 2025-06-20 17:58 UTC (permalink / raw)
To: Ilpo Järvinen, Andy Shevchenko, Armin Wolf
Cc: Hans de Goede, platform-driver-x86
dell_wmi_ddv_get_property() gets called with psy->extensions_sem
read-locked, it calls dell_wmi_ddv_battery_translate() which calls
power_supply_get_property() on the same psy which again read-locks
psy->extensions_sem.
Lockdep rightfully complains about this:
============================================
WARNING: possible recursive locking detected
...
kworker/16:3/1230 is trying to acquire lock:
ffff8c3143417658 (&psy->extensions_sem){++++}-{4:4},
at: power_supply_get_property.part.0+0x23/0x160
but task is already holding lock:
ffff8c3143417658 (&psy->extensions_sem){++++}-{4:4},
at: power_supply_get_property.part.0+0x23/0x160
...
Possible unsafe locking scenario:
CPU0
----
lock(&psy->extensions_sem);
lock(&psy->extensions_sem);
*** DEADLOCK ***
...
Call Trace:
<TASK>
...
down_read+0x3e/0x180
? power_supply_get_property.part.0+0x23/0x160
power_supply_get_property.part.0+0x23/0x160
dell_wmi_ddv_battery_translate+0x68/0x1d0 [dell_wmi_ddv]
? lock_acquire+0xd9/0x2c0
dell_wmi_ddv_get_property+0x25/0x240 [dell_wmi_ddv]
power_supply_get_property.part.0+0x87/0x160
power_supply_format_property+0xc4/0x3d0
add_prop_uevent+0x26/0x90
power_supply_uevent+0xb9/0xf0
This usually works fine, because read-locking can be done multiple times
but if someone tries to write-lock between the 2 read-lock calls then
the second read-lock will block on the write-lock and the write-lock will
be blocked on the first read-lock leading to a deadlock.
The serial is part of the main psy device, not of an extension. Directly
call psy->desc->get_property() in dell_wmi_ddv_battery_translate() to fix
the double-lock issue.
Note this also influences eppid_show() which is called directly rather
then through power_supply_get_property(). This is ok since the ACPI
battery is fully ready to be used when the battery hook's add_battery
callback is called.
Fixes: 058de163a376 ("platform/x86: dell-ddv: Implement the battery matching algorithm")
Signed-off-by: Hans de Goede <hansg@kernel.org>
---
drivers/platform/x86/dell/dell-wmi-ddv.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c
index 67f3d7158403..95cc3139f271 100644
--- a/drivers/platform/x86/dell/dell-wmi-ddv.c
+++ b/drivers/platform/x86/dell/dell-wmi-ddv.c
@@ -689,9 +689,11 @@ static int dell_wmi_ddv_battery_translate(struct dell_wmi_ddv_data *data,
dev_dbg(&data->wdev->dev, "Translation cache miss\n");
- /* Perform a translation between a ACPI battery and a battery index */
-
- ret = power_supply_get_property(battery, POWER_SUPPLY_PROP_SERIAL_NUMBER, &val);
+ /*
+ * Perform a translation between a ACPI battery and a battery index. Directly call
+ * desc->get_property() to avoid locking battery->extensions_sem a second time.
+ */
+ ret = battery->desc->get_property(battery, POWER_SUPPLY_PROP_SERIAL_NUMBER, &val);
if (ret < 0)
return ret;
--
2.49.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH] platform/x86: dell-ddv: Fix taking the psy->extensions_sem lock twice 2025-06-20 17:58 [PATCH] platform/x86: dell-ddv: Fix taking the psy->extensions_sem lock twice Hans de Goede @ 2025-06-22 18:41 ` Armin Wolf 2025-06-22 20:59 ` Hans de Goede 0 siblings, 1 reply; 5+ messages in thread From: Armin Wolf @ 2025-06-22 18:41 UTC (permalink / raw) To: Hans de Goede, Ilpo Järvinen, Andy Shevchenko; +Cc: platform-driver-x86 Am 20.06.25 um 19:58 schrieb Hans de Goede: > dell_wmi_ddv_get_property() gets called with psy->extensions_sem > read-locked, it calls dell_wmi_ddv_battery_translate() which calls > power_supply_get_property() on the same psy which again read-locks > psy->extensions_sem. > > Lockdep rightfully complains about this: > > ============================================ > WARNING: possible recursive locking detected > ... > kworker/16:3/1230 is trying to acquire lock: > ffff8c3143417658 (&psy->extensions_sem){++++}-{4:4}, > at: power_supply_get_property.part.0+0x23/0x160 > but task is already holding lock: > ffff8c3143417658 (&psy->extensions_sem){++++}-{4:4}, > at: power_supply_get_property.part.0+0x23/0x160 > ... > Possible unsafe locking scenario: > > CPU0 > ---- > lock(&psy->extensions_sem); > lock(&psy->extensions_sem); > > *** DEADLOCK *** > ... > Call Trace: > <TASK> > ... > down_read+0x3e/0x180 > ? power_supply_get_property.part.0+0x23/0x160 > power_supply_get_property.part.0+0x23/0x160 > dell_wmi_ddv_battery_translate+0x68/0x1d0 [dell_wmi_ddv] > ? lock_acquire+0xd9/0x2c0 > dell_wmi_ddv_get_property+0x25/0x240 [dell_wmi_ddv] > power_supply_get_property.part.0+0x87/0x160 > power_supply_format_property+0xc4/0x3d0 > add_prop_uevent+0x26/0x90 > power_supply_uevent+0xb9/0xf0 > > This usually works fine, because read-locking can be done multiple times > but if someone tries to write-lock between the 2 read-lock calls then > the second read-lock will block on the write-lock and the write-lock will > be blocked on the first read-lock leading to a deadlock. > > The serial is part of the main psy device, not of an extension. Directly > call psy->desc->get_property() in dell_wmi_ddv_battery_translate() to fix > the double-lock issue. > > Note this also influences eppid_show() which is called directly rather > then through power_supply_get_property(). This is ok since the ACPI > battery is fully ready to be used when the battery hook's add_battery > callback is called. Thank you very much for finding this issue, but i think that simply calling battery->desc->get_property() is not the right solution for this: 1. We should still call psy_desc_has_property() to determine if the power supply actually support POWER_SUPPLY_PROP_SERIAL_NUMBER. 2. At least another power supply extension user (the uniwill-laptop driver currently being under review) suffers from a similar problem, so a more generic solution is needed. Maybe we could introduce a new function for reading power supply properties that ignores any power supply extensions? This way future extension could use this function too. I envision something like this: int power_supply_get_property_direct(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { if (atomic_read(&psy->use_cnt) <= 0) { if (!psy->initialized) return -EAGAIN; return -ENODEV; } if (psy_desc_has_property(psy->desc, psp)) return psy->desc->get_property(psy, psp, val); else if (power_supply_battery_info_has_prop(psy->battery_info, psp)) return power_supply_battery_info_get_prop(psy->battery_info, psp, val); else return -EINVAL; } EXPORT_SYMBOL_GPL(power_supply_get_property_direct); It basically is power_supply_get_property() without the extension logic. I can also write some documentation on how to implement power supply extensions in general. What do you thing? Thanks, Armin Wolf > Fixes: 058de163a376 ("platform/x86: dell-ddv: Implement the battery matching algorithm") > Signed-off-by: Hans de Goede <hansg@kernel.org> > --- > drivers/platform/x86/dell/dell-wmi-ddv.c | 8 +++++--- > 1 file changed, 5 insertions(+), 3 deletions(-) > > diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c > index 67f3d7158403..95cc3139f271 100644 > --- a/drivers/platform/x86/dell/dell-wmi-ddv.c > +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c > @@ -689,9 +689,11 @@ static int dell_wmi_ddv_battery_translate(struct dell_wmi_ddv_data *data, > > dev_dbg(&data->wdev->dev, "Translation cache miss\n"); > > - /* Perform a translation between a ACPI battery and a battery index */ > - > - ret = power_supply_get_property(battery, POWER_SUPPLY_PROP_SERIAL_NUMBER, &val); > + /* > + * Perform a translation between a ACPI battery and a battery index. Directly call > + * desc->get_property() to avoid locking battery->extensions_sem a second time. > + */ > + ret = battery->desc->get_property(battery, POWER_SUPPLY_PROP_SERIAL_NUMBER, &val); > if (ret < 0) > return ret; > ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] platform/x86: dell-ddv: Fix taking the psy->extensions_sem lock twice 2025-06-22 18:41 ` Armin Wolf @ 2025-06-22 20:59 ` Hans de Goede 2025-06-22 22:08 ` Armin Wolf 0 siblings, 1 reply; 5+ messages in thread From: Hans de Goede @ 2025-06-22 20:59 UTC (permalink / raw) To: Armin Wolf, Ilpo Järvinen, Andy Shevchenko, Sebastian Reichel Cc: platform-driver-x86, Linux PM + Cc sre, whom I should have Cc-ed from the beginning. Hi Armin, On 22-Jun-25 8:41 PM, Armin Wolf wrote: > Am 20.06.25 um 19:58 schrieb Hans de Goede: > >> dell_wmi_ddv_get_property() gets called with psy->extensions_sem >> read-locked, it calls dell_wmi_ddv_battery_translate() which calls >> power_supply_get_property() on the same psy which again read-locks >> psy->extensions_sem. >> >> Lockdep rightfully complains about this: >> >> ============================================ >> WARNING: possible recursive locking detected >> ... >> kworker/16:3/1230 is trying to acquire lock: >> ffff8c3143417658 (&psy->extensions_sem){++++}-{4:4}, >> at: power_supply_get_property.part.0+0x23/0x160 >> but task is already holding lock: >> ffff8c3143417658 (&psy->extensions_sem){++++}-{4:4}, >> at: power_supply_get_property.part.0+0x23/0x160 >> ... >> Possible unsafe locking scenario: >> >> CPU0 >> ---- >> lock(&psy->extensions_sem); >> lock(&psy->extensions_sem); >> >> *** DEADLOCK *** >> ... >> Call Trace: >> <TASK> >> ... >> down_read+0x3e/0x180 >> ? power_supply_get_property.part.0+0x23/0x160 >> power_supply_get_property.part.0+0x23/0x160 >> dell_wmi_ddv_battery_translate+0x68/0x1d0 [dell_wmi_ddv] >> ? lock_acquire+0xd9/0x2c0 >> dell_wmi_ddv_get_property+0x25/0x240 [dell_wmi_ddv] >> power_supply_get_property.part.0+0x87/0x160 >> power_supply_format_property+0xc4/0x3d0 >> add_prop_uevent+0x26/0x90 >> power_supply_uevent+0xb9/0xf0 >> >> This usually works fine, because read-locking can be done multiple times >> but if someone tries to write-lock between the 2 read-lock calls then >> the second read-lock will block on the write-lock and the write-lock will >> be blocked on the first read-lock leading to a deadlock. >> >> The serial is part of the main psy device, not of an extension. Directly >> call psy->desc->get_property() in dell_wmi_ddv_battery_translate() to fix >> the double-lock issue. >> >> Note this also influences eppid_show() which is called directly rather >> then through power_supply_get_property(). This is ok since the ACPI >> battery is fully ready to be used when the battery hook's add_battery >> callback is called. > > Thank you very much for finding this issue, but i think that simply calling battery->desc->get_property() > is not the right solution for this: > > 1. We should still call psy_desc_has_property() to determine if the power supply actually support > POWER_SUPPLY_PROP_SERIAL_NUMBER. Although it is currently not enforced in power_supply_core.c it seems reasonable to assume that any powersupply must have a get_property callback in their desc (the core also unconditionally calls this). And most (all?) psy drivers I've seen have a default which returns -EINVAL in their get_property() implementation which works just as well as calling has_prop ... My bigger worry is the lack of the: > if (atomic_read(&psy->use_cnt) <= 0) { > if (!psy->initialized) > return -EAGAIN; > return -ENODEV; > } Check TBH. > 2. At least another power supply extension user (the uniwill-laptop driver currently being under review) > suffers from a similar problem, so a more generic solution is needed. > > Maybe we could introduce a new function for reading power supply properties that ignores any > power supply extensions? This way future extension could use this function too. > > I envision something like this: > > int power_supply_get_property_direct(struct power_supply *psy, > enum power_supply_property psp, > union power_supply_propval *val) > { > if (atomic_read(&psy->use_cnt) <= 0) { > if (!psy->initialized) > return -EAGAIN; > return -ENODEV; > } > > if (psy_desc_has_property(psy->desc, psp)) > return psy->desc->get_property(psy, psp, val); > else if (power_supply_battery_info_has_prop(psy->battery_info, psp)) > return power_supply_battery_info_get_prop(psy->battery_info, psp, val); > else > return -EINVAL; > } > EXPORT_SYMBOL_GPL(power_supply_get_property_direct); > > It basically is power_supply_get_property() without the extension logic. While working on this fix I was thinking that something like this would be useful, so +1 for this. Maybe first do a prep patch where the extension handling in power_supply_get_property() is moved last, then power_supply_get_property() can just wrap this new helprr and on -EINVAL check the extensions. Actually if you move the extensions check to last then the whole doublelock issue goes away because the serial-number will be found before checking extensions. Or if you want to keep checking the extensions first change the current power_supply_get_property() into a new __power_supply_get_property() with a "bool check_extensions" argument and make power_supply_get_property() wrap it pasing true for check_extensions. Or some such, whatever you do try to avoid code duplication but you already know this ... > I can also write some > documentation on how to implement power supply extensions in general. That would also be good to have. Regards, Hans >> Fixes: 058de163a376 ("platform/x86: dell-ddv: Implement the battery matching algorithm") >> Signed-off-by: Hans de Goede <hansg@kernel.org> >> --- >> drivers/platform/x86/dell/dell-wmi-ddv.c | 8 +++++--- >> 1 file changed, 5 insertions(+), 3 deletions(-) >> >> diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c >> index 67f3d7158403..95cc3139f271 100644 >> --- a/drivers/platform/x86/dell/dell-wmi-ddv.c >> +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c >> @@ -689,9 +689,11 @@ static int dell_wmi_ddv_battery_translate(struct dell_wmi_ddv_data *data, >> dev_dbg(&data->wdev->dev, "Translation cache miss\n"); >> - /* Perform a translation between a ACPI battery and a battery index */ >> - >> - ret = power_supply_get_property(battery, POWER_SUPPLY_PROP_SERIAL_NUMBER, &val); >> + /* >> + * Perform a translation between a ACPI battery and a battery index. Directly call >> + * desc->get_property() to avoid locking battery->extensions_sem a second time. >> + */ >> + ret = battery->desc->get_property(battery, POWER_SUPPLY_PROP_SERIAL_NUMBER, &val); >> if (ret < 0) >> return ret; >> ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] platform/x86: dell-ddv: Fix taking the psy->extensions_sem lock twice 2025-06-22 20:59 ` Hans de Goede @ 2025-06-22 22:08 ` Armin Wolf 2025-06-23 22:35 ` Sebastian Reichel 0 siblings, 1 reply; 5+ messages in thread From: Armin Wolf @ 2025-06-22 22:08 UTC (permalink / raw) To: Hans de Goede, Ilpo Järvinen, Andy Shevchenko, Sebastian Reichel Cc: platform-driver-x86, Linux PM Am 22.06.25 um 22:59 schrieb Hans de Goede: > + Cc sre, whom I should have Cc-ed from the beginning. > > Hi Armin, > > On 22-Jun-25 8:41 PM, Armin Wolf wrote: >> Am 20.06.25 um 19:58 schrieb Hans de Goede: >> >>> dell_wmi_ddv_get_property() gets called with psy->extensions_sem >>> read-locked, it calls dell_wmi_ddv_battery_translate() which calls >>> power_supply_get_property() on the same psy which again read-locks >>> psy->extensions_sem. >>> >>> Lockdep rightfully complains about this: >>> >>> ============================================ >>> WARNING: possible recursive locking detected >>> ... >>> kworker/16:3/1230 is trying to acquire lock: >>> ffff8c3143417658 (&psy->extensions_sem){++++}-{4:4}, >>> at: power_supply_get_property.part.0+0x23/0x160 >>> but task is already holding lock: >>> ffff8c3143417658 (&psy->extensions_sem){++++}-{4:4}, >>> at: power_supply_get_property.part.0+0x23/0x160 >>> ... >>> Possible unsafe locking scenario: >>> >>> CPU0 >>> ---- >>> lock(&psy->extensions_sem); >>> lock(&psy->extensions_sem); >>> >>> *** DEADLOCK *** >>> ... >>> Call Trace: >>> <TASK> >>> ... >>> down_read+0x3e/0x180 >>> ? power_supply_get_property.part.0+0x23/0x160 >>> power_supply_get_property.part.0+0x23/0x160 >>> dell_wmi_ddv_battery_translate+0x68/0x1d0 [dell_wmi_ddv] >>> ? lock_acquire+0xd9/0x2c0 >>> dell_wmi_ddv_get_property+0x25/0x240 [dell_wmi_ddv] >>> power_supply_get_property.part.0+0x87/0x160 >>> power_supply_format_property+0xc4/0x3d0 >>> add_prop_uevent+0x26/0x90 >>> power_supply_uevent+0xb9/0xf0 >>> >>> This usually works fine, because read-locking can be done multiple times >>> but if someone tries to write-lock between the 2 read-lock calls then >>> the second read-lock will block on the write-lock and the write-lock will >>> be blocked on the first read-lock leading to a deadlock. >>> >>> The serial is part of the main psy device, not of an extension. Directly >>> call psy->desc->get_property() in dell_wmi_ddv_battery_translate() to fix >>> the double-lock issue. >>> >>> Note this also influences eppid_show() which is called directly rather >>> then through power_supply_get_property(). This is ok since the ACPI >>> battery is fully ready to be used when the battery hook's add_battery >>> callback is called. >> Thank you very much for finding this issue, but i think that simply calling battery->desc->get_property() >> is not the right solution for this: >> >> 1. We should still call psy_desc_has_property() to determine if the power supply actually support >> POWER_SUPPLY_PROP_SERIAL_NUMBER. > Although it is currently not enforced in power_supply_core.c it seems > reasonable to assume that any powersupply must have a get_property > callback in their desc (the core also unconditionally calls this). > > And most (all?) psy drivers I've seen have a default which returns -EINVAL > in their get_property() implementation which works just as well as > calling has_prop ... > > My bigger worry is the lack of the: > >> if (atomic_read(&psy->use_cnt) <= 0) { >> if (!psy->initialized) >> return -EAGAIN; >> return -ENODEV; >> } > Check TBH. > >> 2. At least another power supply extension user (the uniwill-laptop driver currently being under review) >> suffers from a similar problem, so a more generic solution is needed. >> >> Maybe we could introduce a new function for reading power supply properties that ignores any >> power supply extensions? This way future extension could use this function too. >> >> I envision something like this: >> >> int power_supply_get_property_direct(struct power_supply *psy, >> enum power_supply_property psp, >> union power_supply_propval *val) >> { >> if (atomic_read(&psy->use_cnt) <= 0) { >> if (!psy->initialized) >> return -EAGAIN; >> return -ENODEV; >> } >> >> if (psy_desc_has_property(psy->desc, psp)) >> return psy->desc->get_property(psy, psp, val); >> else if (power_supply_battery_info_has_prop(psy->battery_info, psp)) >> return power_supply_battery_info_get_prop(psy->battery_info, psp, val); >> else >> return -EINVAL; >> } >> EXPORT_SYMBOL_GPL(power_supply_get_property_direct); >> >> It basically is power_supply_get_property() without the extension logic. > While working on this fix I was thinking that something like this would be useful, > so +1 for this. > > Maybe first do a prep patch where the extension handling in > power_supply_get_property() is moved last, then power_supply_get_property() > can just wrap this new helprr and on -EINVAL check the extensions. > > Actually if you move the extensions check to last then the whole doublelock > issue goes away because the serial-number will be found before checking > extensions. > > Or if you want to keep checking the extensions first change > the current power_supply_get_property() into a new > __power_supply_get_property() with a "bool check_extensions" > argument and make power_supply_get_property() wrap it pasing true > for check_extensions. Or some such, whatever you do try to avoid code > duplication but you already know this ... >> I can also write some >> documentation on how to implement power supply extensions in general. > That would also be good to have. > > Regards, > > Hans Alright, i will send the necessary patches soon. Thanks, Armin Wolf >>> Fixes: 058de163a376 ("platform/x86: dell-ddv: Implement the battery matching algorithm") >>> Signed-off-by: Hans de Goede <hansg@kernel.org> >>> --- >>> drivers/platform/x86/dell/dell-wmi-ddv.c | 8 +++++--- >>> 1 file changed, 5 insertions(+), 3 deletions(-) >>> >>> diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c >>> index 67f3d7158403..95cc3139f271 100644 >>> --- a/drivers/platform/x86/dell/dell-wmi-ddv.c >>> +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c >>> @@ -689,9 +689,11 @@ static int dell_wmi_ddv_battery_translate(struct dell_wmi_ddv_data *data, >>> dev_dbg(&data->wdev->dev, "Translation cache miss\n"); >>> - /* Perform a translation between a ACPI battery and a battery index */ >>> - >>> - ret = power_supply_get_property(battery, POWER_SUPPLY_PROP_SERIAL_NUMBER, &val); >>> + /* >>> + * Perform a translation between a ACPI battery and a battery index. Directly call >>> + * desc->get_property() to avoid locking battery->extensions_sem a second time. >>> + */ >>> + ret = battery->desc->get_property(battery, POWER_SUPPLY_PROP_SERIAL_NUMBER, &val); >>> if (ret < 0) >>> return ret; >>> > ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] platform/x86: dell-ddv: Fix taking the psy->extensions_sem lock twice 2025-06-22 22:08 ` Armin Wolf @ 2025-06-23 22:35 ` Sebastian Reichel 0 siblings, 0 replies; 5+ messages in thread From: Sebastian Reichel @ 2025-06-23 22:35 UTC (permalink / raw) To: Armin Wolf Cc: Hans de Goede, Ilpo Järvinen, Andy Shevchenko, platform-driver-x86, Linux PM, Thomas Weißschuh [-- Attachment #1: Type: text/plain, Size: 6279 bytes --] Hi, On Mon, Jun 23, 2025 at 12:08:04AM +0200, Armin Wolf wrote: > Am 22.06.25 um 22:59 schrieb Hans de Goede: > > > + Cc sre, whom I should have Cc-ed from the beginning. > > > > Hi Armin, > > > > On 22-Jun-25 8:41 PM, Armin Wolf wrote: > > > Am 20.06.25 um 19:58 schrieb Hans de Goede: > > > > > > > dell_wmi_ddv_get_property() gets called with psy->extensions_sem > > > > read-locked, it calls dell_wmi_ddv_battery_translate() which calls > > > > power_supply_get_property() on the same psy which again read-locks > > > > psy->extensions_sem. > > > > > > > > Lockdep rightfully complains about this: > > > > > > > > ============================================ > > > > WARNING: possible recursive locking detected > > > > ... > > > > kworker/16:3/1230 is trying to acquire lock: > > > > ffff8c3143417658 (&psy->extensions_sem){++++}-{4:4}, > > > > at: power_supply_get_property.part.0+0x23/0x160 > > > > but task is already holding lock: > > > > ffff8c3143417658 (&psy->extensions_sem){++++}-{4:4}, > > > > at: power_supply_get_property.part.0+0x23/0x160 > > > > ... > > > > Possible unsafe locking scenario: > > > > > > > > CPU0 > > > > ---- > > > > lock(&psy->extensions_sem); > > > > lock(&psy->extensions_sem); > > > > > > > > *** DEADLOCK *** > > > > ... > > > > Call Trace: > > > > <TASK> > > > > ... > > > > down_read+0x3e/0x180 > > > > ? power_supply_get_property.part.0+0x23/0x160 > > > > power_supply_get_property.part.0+0x23/0x160 > > > > dell_wmi_ddv_battery_translate+0x68/0x1d0 [dell_wmi_ddv] > > > > ? lock_acquire+0xd9/0x2c0 > > > > dell_wmi_ddv_get_property+0x25/0x240 [dell_wmi_ddv] > > > > power_supply_get_property.part.0+0x87/0x160 > > > > power_supply_format_property+0xc4/0x3d0 > > > > add_prop_uevent+0x26/0x90 > > > > power_supply_uevent+0xb9/0xf0 > > > > > > > > This usually works fine, because read-locking can be done multiple times > > > > but if someone tries to write-lock between the 2 read-lock calls then > > > > the second read-lock will block on the write-lock and the write-lock will > > > > be blocked on the first read-lock leading to a deadlock. > > > > > > > > The serial is part of the main psy device, not of an extension. Directly > > > > call psy->desc->get_property() in dell_wmi_ddv_battery_translate() to fix > > > > the double-lock issue. > > > > > > > > Note this also influences eppid_show() which is called directly rather > > > > then through power_supply_get_property(). This is ok since the ACPI > > > > battery is fully ready to be used when the battery hook's add_battery > > > > callback is called. > > > Thank you very much for finding this issue, but i think that simply calling battery->desc->get_property() > > > is not the right solution for this: > > > > > > 1. We should still call psy_desc_has_property() to determine if the power supply actually support > > > POWER_SUPPLY_PROP_SERIAL_NUMBER. > > Although it is currently not enforced in power_supply_core.c it seems > > reasonable to assume that any powersupply must have a get_property > > callback in their desc (the core also unconditionally calls this). > > > > And most (all?) psy drivers I've seen have a default which returns -EINVAL > > in their get_property() implementation which works just as well as > > calling has_prop ... > > > > My bigger worry is the lack of the: > > > > > if (atomic_read(&psy->use_cnt) <= 0) { > > > if (!psy->initialized) > > > return -EAGAIN; > > > return -ENODEV; > > > } > > Check TBH. > > > > > 2. At least another power supply extension user (the uniwill-laptop driver currently being under review) > > > suffers from a similar problem, so a more generic solution is needed. > > > > > > Maybe we could introduce a new function for reading power supply properties that ignores any > > > power supply extensions? This way future extension could use this function too. > > > > > > I envision something like this: > > > int power_supply_get_property_direct(struct power_supply *psy, > > > enum power_supply_property psp, > > > union power_supply_propval *val) > > > { > > > if (atomic_read(&psy->use_cnt) <= 0) { > > > if (!psy->initialized) > > > return -EAGAIN; > > > return -ENODEV; > > > } > > > > > > if (psy_desc_has_property(psy->desc, psp)) > > > return psy->desc->get_property(psy, psp, val); > > > else if (power_supply_battery_info_has_prop(psy->battery_info, psp)) > > > return power_supply_battery_info_get_prop(psy->battery_info, psp, val); > > > else > > > return -EINVAL; > > > } > > > EXPORT_SYMBOL_GPL(power_supply_get_property_direct); > > > > > > It basically is power_supply_get_property() without the extension logic. > > While working on this fix I was thinking that something like this would be useful, > > so +1 for this. > > > > Maybe first do a prep patch where the extension handling in > > power_supply_get_property() is moved last, then power_supply_get_property() > > can just wrap this new helprr and on -EINVAL check the extensions. > > > > Actually if you move the extensions check to last then the whole doublelock > > issue goes away because the serial-number will be found before checking > > extensions. > > > > Or if you want to keep checking the extensions first change > > the current power_supply_get_property() into a new > > __power_supply_get_property() with a "bool check_extensions" > > argument and make power_supply_get_property() wrap it pasing true > > for check_extensions. Or some such, whatever you do try to avoid code > > duplication but you already know this ... > > > I can also write some > > > documentation on how to implement power supply extensions in general. > > That would also be good to have. > > > > Regards, > > > > Hans > > Alright, i will send the necessary patches soon. Sounds good to me. Please also Cc Thomas Weißschuh, who implemented all the extension code :) Greetings, -- Sebastian [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-06-23 22:36 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-06-20 17:58 [PATCH] platform/x86: dell-ddv: Fix taking the psy->extensions_sem lock twice Hans de Goede 2025-06-22 18:41 ` Armin Wolf 2025-06-22 20:59 ` Hans de Goede 2025-06-22 22:08 ` Armin Wolf 2025-06-23 22:35 ` Sebastian Reichel
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox