[PATCH 5/6] USB: make hub driver's release more robust
Alan Stern <[email protected]>
| Newsgroups | gmane.linux.usb.devel |
|---|---|
| Message-ID | <[email protected]> |
This patch (as893) improves the method used by the hub driver to release its private data structure. The current code is non-robust, relying on a memory region not getting reused by another driver after it has been freed. Signed-off-by: Alan Stern <[email protected]> --- Index: usb-2.6/drivers/usb/core/hub.c =================================================================== --- usb-2.6.orig/drivers/usb/core/hub.c +++ usb-2.6/drivers/usb/core/hub.c @@ -67,6 +67,7 @@ struct usb_hub { unsigned limited_power:1; unsigned quiescing:1; unsigned activating:1; + unsigned disconnected:1; unsigned has_indicators:1; u8 indicator[USB_MAXCHILDREN]; @@ -333,6 +334,7 @@ static void kick_khubd(struct usb_hub *h void usb_kick_khubd(struct usb_device *hdev) { + /* FIXME: What if hdev isn't bound to the hub driver? */ kick_khubd(hdev_to_hub(hdev)); } @@ -933,6 +935,7 @@ static void hub_disconnect(struct usb_in struct usb_device *hdev; /* Disconnect all children and quiesce the hub */ + hub->disconnected = 1; hub->error = 0; hub_pre_reset(intf); @@ -945,10 +948,6 @@ static void hub_disconnect(struct usb_in usb_free_urb(hub->urb); hub->urb = NULL; - spin_lock_irq(&hub_event_lock); - list_del_init(&hub->event_list); - spin_unlock_irq(&hub_event_lock); - kfree(hub->descriptor); hub->descriptor = NULL; @@ -961,7 +960,9 @@ static void hub_disconnect(struct usb_in hub->buffer = NULL; } - kfree(hub); + /* Rely on khubd to deallocate hub */ + usb_get_intf(intf); + kick_khubd(hub); } static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -2625,14 +2626,21 @@ static void hub_events(void) (u16) hub->change_bits[0], (u16) hub->event_bits[0]); - usb_get_intf(intf); spin_unlock_irq(&hub_event_lock); /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ usb_lock_device(hdev); - if (hub != usb_get_intfdata(intf)) - goto loop; + if (unlikely(hub->disconnected)) { + usb_unlock_device(hdev); + spin_lock_irq(&hub_event_lock); + list_del(&hub->event_list); + spin_unlock_irq(&hub_event_lock); + + kfree(hub); + usb_put_intf(intf); /* From hub_disconnect() */ + continue; + } /* If the hub has died, clean up after it */ if (hdev->state == USB_STATE_NOTATTACHED) { @@ -2794,7 +2802,6 @@ loop_autopm: usb_autopm_enable(intf); loop: usb_unlock_device(hdev); - usb_put_intf(intf); } /* end while (1) */ } ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ [email protected] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel