USB: Move hcd free_dev call into usb_disconnect

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

 



Hi:

USB: Move hcd free_dev call into usb_disconnect

I found a way to oops the kernel bug:

1. Open a USB device through devio.
2. Remove the hcd module in the host kernel.
3. Close the devio file descriptor.

The problem is that closing the file descriptor does usb_release_dev 
as it is the last reference.  usb_release_dev then tries to invoke
the hcd free_dev function (or rather dereferencing the hcd driver
struct).  This causes an oops as the hcd driver has already been
unloaded so the struct is gone.

This patch tries to fix this by bringing the free_dev call earlier
and into usb_disconnect.  I have verified that repeating the
above steps no longer crashes with this patch applied.

Signed-off-by: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 0cec6ca..d5a418d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1554,6 +1554,15 @@ static inline void usb_stop_pm(struct usb_device *udev)
 
 #endif
 
+static void hub_free_dev(struct usb_device *udev)
+{
+	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+	/* Root hubs aren't real devices, so don't free HCD resources */
+	if (hcd->driver->free_dev && udev->parent)
+		hcd->driver->free_dev(hcd, udev);
+}
+
 /**
  * usb_disconnect - disconnect a device (usbcore-internal)
  * @pdev: pointer to device being disconnected
@@ -1624,6 +1633,8 @@ void usb_disconnect(struct usb_device **pdev)
 
 	usb_stop_pm(udev);
 
+	hub_free_dev(udev);
+
 	put_device(&udev->dev);
 }
 
@@ -3191,6 +3202,7 @@ loop_disable:
 loop:
 		usb_ep0_reinit(udev);
 		release_address(udev);
+		hub_free_dev(udev);
 		usb_put_dev(udev);
 		if ((status == -ENOTCONN) || (status == -ENOTSUPP))
 			break;
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 0daff0d..ced0776 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -228,9 +228,6 @@ static void usb_release_dev(struct device *dev)
 	hcd = bus_to_hcd(udev->bus);
 
 	usb_destroy_configuration(udev);
-	/* Root hubs aren't real devices, so don't free HCD resources */
-	if (hcd->driver->free_dev && udev->parent)
-		hcd->driver->free_dev(hcd, udev);
 	usb_put_hcd(hcd);
 	kfree(udev->product);
 	kfree(udev->manufacturer);

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@xxxxxxxxxxxxxxxxxxx>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux