NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/48151: USB race condition can lead to panic



On 08/23/13 17:45, vincent%labri.fr@localhost wrote:
Number:         48151
Category:       kern
Synopsis:       USB race condition can lead to panic
[...]

I submit this PR because it's not clear to me what is the right solution. The 
cv_broadcast/wakeup is done in two places :

in the callbacks called by usb_transfer_complete()
right after, directly in usb_transfer_complete()

Removing one of the two is required, but I don't know which is intended 
conceptually. Removing any of the two should fix the race because the only 
reason the xfer is reused in usb_transfer_complete() is to do this 
cv_broadcast()...



Looks like the callbacks can safely be removed - usbd_sync_transfer_sig DTRT.

How about the attached diff? It fixes utoppy at the same time.

Nick
Index: usbdi_util.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usbdi_util.c,v
retrieving revision 1.59
diff -u -p -u -r1.59 usbdi_util.c
--- usbdi_util.c        5 Jan 2013 23:34:21 -0000       1.59
+++ usbdi_util.c        24 Aug 2013 08:23:30 -0000
@@ -415,19 +415,6 @@ usbd_get_config(usbd_device_handle dev, 
        return (usbd_do_request(dev, &req, conf));
 }
 
-Static void usbd_bulk_transfer_cb(usbd_xfer_handle xfer,
-                                 usbd_private_handle priv, usbd_status status);
-Static void
-usbd_bulk_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
-                     usbd_status status)
-{
-
-       if (xfer->pipe->device->bus->lock)
-               cv_broadcast(&xfer->cv);
-       else
-               wakeup(xfer);   /* XXXSMP ok */
-}
-
 usbd_status
 usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
                   u_int16_t flags, u_int32_t timeout, void *buf,
@@ -435,31 +422,19 @@ usbd_bulk_transfer(usbd_xfer_handle xfer
 {
        usbd_status err;
 
-       usbd_setup_xfer(xfer, pipe, 0, buf, *size,
-                       flags, timeout, usbd_bulk_transfer_cb);
-       DPRINTFN(1, ("usbd_bulk_transfer: start transfer %d bytes\n", *size));
+       usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout, NULL);
 
+       DPRINTFN(1, ("usbd_bulk_transfer: start transfer %d bytes\n", *size));
        err = usbd_sync_transfer_sig(xfer);
+
        usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
        DPRINTFN(1,("usbd_bulk_transfer: transferred %d\n", *size));
        if (err) {
                DPRINTF(("usbd_bulk_transfer: error=%d\n", err));
                usbd_clear_endpoint_stall(pipe);
        }
-       return (err);
-}
-
-Static void usbd_intr_transfer_cb(usbd_xfer_handle xfer,
-                                 usbd_private_handle priv, usbd_status status);
-Static void
-usbd_intr_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
-                     usbd_status status)
-{
 
-       if (xfer->pipe->device->bus->lock)
-               cv_broadcast(&xfer->cv);
-       else
-               wakeup(xfer);   /* XXXSMP ok */
+       return (err);
 }
 
 usbd_status
@@ -469,11 +444,13 @@ usbd_intr_transfer(usbd_xfer_handle xfer
 {
        usbd_status err;
 
-       usbd_setup_xfer(xfer, pipe, 0, buf, *size,
-                       flags, timeout, usbd_intr_transfer_cb);
+       usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout, NULL);
+
        DPRINTFN(1, ("usbd_intr_transfer: start transfer %d bytes\n", *size));
        err = usbd_sync_transfer_sig(xfer);
+
        usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
+
        DPRINTFN(1,("usbd_intr_transfer: transferred %d\n", *size));
        if (err) {
                DPRINTF(("usbd_intr_transfer: error=%d\n", err));
Index: utoppy.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/utoppy.c,v
retrieving revision 1.21
diff -u -p -u -r1.21 utoppy.c
--- utoppy.c    27 Oct 2012 17:18:38 -0000      1.21
+++ utoppy.c    24 Aug 2013 08:23:31 -0000
@@ -537,22 +537,10 @@ utoppy_bulk_transfer(usbd_xfer_handle xf
 
        usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout,
            utoppy_bulk_transfer_cb);
-       usbd_lock_pipe(pipe);   /* don't want callback until tsleep() */
-       err = usbd_transfer(xfer);
-       if (err != USBD_IN_PROGRESS) {
-               usbd_unlock_pipe(pipe);
-               return (err);
-       }
-       if (pipe->device->bus->lock)
-               error = cv_wait_sig(&xfer->cv, pipe->device->bus->lock);
-       else
-               error = tsleep((void *)xfer, PZERO, lbl, 0);
-       usbd_unlock_pipe(pipe);
-       if (error) {
-               usbd_abort_pipe(pipe);
-               return (USBD_INTERRUPTED);
-       }
-       usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
+
+       err = usbd_sync_transfer_sig(xfer);
+
+       usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
        return (err);
 }
 


Home | Main Index | Thread Index | Old Index