Re: [PATCH] HID: i2c-hid: goodix: Fix a lockdep splat

From: Doug Anderson
Date: Fri Jan 28 2022 - 17:48:52 EST


Hi,

On Fri, Jan 28, 2022 at 9:48 AM Daniel Thompson
<daniel.thompson@xxxxxxxxxx> wrote:
>
> I'm was on the receiving end of a lockdep splat from this driver and after
> scratching my head I couldn't be entirely sure it was a false positive
> given we would also have to think about whether the regulator locking is
> safe (since the notifier is called whilst holding regulator locks which
> are also needed for regulator_is_enabled() ).
>
> Regardless of whether it is a real bug or not, the mutex isn't needed.
> We can use reference counting tricks instead to avoid races with the
> notifier calls.
>
> The observed splat follows:
>
> ------------------------------------------------------
> kworker/u16:3/127 is trying to acquire lock:
> ffff00008021fb20 (&ihid_goodix->regulator_mutex){+.+.}-{4:4}, at: ihid_goodix_vdd_notify+0x30/0x94
>
> but task is already holding lock:
> ffff0000835c60c0 (&(&rdev->notifier)->rwsem){++++}-{4:4}, at: blocking_notifier_call_chain+0x30/0x70
>
> which lock already depends on the new lock.
>
>
> the existing dependency chain (in reverse order) is:
>
> -> #1 (&(&rdev->notifier)->rwsem){++++}-{4:4}:
> down_write+0x68/0x8c
> blocking_notifier_chain_register+0x54/0x70
> regulator_register_notifier+0x1c/0x24
> devm_regulator_register_notifier+0x58/0x98
> i2c_hid_of_goodix_probe+0xdc/0x158
> i2c_device_probe+0x25d/0x270
> really_probe+0x174/0x2cc
> __driver_probe_device+0xc0/0xd8
> driver_probe_device+0x50/0xe4
> __device_attach_driver+0xa8/0xc0
> bus_for_each_drv+0x9c/0xc0
> __device_attach_async_helper+0x6c/0xbc
> async_run_entry_fn+0x38/0x100
> process_one_work+0x294/0x438
> worker_thread+0x180/0x258
> kthread+0x120/0x130
> ret_from_fork+0x10/0x20
>
> -> #0 (&ihid_goodix->regulator_mutex){+.+.}-{4:4}:
> __lock_acquire+0xd24/0xfe8
> lock_acquire+0x288/0x2f4
> __mutex_lock+0xa0/0x338
> mutex_lock_nested+0x3c/0x5c
> ihid_goodix_vdd_notify+0x30/0x94
> notifier_call_chain+0x6c/0x8c
> blocking_notifier_call_chain+0x48/0x70
> _notifier_call_chain.isra.0+0x18/0x20
> _regulator_enable+0xc0/0x178
> regulator_enable+0x40/0x7c
> goodix_i2c_hid_power_up+0x18/0x20
> i2c_hid_core_power_up.isra.0+0x1c/0x2c
> i2c_hid_core_probe+0xd8/0x3d4
> i2c_hid_of_goodix_probe+0x14c/0x158
> i2c_device_probe+0x25c/0x270
> really_probe+0x174/0x2cc
> __driver_probe_device+0xc0/0xd8
> driver_probe_device+0x50/0xe4
> __device_attach_driver+0xa8/0xc0
> bus_for_each_drv+0x9c/0xc0
> __device_attach_async_helper+0x6c/0xbc
> async_run_entry_fn+0x38/0x100
> process_one_work+0x294/0x438
> worker_thread+0x180/0x258
> kthread+0x120/0x130
> ret_from_fork+0x10/0x20
>
> other info that might help us debug this:
>
> Possible unsafe locking scenario:
>
> CPU0 CPU1
> ---- ----
> lock(&(&rdev->notifier)->rwsem);
> lock(&ihid_goodix->regulator_mutex);
> lock(&(&rdev->notifier)->rwsem);
> lock(&ihid_goodix->regulator_mutex);
>
> *** DEADLOCK ***
>
> Signed-off-by: Daniel Thompson <daniel.thompson@xxxxxxxxxx>
> ---
> drivers/hid/i2c-hid/i2c-hid-of-goodix.c | 28 +++++++++++--------------
> 1 file changed, 12 insertions(+), 16 deletions(-)

Yes, this seems like a reasonable solution, thanks! Probably want:

Fixes: 18eeef46d359 ("HID: i2c-hid: goodix: Tie the reset line to true
state of the regulator")

Reviewed-by: Douglas Anderson <dianders@xxxxxxxxxxxx>