On Tue, Sep 11, 2012 at 11:34:56AM -0400, Alan Stern wrote:
> On Mon, 10 Sep 2012, Don Zickus wrote:
>
> > A customer of ours noticed that after a bunch of hot removals of the EHCI
> > PCI device, a panic occurs. This happened on a 2.6.32 RHEL-6 kernel, but
> > I believe is still applicable upstream.
> >
> > The panic was further simplified to enabling SLUB debug poisoning and
> > running
> > the following command:
> >
> > while true; do find /proc/bus/usb -type f -exec cat {} >/dev/null \; ; done
> > &
> >
> > This gets the machine to panic after 1 or 2 removals of the device.
>
> > This is likely because the following thread was in the process of removing
> > the
> > device:
>
> > The fix that solved their problem was to deregister the usb bus first before
> > running usb_put_dev. After running multiple tests the panic disappeared.
> >
> > Deregistering the bus first to prevent future readers from accessing the
> > device
> > before cleaning up the hcd, seemed like an appropriate way to go. I'll
> > leave
> > it to the experts to validate that or provide a better solution. :-)
> >
> > I adapted their usb_remove_hcd fix for usb_add_hcd error path too to mimic
> > the same behaviour (a little code shuffling to handle the gotos cleanly).
>
> Moving things around in usb_add_hcd() is not a good way to attack this
> problem. Here's a better approach; please make sure that it does what
> you want. The idea is to indicate that a root hub is not registered by
> setting its devnum field to 0.
Thanks for the feedback. I will pass this along for testing and get back
to you.
Thanks,
Don
>
> Alan Stern
>
>
>
> Index: usb-3.6/drivers/usb/core/devices.c
> ===================================================================
> --- usb-3.6.orig/drivers/usb/core/devices.c
> +++ usb-3.6/drivers/usb/core/devices.c
> @@ -624,7 +624,7 @@ static ssize_t usb_device_read(struct fi
> /* print devices for all busses */
> list_for_each_entry(bus, &usb_bus_list, bus_list) {
> /* recurse through all children of the root hub */
> - if (!bus->root_hub)
> + if (!bus->root_hub || bus->root_hub->devnum == 0)
> continue;
> usb_lock_device(bus->root_hub);
> ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos,
> Index: usb-3.6/drivers/usb/core/hcd.c
> ===================================================================
> --- usb-3.6.orig/drivers/usb/core/hcd.c
> +++ usb-3.6/drivers/usb/core/hcd.c
> @@ -980,6 +980,8 @@ static int register_root_hub(struct usb_
> const int devnum = 1;
> int retval;
>
> + mutex_lock(&usb_bus_list_lock);
> +
> usb_dev->devnum = devnum;
> usb_dev->bus->devnum_next = devnum + 1;
> memset (&usb_dev->bus->devmap.devicemap, 0,
> @@ -987,8 +989,6 @@ static int register_root_hub(struct usb_
> set_bit (devnum, usb_dev->bus->devmap.devicemap);
> usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
>
> - mutex_lock(&usb_bus_list_lock);
> -
> usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
> retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
> if (retval != sizeof usb_dev->descriptor) {
> @@ -1011,6 +1011,7 @@ static int register_root_hub(struct usb_
> if (retval) {
> dev_err (parent_dev, "can't register root hub for %s, %d\n",
> dev_name(&usb_dev->dev), retval);
> + usb_dev->devnum = 0;
> }
> mutex_unlock(&usb_bus_list_lock);
>
> @@ -2527,6 +2528,7 @@ error_create_attr_group:
> #endif
> mutex_lock(&usb_bus_list_lock);
> usb_disconnect(&rhdev); /* Sets rhdev to NULL */
> + hcd->self.root_hub->devnum = 0;
> mutex_unlock(&usb_bus_list_lock);
> err_register_root_hub:
> hcd->rh_pollable = 0;
> @@ -2583,6 +2585,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
>
> mutex_lock(&usb_bus_list_lock);
> usb_disconnect(&rhdev); /* Sets rhdev to NULL */
> + hcd->self.root_hub->devnum = 0;
> mutex_unlock(&usb_bus_list_lock);
>
> /* Prevent any more root-hub status calls from the timer.
>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html