diff options
author | hselasky <hselasky@FreeBSD.org> | 2011-08-20 15:12:53 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2011-08-20 15:12:53 +0000 |
commit | 9b44ba7fde351b9f280a957237fbe64db3f601e9 (patch) | |
tree | 5a0184c104664c570194b020a3775bef5fcba6f9 | |
parent | 727eb4fe3932d21042450cf3c33a8173707bd9c1 (diff) | |
download | FreeBSD-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.c | 24 |
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 |