diff options
author | Oliver Neukum <oliver@neukum.org> | 2012-04-30 09:13:46 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-05-01 13:22:13 -0400 |
commit | 8815bb09af21316aeb5f8948b24ac62181670db2 (patch) | |
tree | a6667e719e124f06257f1b9cb11abe6bce9295b0 /drivers/usb/core/urb.c | |
parent | 166cb70e97bd83d7ae9bbec6ae59a178fd9bb823 (diff) | |
download | linux-8815bb09af21316aeb5f8948b24ac62181670db2.tar.gz linux-8815bb09af21316aeb5f8948b24ac62181670db2.tar.bz2 linux-8815bb09af21316aeb5f8948b24ac62181670db2.zip |
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/usb/core/urb.c')
-rw-r--r-- | drivers/usb/core/urb.c | 21 |
1 files changed, 21 insertions, 0 deletions
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 @@ -681,6 +681,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 * |