aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPete Zaitcev <zaitcev@redhat.com>2008-06-01 21:23:07 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2008-07-21 15:16:25 -0700
commit6deb270b5c60680ca9117bd545302ea6a58bad42 (patch)
treea1edb9b518004c5939a29ac98a8314835b7e5166 /drivers
parentUSB: make SA1111 OHCI driver SA11x0 specific (diff)
downloadlinux-dev-6deb270b5c60680ca9117bd545302ea6a58bad42.tar.xz
linux-dev-6deb270b5c60680ca9117bd545302ea6a58bad42.zip
USB: ohci_hcd hang: submit vs. rmmod race
If we do rmmod ohci_hcd while an application is doing something, the following may happen: - a control URB completes (in finish_urb) and the ohci's endpoint is set into ED_UNLINK in ed_deschedule - same URB is (re)submitted because of the open/close loop or other such application behaviour - rmmod sets the state to HC_STATE_QUESCING - finish_unlinks happens at next SOF; normally it would set ed into ED_IDLE and immediately call ed_schedule (since URB had extra TDs queued), which sets it into ED_OPER. But the check in ed_schedule makes it fail with -EAGAIN (which is ignored) - from now on we have a dead URB stuck; it cannot even be unlinked because the ed status is not ED_OPER, and thus start_ed_unlink is not invoked. This patch removes the check. In 2.6.25, all callers check for __ACTIVE bit before invoking ed_schedule, which is more appropriate. Alan Stern and David Brownell approved of this (cautiously). Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ohci-q.c3
1 files changed, 0 insertions, 3 deletions
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 9b547407c934..6a9b4c557953 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -159,9 +159,6 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
{
int branch;
- if (ohci_to_hcd(ohci)->state == HC_STATE_QUIESCING)
- return -EAGAIN;
-
ed->state = ED_OPER;
ed->ed_prev = NULL;
ed->ed_next = NULL;