NetBSD-Bugs archive

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

xsrc/41595: usb xfer re-entry. When the xfer's interrupt & the xfer's abort task occur at the same time, this will cause the USB stack crash.



>Number:         41595
>Category:       xsrc
>Synopsis:       usb xfer re-entry. When the xfer's interrupt & the xfer's 
>abort task occur at the same time, this will cause the USB stack crash.
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    xsrc-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Jun 14 11:00:01 +0000 2009
>Originator:     zhenhua,lin
>Release:        no
>Organization:
no
>Environment:
no.
This problem found at the code review phase.
>Description:
Sorry for my poor English.

In the following situation will cause usb xfer re-entry, and cause the usb 
stack crash:
1) XFER timeout, causes *hci_timeout be called;
2) *hci_timeout adds the ohci_timeout_task() to the task, in order to execute 
this abort transaction in a process context;
 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        /* Execute the abort in a process context. */
        usb_init_task(&oxfer->abort_task, ohci_timeout_task, addr);
        usb_add_task(oxfer->xfer.pipe->device, &oxfer->abort_task,
            USB_TASKQ_HC);
<<<<<<<<<<<<<<<<<<<<<<<<<<<<

3) If this xfer comes back at this time,
   Of course, the system will response to the interrupt first;
   This will cause this xfer be done, and removed from the xfer;
4) Timeout abort transaction will be called after the interrupt, and call the 
usb_transfer_complete().

This will cause the xfer re-entry.
>How-To-Repeat:
see above, Thanks.
>Fix:
void
*hci_timeout_task(void *addr)
{
        usbd_xfer_handle xfer = addr;
        int s;

        DPRINTF(("*hci_timeout_task: xfer=%p\n", xfer));

        s = splusb();
        *hci_abort_xfer(xfer, USBD_TIMEOUT);
        splx(s);
}


to ==========>


void
*hci_timeout_task(void *addr)
{
        usbd_xfer_handle xfer = addr;
        int s;

        DPRINTF(("*hci_timeout_task: xfer=%p\n", xfer));

        if (xfer->done != 1)
        {
            s = splusb();
            *hci_abort_xfer(xfer, USBD_TIMEOUT);
            splx(s);
        }
}



Home | Main Index | Thread Index | Old Index