Skip to contentSkip to conversation

platform/x86: thinkpad_acpi: Use input_device_enabled()

PATCH In review Dmitry Torokhov 4 participants 9 messages Aug 5 – Sep 30

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 platform/x86: thinkpad_acpi: Use input_device_enabled()

From: Andrzej Pietrasiewicz <[email protected]>

Use the new helper. Inspecting input device's 'users' member needs to be done under device's mutex, so add appropriate invocations.

---

Not sure how this got stuck in my patch queue but it is still valid...

 drivers/platform/x86/lenovo/thinkpad_acpi.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/platform/x86/lenovo/thinkpad_acpi.c +3 -1
index 445e1403308e..f8e116e8a65d 100644
@@ -2547,9 +2547,10 @@ static void hotkey_poll_setup(const bool may_warn)
 
 	lockdep_assert_held(&hotkey_mutex);
 
+	mutex_lock(&tpacpi_inputdev->mutex);
 	if (hotkey_poll_freq > 0 &&
 	    (poll_driver_mask ||
-	     (poll_user_mask && tpacpi_inputdev->users > 0))) {
+	     (poll_user_mask && input_device_enabled(tpacpi_inputdev)))) {
 		if (!tpacpi_hotkey_task) {
 			tpacpi_hotkey_task = kthread_run(hotkey_kthread,
 					NULL, TPACPI_NVRAM_KTHREAD_NAME);
@@ -2566,6 +2567,7 @@ static void hotkey_poll_setup(const bool may_warn)
 				  poll_user_mask, poll_driver_mask);
 		}
 	}
+	mutex_unlock(&tpacpi_inputdev->mutex);
 }
 
 static void hotkey_poll_setup_safe(const bool may_warn)
Signature · 5 lines
2.55.0.571.g244d577d93-goog


-- 
Dmitry
maintainer Reviewed-by on v1 1/1
#1 lore raw
Quoted 36 lines · Dmitry Torokhov

From: Andrzej Pietrasiewicz <[email protected]>

Use the new helper. Inspecting input device's 'users' member needs to be done under device's mutex, so add appropriate invocations.

---

Not sure how this got stuck in my patch queue but it is still valid...

 drivers/platform/x86/lenovo/thinkpad_acpi.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/platform/x86/lenovo/thinkpad_acpi.c +2 -1
index 445e1403308e..f8e116e8a65d 100644
@@ -2547,9 +2547,10 @@ static void hotkey_poll_setup(const bool 
 may_warn)
 
 	lockdep_assert_held(&hotkey_mutex);
 
+	mutex_lock(&tpacpi_inputdev->mutex);
 	if (hotkey_poll_freq > 0 &&
 	    (poll_driver_mask ||
-	     (poll_user_mask && tpacpi_inputdev->users > 0))) {
+	     (poll_user_mask && input_device_enabled(tpacpi_inputdev)))) {
 		if (!tpacpi_hotkey_task) {
 			tpacpi_hotkey_task = kthread_run(hotkey_kthread,
drivers/platform/x86/lenovo/thinkpad_acpi.c +0 -0
 					NULL, TPACPI_NVRAM_KTHREAD_NAME);

drivers/platform/x86/lenovo/thinkpad_acpi.c static void hotkey_poll_setup(const bool may_warn) · line 2573

Quoted 7 lines
drivers/platform/x86/lenovo/thinkpad_acpi.c +1 -0
@@ -2566,6 +2567,7 @@ static void hotkey_poll_setup(const bool may_warn)
 				  poll_user_mask, poll_driver_mask);
 		}
 	}
+	mutex_unlock(&tpacpi_inputdev->mutex);
 }
 
 static void hotkey_poll_setup_safe(const bool may_warn)

Looks good to me.

Only note is that can you use guard(mutex)(&tpacpi_inputdev->mutex) instead of the lock/unlock? I think that's preferred these days.

#2 lore raw

Hi Mark,

Quoted 44 lines · Mark Pearson
Quoted 41 lines · Dmitry Torokhov

From: Andrzej Pietrasiewicz <[email protected]>

Use the new helper. Inspecting input device's 'users' member needs to be done under device's mutex, so add appropriate invocations.

---

Not sure how this got stuck in my patch queue but it is still valid...

 drivers/platform/x86/lenovo/thinkpad_acpi.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/platform/x86/lenovo/thinkpad_acpi.c +2 -1
index 445e1403308e..f8e116e8a65d 100644
@@ -2547,9 +2547,10 @@ static void hotkey_poll_setup(const bool 
 may_warn)
 
 	lockdep_assert_held(&hotkey_mutex);
 
+	mutex_lock(&tpacpi_inputdev->mutex);
 	if (hotkey_poll_freq > 0 &&
 	    (poll_driver_mask ||
-	     (poll_user_mask && tpacpi_inputdev->users > 0))) {
+	     (poll_user_mask && input_device_enabled(tpacpi_inputdev)))) {
 		if (!tpacpi_hotkey_task) {
 			tpacpi_hotkey_task = kthread_run(hotkey_kthread,
drivers/platform/x86/lenovo/thinkpad_acpi.c +1 -0
 					NULL, TPACPI_NVRAM_KTHREAD_NAME);
@@ -2566,6 +2567,7 @@ static void hotkey_poll_setup(const bool may_warn)
 				  poll_user_mask, poll_driver_mask);
 		}
 	}
+	mutex_unlock(&tpacpi_inputdev->mutex);
 }
 
Quoted 6 lines

drivers/platform/x86/lenovo/thinkpad_acpi.c static void hotkey_poll_setup(const bool may_warn) · line 2573

Quoted 2 lines
drivers/platform/x86/lenovo/thinkpad_acpi.c +0 -0
 static void hotkey_poll_setup_safe(const bool may_warn)

Looks good to me.

Only note is that can you use guard(mutex)(&tpacpi_inputdev->mutex) instead of the lock/unlock? I think that's preferred these days.

If that is desired the whole driver needs converting. I can do it in a separate patch(es) if you want.

Quoted 2 lines

Thanks.

Signature · 1 line
Dmitry
maintainer
#3 lore raw
Quoted 52 lines · Dmitry Torokhov

Hi Mark,

Quoted 49 lines · Mark Pearson
Quoted 36 lines · Dmitry Torokhov

From: Andrzej Pietrasiewicz <[email protected]>

Use the new helper. Inspecting input device's 'users' member needs to be done under device's mutex, so add appropriate invocations.

---

Not sure how this got stuck in my patch queue but it is still valid...

 drivers/platform/x86/lenovo/thinkpad_acpi.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/platform/x86/lenovo/thinkpad_acpi.c +2 -1
index 445e1403308e..f8e116e8a65d 100644
@@ -2547,9 +2547,10 @@ static void hotkey_poll_setup(const bool 
 may_warn)
 
 	lockdep_assert_held(&hotkey_mutex);
 
+	mutex_lock(&tpacpi_inputdev->mutex);
 	if (hotkey_poll_freq > 0 &&
 	    (poll_driver_mask ||
-	     (poll_user_mask && tpacpi_inputdev->users > 0))) {
+	     (poll_user_mask && input_device_enabled(tpacpi_inputdev)))) {
 		if (!tpacpi_hotkey_task) {
 			tpacpi_hotkey_task = kthread_run(hotkey_kthread,
drivers/platform/x86/lenovo/thinkpad_acpi.c +0 -0
 					NULL, TPACPI_NVRAM_KTHREAD_NAME);

drivers/platform/x86/lenovo/thinkpad_acpi.c static void hotkey_poll_setup(const bool may_warn) · line 2573

Quoted 7 lines
drivers/platform/x86/lenovo/thinkpad_acpi.c +1 -0
@@ -2566,6 +2567,7 @@ static void hotkey_poll_setup(const bool may_warn)
 				  poll_user_mask, poll_driver_mask);
 		}
 	}
+	mutex_unlock(&tpacpi_inputdev->mutex);
 }
 
 static void hotkey_poll_setup_safe(const bool may_warn)

Looks good to me.

Quoted 5 lines
Quoted 1 line

Only note is that can you use guard(mutex)(&tpacpi_inputdev->mutex) instead of the lock/unlock? I think that's preferred these days.

If that is desired the whole driver needs converting. I can do it in a separate patch(es) if you want.

Ah - good point. Not worth it for this IMO, unless the more experienced maintainers have a strong opinion :)

Mark

#4 lore raw
Quoted 55 lines · Mark Pearson
Quoted 52 lines · Dmitry Torokhov

Hi Mark,

Quoted 49 lines · Mark Pearson
Quoted 36 lines · Dmitry Torokhov

From: Andrzej Pietrasiewicz <[email protected]>

Use the new helper. Inspecting input device's 'users' member needs to be done under device's mutex, so add appropriate invocations.

---

Not sure how this got stuck in my patch queue but it is still valid...

 drivers/platform/x86/lenovo/thinkpad_acpi.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/platform/x86/lenovo/thinkpad_acpi.c +2 -1
index 445e1403308e..f8e116e8a65d 100644
@@ -2547,9 +2547,10 @@ static void hotkey_poll_setup(const bool 
 may_warn)
 
 	lockdep_assert_held(&hotkey_mutex);
 
+	mutex_lock(&tpacpi_inputdev->mutex);
 	if (hotkey_poll_freq > 0 &&
 	    (poll_driver_mask ||
-	     (poll_user_mask && tpacpi_inputdev->users > 0))) {
+	     (poll_user_mask && input_device_enabled(tpacpi_inputdev)))) {
 		if (!tpacpi_hotkey_task) {
 			tpacpi_hotkey_task = kthread_run(hotkey_kthread,
drivers/platform/x86/lenovo/thinkpad_acpi.c +0 -0
 					NULL, TPACPI_NVRAM_KTHREAD_NAME);

drivers/platform/x86/lenovo/thinkpad_acpi.c static void hotkey_poll_setup(const bool may_warn) · line 2573

Quoted 7 lines
drivers/platform/x86/lenovo/thinkpad_acpi.c +1 -0
@@ -2566,6 +2567,7 @@ static void hotkey_poll_setup(const bool may_warn)
 				  poll_user_mask, poll_driver_mask);
 		}
 	}
+	mutex_unlock(&tpacpi_inputdev->mutex);
 }
 
 static void hotkey_poll_setup_safe(const bool may_warn)

Looks good to me.

Quoted 6 lines
Quoted 5 lines
Quoted 1 line

Only note is that can you use guard(mutex)(&tpacpi_inputdev->mutex) instead of the lock/unlock? I think that's preferred these days.

If that is desired the whole driver needs converting. I can do it in a separate patch(es) if you want.

Ah - good point. Not worth it for this IMO, unless the more experienced maintainers have a strong opinion :)

Well, I went and did it anyways in case you want to apply it.

Thanks.

Signature · 1 line
Dmitry
maintainer
#5 lore raw
In reply to Dmitry Torokhov
Quoted 2 lines · Dmitry Torokhov

Use the new helper. Inspecting input device's 'users' member needs to be done under device's mutex, so add appropriate invocations.

Thank you for your contribution, it has been applied to my local review-ilpo-next branch. Note it will show up in the public platform-drivers-x86/review-ilpo-next branch only once I've pushed my local branch there, which might take a while.

FYI [if applicable to your patch], as per Linus' policy change, also fixes are mostly routed through for-next unless the fix is for a commit introduced in the most recent cycle or is clearly a regression fix.

The list of commits applied:
[1/1] platform/x86: thinkpad_acpi: Use input_device_enabled()

      commit: be0048786d53375fa4eace15cfdf65593956a1a2

--
i.

#6 lore raw
Quoted 2 lines · Ilpo Järvinen

[1/1] platform/x86: thinkpad_acpi: Use input_device_enabled()

      commit: be0048786d53375fa4eace15cfdf65593956a1a2

This hangs on module load for me. hotkey_inputdev_open() gets called from input_open_device() with dev->mutex already held, so the new lock in hotkey_poll_setup() deadlocks:

  INFO: task insmod:28182 is blocked on a mutex likely owned by task insmod:28182.
   hotkey_poll_setup+0x50/0x140 [thinkpad_acpi]
   hotkey_inputdev_open+0x36/0x50 [thinkpad_acpi]
   input_open_device+0x9d/0x130
   kbd_connect+0x8f/0xb0

I guess hotkey_inputdev_close() has the same issue. This was next-20260929's thinkpad_acpi.c built against 7.1.11.

#7 lore raw
Quoted 8 lines · Ali Ahmet Memiş
Quoted 2 lines · Ilpo Järvinen

[1/1] platform/x86: thinkpad_acpi: Use input_device_enabled()

      commit: be0048786d53375fa4eace15cfdf65593956a1a2

This hangs on module load for me. hotkey_inputdev_open() gets called from input_open_device() with dev->mutex already held, so the new lock in hotkey_poll_setup() deadlocks:

Quoted 8 lines
  INFO: task insmod:28182 is blocked on a mutex likely owned by task insmod:28182.
   hotkey_poll_setup+0x50/0x140 [thinkpad_acpi]
   hotkey_inputdev_open+0x36/0x50 [thinkpad_acpi]
   input_open_device+0x9d/0x130
   kbd_connect+0x8f/0xb0

I guess hotkey_inputdev_close() has the same issue. This was next-20260929's thinkpad_acpi.c built against 7.1.11.

Hmm, indeed. I wonder if below will fox this for you.

Signature · 32 lines
Dmitry

platform/x86: thinkpad_acpi: fix deadlock in hotkey input open/close

Commit d6479c25ecef ("platform/x86: thinkpad_acpi: Use
input_device_enabled()") changed hotkey_poll_setup() to acquire
tpacpi_inputdev->mutex and call input_device_enabled(tpacpi_inputdev).

However, the input core already holds dev->mutex when invoking a
device's open() and close() callbacks. Because hotkey_inputdev_open()
and hotkey_inputdev_close() call into hotkey_poll_setup(), attempting to
acquire tpacpi_inputdev->mutex again results in an immediate
self-deadlock.

Additionally, locking tpacpi_inputdev->mutex inside hotkey_poll_setup()
while holding hotkey_mutex introduces an ABBA lock ordering inversion
with hotkey_inputdev_open() and hotkey_inputdev_close(), which acquire
hotkey_mutex while holding tpacpi_inputdev->mutex. Finally,
input_inhibit_device() calls dev->close() before setting dev->inhibited,
so input_device_enabled() still returns true inside
hotkey_inputdev_close().

Track whether the input device is active in a driver-local boolean
protected by hotkey_mutex instead of locking tpacpi_inputdev->mutex and
querying input_device_enabled().

Fixes: d6479c25ecef ("platform/x86: thinkpad_acpi: Use input_device_enabled()")
Assisted-by: LLM
Signed-off-by: Dmitry Torokhov <[email protected]>
---
 drivers/platform/x86/lenovo/thinkpad_acpi.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)
drivers/platform/x86/lenovo/thinkpad_acpi.c +11 -5
index 1225b01ed14d..40e9763a12f8 100644
@@ -1887,6 +1887,7 @@ static u32 hotkey_reserved_mask;	/* events better left disabled */
 static u32 hotkey_driver_mask;		/* events needed by the driver */
 static u32 hotkey_user_mask;		/* events visible to userspace */
 static u32 hotkey_acpi_mask;		/* events enabled in firmware */
+static bool hotkey_input_enabled;
 
 static bool tpacpi_driver_event(const unsigned int hkey_event);
 static void hotkey_poll_setup(const bool may_warn);
@@ -2544,10 +2545,8 @@ static void hotkey_poll_setup(const bool may_warn)
 
 	lockdep_assert_held(&hotkey_mutex);
 
-	guard(mutex)(&tpacpi_inputdev->mutex);
 	if (hotkey_poll_freq > 0 &&
-	    (poll_driver_mask ||
-	     (poll_user_mask && input_device_enabled(tpacpi_inputdev)))) {
+	    (poll_driver_mask || (poll_user_mask && hotkey_input_enabled))) {
 		if (!tpacpi_hotkey_task) {
 			tpacpi_hotkey_task = kthread_run(hotkey_kthread,
 					NULL, TPACPI_NVRAM_KTHREAD_NAME);
@@ -2602,7 +2601,10 @@ static int hotkey_inputdev_open(struct input_dev *dev)
 	switch (tpacpi_lifecycle) {
 	case TPACPI_LIFE_INIT:
 	case TPACPI_LIFE_RUNNING:
-		hotkey_poll_setup_safe(false);
+		scoped_guard(mutex, &hotkey_mutex) {
+			hotkey_input_enabled = true;
+			hotkey_poll_setup(false);
+		}
 		return 0;
 	case TPACPI_LIFE_EXITING:
 		return -EBUSY;
@@ -2615,10 +2617,14 @@ static int hotkey_inputdev_open(struct input_dev *dev)
 
 static void hotkey_inputdev_close(struct input_dev *dev)
 {
+	guard(mutex)(&hotkey_mutex);
+
+	hotkey_input_enabled = false;
+
 	/* disable hotkey polling when possible */
 	if (tpacpi_lifecycle != TPACPI_LIFE_EXITING &&
 	    !(hotkey_source_mask & hotkey_driver_mask))
-		hotkey_poll_setup_safe(false);
+		hotkey_poll_setup(false);
 }
 
 /* sysfs hotkey enable ------------------------------------------------- */
Signature · 1 line
2.56.0.rc1.315.gc6ed9934b7-goog
#8 lore raw
Quoted 1 line · Dmitry Torokhov

Hmm, indeed. I wonder if below will fox this for you.

Yes, it loads fine now. I also toggled inhibited on the input device with polling enabled, and the nvram thread stops and starts again as expected.