PERFORCE change 170001 for review

Hans Petter Selasky hselasky at FreeBSD.org
Sat Oct 31 15:40:45 UTC 2009


http://p4web.freebsd.org/chv.cgi?CH=170001

Change 170001 by hselasky at hselasky_laptop001 on 2009/10/31 15:39:49

	
	USB CORE:
		- Fix a corner case where usbd_transfer_drain() can return
		too early. This fixes some rare panics at USB device detach.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/usb_core.h#28 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#170 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/usb_core.h#28 (text+ko) ====

@@ -112,6 +112,7 @@
 	uint8_t	curr_dma_set:1;		/* used by USB HC/DC driver */
 	uint8_t	can_cancel_immed:1;	/* set if USB transfer can be
 					 * cancelled immediately */
+	uint8_t	doing_callback:1;	/* set if executing the callback */
 };
 
 /*

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

@@ -1797,8 +1797,18 @@
 
 	usbd_transfer_stop(xfer);
 
-	while (usbd_transfer_pending(xfer)) {
+	while (usbd_transfer_pending(xfer) || 
+	    xfer->flags_int.doing_callback) {
+
+		/* 
+		 * It is allowed that the callback can drop its
+		 * transfer mutex. In that case checking only
+		 * "usbd_transfer_pending()" is not enough to tell if
+		 * the USB transfer is fully drained. We also need to
+		 * check the internal "doing_callback" flag.
+		 */
 		xfer->flags_int.draining = 1;
+
 		/*
 		 * Wait until the current outstanding USB
 		 * transfer is complete !
@@ -2043,6 +2053,9 @@
 	/* get next USB transfer in the queue */
 	info->done_q.curr = NULL;
 
+	/* set flag in case of drain */
+	xfer->flags_int.doing_callback = 1;
+
 	USB_BUS_UNLOCK(info->bus);
 	USB_BUS_LOCK_ASSERT(info->bus, MA_NOTOWNED);
 
@@ -2095,12 +2108,17 @@
 	if ((!xfer->flags_int.open) &&
 	    (xfer->flags_int.started) &&
 	    (xfer->usb_state == USB_ST_ERROR)) {
+		/* clear flag in case of drain */
+		xfer->flags_int.doing_callback = 0;
 		/* try to loop, but not recursivly */
 		usb_command_wrapper(&info->done_q, xfer);
 		return;
 	}
 
 done:
+	/* clear flag in case of drain */
+	xfer->flags_int.doing_callback = 0;
+
 	/*
 	 * Check if we are draining.
 	 */


More information about the p4-projects mailing list