Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 2 Jun 2009 17:30:18 +0000 (UTC)
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r193316 - head/sys/dev/usb
Message-ID:  <200906021730.n52HUIMQ022202@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: thompsa
Date: Tue Jun  2 17:30:18 2009
New Revision: 193316
URL: http://svn.freebsd.org/changeset/base/193316

Log:
  Fix multithread issue where the is_uref variable was not set and cleared
  properly in the CDEV private data.
  
  Submitted by:	Hans Petter Selasky

Modified:
  head/sys/dev/usb/usb_dev.c

Modified: head/sys/dev/usb/usb_dev.c
==============================================================================
--- head/sys/dev/usb/usb_dev.c	Tue Jun  2 17:29:15 2009	(r193315)
+++ head/sys/dev/usb/usb_dev.c	Tue Jun  2 17:30:18 2009	(r193316)
@@ -169,21 +169,23 @@ usb2_ref_device(struct usb_cdev_privdata
 	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
 		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
 	}
 	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 @@ error:
 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_priv
 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_privda
 		}
 		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?200906021730.n52HUIMQ022202>