diff options
author | hselasky <hselasky@FreeBSD.org> | 2014-01-24 08:10:08 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2014-01-24 08:10:08 +0000 |
commit | 6e5156d6bb6755f251e480703c56db26ea69c02a (patch) | |
tree | 7e6f2f512b9261046f389034ef2aafa0d782d0e8 /sys/dev/usb/usb_dev.c | |
parent | f692196495136a8dd592a7f06a940e6fae03fd6d (diff) | |
download | FreeBSD-src-6e5156d6bb6755f251e480703c56db26ea69c02a.zip FreeBSD-src-6e5156d6bb6755f251e480703c56db26ea69c02a.tar.gz |
MFC r260808 and r260814:
- Close a minor deadlock.
- Fix a possible memory use after free and leak situation associated
with USB device detach when using character device handles. This also
includes LibUSB. It turns out that "usb_close()" cannot always get a
reference to clean up its USB transfers and such, if called during the
kernel USB device detach.
Diffstat (limited to 'sys/dev/usb/usb_dev.c')
-rw-r--r-- | sys/dev/usb/usb_dev.c | 33 |
1 files changed, 17 insertions, 16 deletions
diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c index 9e3cef5..6a3080f 100644 --- a/sys/dev/usb/usb_dev.c +++ b/sys/dev/usb/usb_dev.c @@ -207,6 +207,11 @@ usb_ref_device(struct usb_cdev_privdata *cpd, DPRINTFN(2, "no device at %u\n", cpd->dev_index); goto error; } + if (cpd->udev->state == USB_STATE_DETACHED && + (need_uref != 2)) { + DPRINTFN(2, "device is detached\n"); + goto error; + } if (cpd->udev->refcount == USB_DEV_REF_MAX) { DPRINTFN(2, "no dev ref\n"); goto error; @@ -597,6 +602,13 @@ usb_fifo_free(struct usb_fifo *f) mtx_unlock(f->priv_mtx); mtx_lock(&usb_ref_lock); + /* + * Check if the "f->refcount" variable reached zero + * during the unlocked time before entering wait: + */ + if (f->refcount == 0) + break; + /* wait for sync */ cv_wait(&f->cv_drain, &usb_ref_lock); } @@ -915,23 +927,12 @@ usb_close(void *arg) DPRINTFN(2, "cpd=%p\n", cpd); - err = usb_ref_device(cpd, &refs, 0); - if (err) + err = usb_ref_device(cpd, &refs, + 2 /* uref and allow detached state */); + if (err) { + DPRINTFN(0, "Cannot grab USB reference when " + "closing USB file handle\n"); 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); |