Fix multithread issue where the is_uref variable was not set and cleared

properly in the CDEV private data.

Submitted by:	Hans Petter Selasky
This commit is contained in:
Andrew Thompson 2009-06-02 17:30:18 +00:00
parent 7b8b6d352f
commit a488edb567
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=193316

View File

@ -169,21 +169,23 @@ usb2_ref_device(struct usb_cdev_privdata* cpd, int need_uref)
cpd->bus = devclass_get_softc(usb2_devclass_ptr, cpd->bus_index);
if (cpd->bus == NULL) {
DPRINTFN(2, "no bus at %u\n", cpd->bus_index);
need_uref = 0;
goto error;
}
cpd->udev = cpd->bus->devices[cpd->dev_index];
if (cpd->udev == NULL) {
DPRINTFN(2, "no device at %u\n", cpd->dev_index);
need_uref = 0;
goto error;
}
if (cpd->udev->refcount == USB_DEV_REF_MAX) {
DPRINTFN(2, "no dev ref\n");
need_uref = 0;
goto error;
}
if (need_uref) {
DPRINTFN(2, "ref udev - needed\n");
cpd->udev->refcount++;
cpd->is_uref = 1;
mtx_unlock(&usb2_ref_lock);
@ -194,6 +196,11 @@ usb2_ref_device(struct usb_cdev_privdata* cpd, int need_uref)
sx_xlock(cpd->udev->default_sx + 1);
mtx_lock(&usb2_ref_lock);
/*
* Set "is_uref" after grabbing the default SX lock
*/
cpd->is_uref = 1;
}
/* check if we are doing an open */
@ -258,18 +265,18 @@ usb2_ref_device(struct usb_cdev_privdata* cpd, int need_uref)
}
mtx_unlock(&usb2_ref_lock);
if (cpd->is_uref) {
if (need_uref) {
mtx_lock(&Giant); /* XXX */
}
return (0);
error:
if (cpd->is_uref) {
if (need_uref) {
cpd->is_uref = 0;
sx_unlock(cpd->udev->default_sx + 1);
if (--(cpd->udev->refcount) == 0) {
usb2_cv_signal(cpd->udev->default_cv + 1);
}
cpd->is_uref = 0;
}
mtx_unlock(&usb2_ref_lock);
DPRINTFN(2, "fail\n");
@ -289,10 +296,14 @@ usb2_ref_device(struct usb_cdev_privdata* cpd, int need_uref)
static usb_error_t
usb2_usb_ref_device(struct usb_cdev_privdata *cpd)
{
uint8_t is_uref;
is_uref = cpd->is_uref && sx_xlocked(cpd->udev->default_sx + 1);
/*
* Check if we already got an USB reference on this location:
*/
if (cpd->is_uref)
if (is_uref)
return (0); /* success */
/*
@ -313,7 +324,12 @@ usb2_usb_ref_device(struct usb_cdev_privdata *cpd)
void
usb2_unref_device(struct usb_cdev_privdata *cpd)
{
if (cpd->is_uref) {
uint8_t is_uref;
is_uref = cpd->is_uref && sx_xlocked(cpd->udev->default_sx + 1);
if (is_uref) {
cpd->is_uref = 0;
mtx_unlock(&Giant); /* XXX */
sx_unlock(cpd->udev->default_sx + 1);
}
@ -330,11 +346,10 @@ usb2_unref_device(struct usb_cdev_privdata *cpd)
}
cpd->is_write = 0;
}
if (cpd->is_uref) {
if (is_uref) {
if (--(cpd->udev->refcount) == 0) {
usb2_cv_signal(cpd->udev->default_cv + 1);
}
cpd->is_uref = 0;
}
mtx_unlock(&usb2_ref_lock);
}