summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2011-08-20 15:12:53 +0000
committerhselasky <hselasky@FreeBSD.org>2011-08-20 15:12:53 +0000
commit9b44ba7fde351b9f280a957237fbe64db3f601e9 (patch)
tree5a0184c104664c570194b020a3775bef5fcba6f9
parent727eb4fe3932d21042450cf3c33a8173707bd9c1 (diff)
downloadFreeBSD-src-9b44ba7fde351b9f280a957237fbe64db3f601e9.zip
FreeBSD-src-9b44ba7fde351b9f280a957237fbe64db3f601e9.tar.gz
Fix for recursive locking in usb_close() after change 224777.
Approved by: re (kib) MFC after: 3 days Reported by: kwm @
-rw-r--r--sys/dev/usb/usb_dev.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c
index 7a83ee3..990bda2 100644
--- a/sys/dev/usb/usb_dev.c
+++ b/sys/dev/usb/usb_dev.c
@@ -911,10 +911,23 @@ usb_close(void *arg)
DPRINTFN(2, "cpd=%p\n", cpd);
- err = usb_ref_device(cpd, &refs, 1);
- if (err) {
- free(cpd, M_USBDEV);
- return;
+ err = usb_ref_device(cpd, &refs, 0);
+ if (err)
+ goto done;
+
+ /*
+ * If this function is not called directly from the root HUB
+ * thread, there is usually a need to lock the enumeration
+ * lock. Check this.
+ */
+ if (!usbd_enum_is_locked(cpd->udev)) {
+
+ DPRINTFN(2, "Locking enumeration\n");
+
+ /* reference device */
+ err = usb_usb_ref_device(cpd, &refs);
+ if (err)
+ goto done;
}
if (cpd->fflags & FREAD) {
usb_fifo_close(refs.rxfifo, cpd->fflags);
@@ -922,10 +935,9 @@ usb_close(void *arg)
if (cpd->fflags & FWRITE) {
usb_fifo_close(refs.txfifo, cpd->fflags);
}
-
usb_unref_device(cpd, &refs);
+done:
free(cpd, M_USBDEV);
- return;
}
static void
OpenPOWER on IntegriCloud