[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.