diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-03-13 11:10:52 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-04-27 16:28:34 -0400 |
commit | 1b42ae6d4355328dc4406b6f0188adcf8c566435 (patch) | |
tree | 054e44f46fd7c2c4b25e4a7d40313879c5a4bffd | |
parent | 949be0f7be8de0c5a6a46626bd983f7a03a4b26e (diff) |
USB: fix race in HCD removal
This patch (as865) fixes a race in the HCD removal code discovered by
Milan Plzik. Arrival of an interrupt after the root hub was
unregistered could cause the root-hub status timer to start up, even
after it was supposed to have been shut down. The problem is fixed by
moving the del_timer_sync() call to after the HCD's stop() method, at
which time IRQ generation should be disabled.
Cc: Milan Plzik <milan.plzik@gmail.com>
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/core/hcd.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index b26c19e8d19f..af7aed11398b 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -544,6 +544,8 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) | |||
544 | unsigned long flags; | 544 | unsigned long flags; |
545 | char buffer[4]; /* Any root hubs with > 31 ports? */ | 545 | char buffer[4]; /* Any root hubs with > 31 ports? */ |
546 | 546 | ||
547 | if (unlikely(!hcd->rh_registered)) | ||
548 | return; | ||
547 | if (!hcd->uses_new_polling && !hcd->status_urb) | 549 | if (!hcd->uses_new_polling && !hcd->status_urb) |
548 | return; | 550 | return; |
549 | 551 | ||
@@ -1670,12 +1672,12 @@ void usb_remove_hcd(struct usb_hcd *hcd) | |||
1670 | usb_disconnect(&hcd->self.root_hub); | 1672 | usb_disconnect(&hcd->self.root_hub); |
1671 | mutex_unlock(&usb_bus_list_lock); | 1673 | mutex_unlock(&usb_bus_list_lock); |
1672 | 1674 | ||
1673 | hcd->poll_rh = 0; | ||
1674 | del_timer_sync(&hcd->rh_timer); | ||
1675 | |||
1676 | hcd->driver->stop(hcd); | 1675 | hcd->driver->stop(hcd); |
1677 | hcd->state = HC_STATE_HALT; | 1676 | hcd->state = HC_STATE_HALT; |
1678 | 1677 | ||
1678 | hcd->poll_rh = 0; | ||
1679 | del_timer_sync(&hcd->rh_timer); | ||
1680 | |||
1679 | if (hcd->irq >= 0) | 1681 | if (hcd->irq >= 0) |
1680 | free_irq(hcd->irq, hcd); | 1682 | free_irq(hcd->irq, hcd); |
1681 | usb_deregister_bus(&hcd->self); | 1683 | usb_deregister_bus(&hcd->self); |