On Tue Sep 1 11:02:22 2026 +0100, Sean Young wrote:
> data->keylock is taken with spin_lock() in ir_mce_kbd_decode(), which
> runs in the raw IR decode kthread with local interrupts enabled, but
> with spin_lock_irqsave() in mce_kbd_rx_timeout(), the rx_timeout timer
> callback, which runs in softirq context.
> 
> If the decode kthread is holding keylock via spin_lock() when a timer
> interrupt fires on the same CPU and the softirq runs
> mce_kbd_rx_timeout(), the softirq spins forever waiting for a lock
> that only the now-preempted kthread can release, while the kthread
> cannot run again until the softirq gives up the CPU. This deadlocks
> the CPU.
> 
> Fixes: 53a62800efb2 ("media: rc: mce_kbd decoder: fix race condition")
> Signed-off-by: Sean Young <[email protected]>
> Cc: [email protected]
> Acked-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Sean Young

 drivers/media/rc/ir-mce_kbd-decoder.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

---

diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c 
b/drivers/media/rc/ir-mce_kbd-decoder.c
index bb2d7c37c263..d1c9263511b0 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -219,6 +219,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct 
ir_raw_event ev)
        struct mce_kbd_dec *data = &dev->raw->mce_kbd;
        u32 scancode;
        unsigned long delay;
+       unsigned long flags;
        struct lirc_scancode lsc = {};
 
        if (!is_timing_event(ev)) {
@@ -319,7 +320,7 @@ again:
                        scancode = data->body & 0xffffff;
                        dev_dbg(&dev->dev, "keyboard data 0x%08x\n",
                                data->body);
-                       spin_lock(&data->keylock);
+                       spin_lock_irqsave(&data->keylock, flags);
                        if (scancode) {
                                delay = usecs_to_jiffies(dev->timeout) +
                                        msecs_to_jiffies(100);
@@ -329,7 +330,7 @@ again:
                        }
                        /* Pass data to keyboard buffer parser */
                        ir_mce_kbd_process_keyboard_data(dev, scancode);
-                       spin_unlock(&data->keylock);
+                       spin_unlock_irqrestore(&data->keylock, flags);
                        lsc.rc_proto = RC_PROTO_MCIR2_KBD;
                        break;
                case MCIR2_MOUSE_NBITS:
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to