diff options
author | Oliver Neukum <oliver@neukum.org> | 2012-04-30 03:13:46 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-05-01 13:22:13 -0400 |
commit | 8815bb09af21316aeb5f8948b24ac62181670db2 (patch) | |
tree | a6667e719e124f06257f1b9cb11abe6bce9295b0 /drivers/hid/usbhid | |
parent | 166cb70e97bd83d7ae9bbec6ae59a178fd9bb823 (diff) |
usbhid: prevent deadlock during timeout
On some HCDs usb_unlink_urb() can directly call the
completion handler. That limits the spinlocks that can
be taken in the handler to locks not held while calling
usb_unlink_urb()
To prevent a race with resubmission, this patch exposes
usbcore's infrastructure for blocking submission, uses it
and so drops the lock without causing a race in usbhid.
Signed-off-by: Oliver Neukum <oneukum@suse.de>
Acked-by: Jiri Kosina <jkosina@suse.cz>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hid/usbhid')
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 61 |
1 files changed, 55 insertions, 6 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 5bf91dbad59d..4bbb883a3dd2 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
@@ -399,6 +399,16 @@ static int hid_submit_ctrl(struct hid_device *hid) | |||
399 | * Output interrupt completion handler. | 399 | * Output interrupt completion handler. |
400 | */ | 400 | */ |
401 | 401 | ||
402 | static int irq_out_pump_restart(struct hid_device *hid) | ||
403 | { | ||
404 | struct usbhid_device *usbhid = hid->driver_data; | ||
405 | |||
406 | if (usbhid->outhead != usbhid->outtail) | ||
407 | return hid_submit_out(hid); | ||
408 | else | ||
409 | return -1; | ||
410 | } | ||
411 | |||
402 | static void hid_irq_out(struct urb *urb) | 412 | static void hid_irq_out(struct urb *urb) |
403 | { | 413 | { |
404 | struct hid_device *hid = urb->context; | 414 | struct hid_device *hid = urb->context; |
@@ -428,7 +438,7 @@ static void hid_irq_out(struct urb *urb) | |||
428 | else | 438 | else |
429 | usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); | 439 | usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); |
430 | 440 | ||
431 | if (usbhid->outhead != usbhid->outtail && !hid_submit_out(hid)) { | 441 | if (!irq_out_pump_restart(hid)) { |
432 | /* Successfully submitted next urb in queue */ | 442 | /* Successfully submitted next urb in queue */ |
433 | spin_unlock_irqrestore(&usbhid->lock, flags); | 443 | spin_unlock_irqrestore(&usbhid->lock, flags); |
434 | return; | 444 | return; |
@@ -443,6 +453,15 @@ static void hid_irq_out(struct urb *urb) | |||
443 | /* | 453 | /* |
444 | * Control pipe completion handler. | 454 | * Control pipe completion handler. |
445 | */ | 455 | */ |
456 | static int ctrl_pump_restart(struct hid_device *hid) | ||
457 | { | ||
458 | struct usbhid_device *usbhid = hid->driver_data; | ||
459 | |||
460 | if (usbhid->ctrlhead != usbhid->ctrltail) | ||
461 | return hid_submit_ctrl(hid); | ||
462 | else | ||
463 | return -1; | ||
464 | } | ||
446 | 465 | ||
447 | static void hid_ctrl(struct urb *urb) | 466 | static void hid_ctrl(struct urb *urb) |
448 | { | 467 | { |
@@ -476,7 +495,7 @@ static void hid_ctrl(struct urb *urb) | |||
476 | else | 495 | else |
477 | usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); | 496 | usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); |
478 | 497 | ||
479 | if (usbhid->ctrlhead != usbhid->ctrltail && !hid_submit_ctrl(hid)) { | 498 | if (!ctrl_pump_restart(hid)) { |
480 | /* Successfully submitted next urb in queue */ | 499 | /* Successfully submitted next urb in queue */ |
481 | spin_unlock(&usbhid->lock); | 500 | spin_unlock(&usbhid->lock); |
482 | return; | 501 | return; |
@@ -535,11 +554,27 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re | |||
535 | * the queue is known to run | 554 | * the queue is known to run |
536 | * but an earlier request may be stuck | 555 | * but an earlier request may be stuck |
537 | * we may need to time out | 556 | * we may need to time out |
538 | * no race because this is called under | 557 | * no race because the URB is blocked under |
539 | * spinlock | 558 | * spinlock |
540 | */ | 559 | */ |
541 | if (time_after(jiffies, usbhid->last_out + HZ * 5)) | 560 | if (time_after(jiffies, usbhid->last_out + HZ * 5)) { |
561 | usb_block_urb(usbhid->urbout); | ||
562 | /* drop lock to not deadlock if the callback is called */ | ||
563 | spin_unlock(&usbhid->lock); | ||
542 | usb_unlink_urb(usbhid->urbout); | 564 | usb_unlink_urb(usbhid->urbout); |
565 | spin_lock(&usbhid->lock); | ||
566 | usb_unblock_urb(usbhid->urbout); | ||
567 | /* | ||
568 | * if the unlinking has already completed | ||
569 | * the pump will have been stopped | ||
570 | * it must be restarted now | ||
571 | */ | ||
572 | if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl)) | ||
573 | if (!irq_out_pump_restart(hid)) | ||
574 | set_bit(HID_OUT_RUNNING, &usbhid->iofl); | ||
575 | |||
576 | |||
577 | } | ||
543 | } | 578 | } |
544 | return; | 579 | return; |
545 | } | 580 | } |
@@ -583,11 +618,25 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re | |||
583 | * the queue is known to run | 618 | * the queue is known to run |
584 | * but an earlier request may be stuck | 619 | * but an earlier request may be stuck |
585 | * we may need to time out | 620 | * we may need to time out |
586 | * no race because this is called under | 621 | * no race because the URB is blocked under |
587 | * spinlock | 622 | * spinlock |
588 | */ | 623 | */ |
589 | if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) | 624 | if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) { |
625 | usb_block_urb(usbhid->urbctrl); | ||
626 | /* drop lock to not deadlock if the callback is called */ | ||
627 | spin_unlock(&usbhid->lock); | ||
590 | usb_unlink_urb(usbhid->urbctrl); | 628 | usb_unlink_urb(usbhid->urbctrl); |
629 | spin_lock(&usbhid->lock); | ||
630 | usb_unblock_urb(usbhid->urbctrl); | ||
631 | /* | ||
632 | * if the unlinking has already completed | ||
633 | * the pump will have been stopped | ||
634 | * it must be restarted now | ||
635 | */ | ||
636 | if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) | ||
637 | if (!ctrl_pump_restart(hid)) | ||
638 | set_bit(HID_CTRL_RUNNING, &usbhid->iofl); | ||
639 | } | ||
591 | } | 640 | } |
592 | } | 641 | } |
593 | 642 | ||