Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 1 Jun 2009 12:31:41 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 163254 for review
Message-ID:  <200906011231.n51CVf7C066020@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=163254

Change 163254 by hselasky@hselasky_laptop001 on 2009/06/01 12:30:53

	
	USB CORE: Fix multithread issue where
	the is_uref variable was not set and cleared
	properly in the CDEV private data.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/usb_dev.c#25 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/usb_dev.c#25 (text+ko) ====

@@ -169,21 +169,23 @@
 	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 @@
 		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 @@
 	}
 	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 @@
 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 @@
 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 @@
 		}
 		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);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906011231.n51CVf7C066020>