diff options
author | hselasky <hselasky@FreeBSD.org> | 2014-03-27 06:59:56 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2014-03-27 06:59:56 +0000 |
commit | 5d4dbd39e385c96979daf137b2a7851287002c42 (patch) | |
tree | 1ecf3aaf2a06c2128c4f1ebc9ac55083e138ea09 /sys/dev/usb/usb_dev.c | |
parent | 609200cd258f7cda640616b44ce2c91d80301f17 (diff) | |
download | FreeBSD-src-5d4dbd39e385c96979daf137b2a7851287002c42.zip FreeBSD-src-5d4dbd39e385c96979daf137b2a7851287002c42.tar.gz |
MFC r263423:
Try to resolve a possible deadlock when detaching USB devices which
create character devices. The deadlock can happen if an application is
issuing IOCTLs which require USB refcounting, at the same time the USB
device is detaching.
There is already a counter in place in the USB device structure to
detect this situation, but it was not always checked ahead of invoking
functions that might destroy character devices, like detach, set
configuration, set alternate interface or detach active kernel driver.
Diffstat (limited to 'sys/dev/usb/usb_dev.c')
-rw-r--r-- | sys/dev/usb/usb_dev.c | 19 |
1 files changed, 9 insertions, 10 deletions
diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c index c81b942..e4471ae 100644 --- a/sys/dev/usb/usb_dev.c +++ b/sys/dev/usb/usb_dev.c @@ -214,12 +214,13 @@ usb_ref_device(struct usb_cdev_privdata *cpd, DPRINTFN(2, "device is detached\n"); goto error; } - if (cpd->udev->refcount == USB_DEV_REF_MAX) { - DPRINTFN(2, "no dev ref\n"); - goto error; - } if (need_uref) { DPRINTFN(2, "ref udev - needed\n"); + + if (cpd->udev->refcount == USB_DEV_REF_MAX) { + DPRINTFN(2, "no dev ref\n"); + goto error; + } cpd->udev->refcount++; mtx_unlock(&usb_ref_lock); @@ -293,9 +294,8 @@ error: usbd_enum_unlock(cpd->udev); if (crd->is_uref) { - if (--(cpd->udev->refcount) == 0) { - cv_signal(&cpd->udev->ref_cv); - } + cpd->udev->refcount--; + cv_broadcast(&cpd->udev->ref_cv); } mtx_unlock(&usb_ref_lock); DPRINTFN(2, "fail\n"); @@ -361,10 +361,9 @@ usb_unref_device(struct usb_cdev_privdata *cpd, crd->is_write = 0; } if (crd->is_uref) { - if (--(cpd->udev->refcount) == 0) { - cv_signal(&cpd->udev->ref_cv); - } crd->is_uref = 0; + cpd->udev->refcount--; + cv_broadcast(&cpd->udev->ref_cv); } mtx_unlock(&usb_ref_lock); } |