aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2012-04-30 09:13:46 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-05-01 13:22:13 -0400
commit8815bb09af21316aeb5f8948b24ac62181670db2 (patch)
treea6667e719e124f06257f1b9cb11abe6bce9295b0 /drivers/usb/core
parentusb: add USB_QUIRK_RESET_RESUME for M-Audio 88es (diff)
downloadlinux-dev-8815bb09af21316aeb5f8948b24ac62181670db2.tar.xz
linux-dev-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')
-rw-r--r--drivers/usb/core/urb.c21
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
*