X86 platform drivers
 help / color / mirror / Atom feed
From: Hans de Goede <hansg@kernel.org>
To: "Armin Wolf" <W_Armin@gmx.de>,
	"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
	"Andy Shevchenko" <andy@kernel.org>,
	"Sebastian Reichel" <sre@kernel.org>
Cc: platform-driver-x86@vger.kernel.org, Linux PM <linux-pm@vger.kernel.org>
Subject: Re: [PATCH] platform/x86: dell-ddv: Fix taking the psy->extensions_sem lock twice
Date: Sun, 22 Jun 2025 22:59:30 +0200	[thread overview]
Message-ID: <b46dcef3-2893-4b94-81ef-a495e6a0e7ca@kernel.org> (raw)
In-Reply-To: <3bfea893-fd3e-48b6-8a34-9ab36108efe2@gmx.de>

+ 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;
>>   


  reply	other threads:[~2025-06-22 20:59 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2025-06-22 22:08     ` Armin Wolf
2025-06-23 22:35       ` Sebastian Reichel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b46dcef3-2893-4b94-81ef-a495e6a0e7ca@kernel.org \
    --to=hansg@kernel.org \
    --cc=W_Armin@gmx.de \
    --cc=andy@kernel.org \
    --cc=ilpo.jarvinen@linux.intel.com \
    --cc=linux-pm@vger.kernel.org \
    --cc=platform-driver-x86@vger.kernel.org \
    --cc=sre@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox