Skip to content

Commit 98e0121

Browse files
Tetsuo Handadtor
authored andcommitted
Input: iforce - wake up after clearing IFORCE_XMIT_RUNNING flag
syzbot is reporting hung task at __input_unregister_device() [1], for iforce_close() waiting at wait_event_interruptible() with dev->mutex held is blocking input_disconnect_device() from __input_unregister_device(). It seems that the cause is simply that commit c2b27ef ("Input: iforce - wait for command completion when closing the device") forgot to call wake_up() after clear_bit(). Fix this problem by introducing a helper that calls clear_bit() followed by wake_up_all(). Reported-by: syzbot <syzbot+deb6abc36aad4008f407@syzkaller.appspotmail.com> Fixes: c2b27ef ("Input: iforce - wait for command completion when closing the device") Tested-by: syzbot <syzbot+deb6abc36aad4008f407@syzkaller.appspotmail.com> Suggested-by: Fabio M. De Francesco <fmdefrancesco@gmail.com> Co-developed-by: Hillf Danton <hdanton@sina.com> Signed-off-by: Hillf Danton <hdanton@sina.com> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Link: https://lore.kernel.org/r/887021c3-4f13-40ce-c8b9-aa6e09faa3a7@I-love.SAKURA.ne.jp Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
1 parent 80b9ebd commit 98e0121

File tree

3 files changed

+13
-7
lines changed

3 files changed

+13
-7
lines changed

drivers/input/joystick/iforce/iforce-serio.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ static void iforce_serio_xmit(struct iforce *iforce)
3939

4040
again:
4141
if (iforce->xmit.head == iforce->xmit.tail) {
42-
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
42+
iforce_clear_xmit_and_wake(iforce);
4343
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
4444
return;
4545
}
@@ -64,7 +64,7 @@ static void iforce_serio_xmit(struct iforce *iforce)
6464
if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
6565
goto again;
6666

67-
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
67+
iforce_clear_xmit_and_wake(iforce);
6868

6969
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
7070
}
@@ -169,7 +169,7 @@ static irqreturn_t iforce_serio_irq(struct serio *serio,
169169
iforce_serio->cmd_response_len = iforce_serio->len;
170170

171171
/* Signal that command is done */
172-
wake_up(&iforce->wait);
172+
wake_up_all(&iforce->wait);
173173
} else if (likely(iforce->type)) {
174174
iforce_process_packet(iforce, iforce_serio->id,
175175
iforce_serio->data_in,

drivers/input/joystick/iforce/iforce-usb.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ static void __iforce_usb_xmit(struct iforce *iforce)
3030
spin_lock_irqsave(&iforce->xmit_lock, flags);
3131

3232
if (iforce->xmit.head == iforce->xmit.tail) {
33-
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
33+
iforce_clear_xmit_and_wake(iforce);
3434
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
3535
return;
3636
}
@@ -58,9 +58,9 @@ static void __iforce_usb_xmit(struct iforce *iforce)
5858
XMIT_INC(iforce->xmit.tail, n);
5959

6060
if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) {
61-
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
6261
dev_warn(&iforce_usb->intf->dev,
6362
"usb_submit_urb failed %d\n", n);
63+
iforce_clear_xmit_and_wake(iforce);
6464
}
6565

6666
/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
@@ -175,15 +175,15 @@ static void iforce_usb_out(struct urb *urb)
175175
struct iforce *iforce = &iforce_usb->iforce;
176176

177177
if (urb->status) {
178-
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
179178
dev_dbg(&iforce_usb->intf->dev, "urb->status %d, exiting\n",
180179
urb->status);
180+
iforce_clear_xmit_and_wake(iforce);
181181
return;
182182
}
183183

184184
__iforce_usb_xmit(iforce);
185185

186-
wake_up(&iforce->wait);
186+
wake_up_all(&iforce->wait);
187187
}
188188

189189
static int iforce_usb_probe(struct usb_interface *intf,

drivers/input/joystick/iforce/iforce.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ static inline int iforce_get_id_packet(struct iforce *iforce, u8 id,
119119
response_data, response_len);
120120
}
121121

122+
static inline void iforce_clear_xmit_and_wake(struct iforce *iforce)
123+
{
124+
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
125+
wake_up_all(&iforce->wait);
126+
}
127+
122128
/* Public functions */
123129
/* iforce-main.c */
124130
int iforce_init_device(struct device *parent, u16 bustype,

0 commit comments

Comments
 (0)