The URB complete handler may be called by usb_unlink_urb directly,
so deadlock will be triggered in __usbhid_submit_report since
usbhid->lock is to be acquired in ctrl/out URB complete handler
but it is hold before calling usb_unlink_urb.

This patch avoids the deadlock by releasing the lock before
calling usb_unlink_urb.

CC: <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
 drivers/hid/usbhid/hid-core.c |   16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index aa1c503..b5d07da 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -543,11 +543,13 @@ static void __usbhid_submit_report(struct hid_device 
*hid, struct hid_report *re
                         * the queue is known to run
                         * but an earlier request may be stuck
                         * we may need to time out
-                        * no race because this is called under
-                        * spinlock
+                        * release spinlock to avoid deadlock.
                         */
-                       if (time_after(jiffies, usbhid->last_out + HZ * 5))
+                       if (time_after(jiffies, usbhid->last_out + HZ * 5)) {
+                               spin_unlock(&usbhid->lock);
                                usb_unlink_urb(usbhid->urbout);
+                               spin_lock(&usbhid->lock);
+                       }
                }
                return;
        }
@@ -591,11 +593,13 @@ static void __usbhid_submit_report(struct hid_device 
*hid, struct hid_report *re
                 * the queue is known to run
                 * but an earlier request may be stuck
                 * we may need to time out
-                * no race because this is called under
-                * spinlock
+                * release spinlock to avoid deadlock.
                 */
-               if (time_after(jiffies, usbhid->last_ctrl + HZ * 5))
+               if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) {
+                       spin_unlock(&usbhid->lock);
                        usb_unlink_urb(usbhid->urbctrl);
+                       spin_lock(&usbhid->lock);
+               }
        }
 }
 
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to