From 8815bb09af21316aeb5f8948b24ac62181670db2 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 30 Apr 2012 09:13:46 +0200 Subject: 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 Acked-by: Jiri Kosina Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/urb.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/usb/core/urb.c') diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index cd9b3a2cd8a7..9d912bfdcffe 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -680,6 +680,27 @@ void usb_unpoison_urb(struct urb *urb) } EXPORT_SYMBOL_GPL(usb_unpoison_urb); +/** + * usb_block_urb - reliably prevent further use of an URB + * @urb: pointer to URB to be blocked, may be NULL + * + * After the routine has run, attempts to resubmit the URB will fail + * with error -EPERM. Thus even if the URB's completion handler always + * tries to resubmit, it will not succeed and the URB will become idle. + * + * The URB must not be deallocated while this routine is running. In + * particular, when a driver calls this routine, it must insure that the + * completion handler cannot deallocate the URB. + */ +void usb_block_urb(struct urb *urb) +{ + if (!urb) + return; + + atomic_inc(&urb->reject); +} +EXPORT_SYMBOL_GPL(usb_block_urb); + /** * usb_kill_anchored_urbs - cancel transfer requests en masse * @anchor: anchor the requests are bound to -- cgit v1.2.3-70-g09d2