summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb_request.c
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2016-09-12 10:14:30 +0000
committerhselasky <hselasky@FreeBSD.org>2016-09-12 10:14:30 +0000
commita1a22a6289df77ce21f083b6b8f3334eaeba390e (patch)
tree296e7778360b96185b83ef1a47f4015819c4598d /sys/dev/usb/usb_request.c
parent860932ee33fe82330891c9acc939827c05f20999 (diff)
downloadFreeBSD-src-a1a22a6289df77ce21f083b6b8f3334eaeba390e.zip
FreeBSD-src-a1a22a6289df77ce21f083b6b8f3334eaeba390e.tar.gz
MFC r305421:
Resolve deadlock between device_detach() and usbd_do_request_flags() by reviving the SX control request lock and refining which lock protects the common scratch area in "struct usb_device". The SX control request lock was removed by r246759 because it caused a lock order reversal with the USB enumeration lock inside usbd_transfer_setup() as a function of r246616. It was thought that reducing the number of locks would resolve the LOR, but because some USB device drivers use usbd_do_request_flags() inside callback functions, like in taskqueues, a deadlock may occur when these are drained from device_detach(). By restoring the SX control request lock usbd_do_request_flags() is allowed to complete its execution when a USB device driver is detaching. By using the SX control request lock to protect the scratch area, the LOR introduced by r246616 is also resolved. Bump the FreeBSD version while at it to force recompilation of all USB kernel modules. Found by: avos@
Diffstat (limited to 'sys/dev/usb/usb_request.c')
-rw-r--r--sys/dev/usb/usb_request.c15
1 files changed, 3 insertions, 12 deletions
diff --git a/sys/dev/usb/usb_request.c b/sys/dev/usb/usb_request.c
index 634d423..7c02282 100644
--- a/sys/dev/usb/usb_request.c
+++ b/sys/dev/usb/usb_request.c
@@ -460,16 +460,9 @@ usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
}
/*
- * Grab the USB device enumeration SX-lock serialization is
- * achieved when multiple threads are involved:
+ * Serialize access to this function:
*/
- do_unlock = usbd_enum_lock(udev);
-
- /*
- * We need to allow suspend and resume at this point, else the
- * control transfer will timeout if the device is suspended!
- */
- usbd_sr_unlock(udev);
+ do_unlock = usbd_ctrl_lock(udev);
hr_func = usbd_get_hr_func(udev);
@@ -713,10 +706,8 @@ usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
USB_XFER_UNLOCK(xfer);
done:
- usbd_sr_lock(udev);
-
if (do_unlock)
- usbd_enum_unlock(udev);
+ usbd_ctrl_unlock(udev);
if ((mtx != NULL) && (mtx != &Giant))
mtx_lock(mtx);
OpenPOWER on IntegriCloud