Hi, On 22.11.2021 11:50, Mathias Nyman wrote: > Fix the circular lock dependency and unbalanced unlock of addess0_mutex > introduced when fixing an address0_mutex enumeration retry race in commit > ae6dc22d2d1 ("usb: hub: Fix usb enumeration issue due to address0 race") > > Make sure locking order between port_dev->status_lock and address0_mutex > is correct, and that address0_mutex is not unlocked in hub_port_connect > "done:" codepath which may be reached without locking address0_mutex > > Fixes: 6ae6dc22d2d1 ("usb: hub: Fix usb enumeration issue due to address0 race") > Cc: <stable@xxxxxxxxxxxxxxx> > Signed-off-by: Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx> This fixes the issue I've reported here: https://lore.kernel.org/all/f3bfcbc7-f701-c74a-09bd-6491d4c8d863@xxxxxxxxxxx/ Reported-by: Marek Szyprowski <m.szyprowski@xxxxxxxxxxx> Tested-by: Marek Szyprowski <m.szyprowski@xxxxxxxxxxx> > --- > drivers/usb/core/hub.c | 20 ++++++++++++-------- > 1 file changed, 12 insertions(+), 8 deletions(-) > > diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c > index 00c3506324e4..00070a8a6507 100644 > --- a/drivers/usb/core/hub.c > +++ b/drivers/usb/core/hub.c > @@ -5188,6 +5188,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, > struct usb_port *port_dev = hub->ports[port1 - 1]; > struct usb_device *udev = port_dev->child; > static int unreliable_port = -1; > + bool retry_locked; > > /* Disconnect any existing devices under this port */ > if (udev) { > @@ -5244,10 +5245,10 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, > > status = 0; > > - mutex_lock(hcd->address0_mutex); > - > for (i = 0; i < PORT_INIT_TRIES; i++) { > - > + usb_lock_port(port_dev); > + mutex_lock(hcd->address0_mutex); > + retry_locked = true; > /* reallocate for each attempt, since references > * to the previous one can escape in various ways > */ > @@ -5255,6 +5256,8 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, > if (!udev) { > dev_err(&port_dev->dev, > "couldn't allocate usb_device\n"); > + mutex_unlock(hcd->address0_mutex); > + usb_unlock_port(port_dev); > goto done; > } > > @@ -5276,13 +5279,13 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, > } > > /* reset (non-USB 3.0 devices) and get descriptor */ > - usb_lock_port(port_dev); > status = hub_port_init(hub, udev, port1, i); > - usb_unlock_port(port_dev); > if (status < 0) > goto loop; > > mutex_unlock(hcd->address0_mutex); > + usb_unlock_port(port_dev); > + retry_locked = false; > > if (udev->quirks & USB_QUIRK_DELAY_INIT) > msleep(2000); > @@ -5372,11 +5375,14 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, > > loop_disable: > hub_port_disable(hub, port1, 1); > - mutex_lock(hcd->address0_mutex); > loop: > usb_ep0_reinit(udev); > release_devnum(udev); > hub_free_dev(udev); > + if (retry_locked) { > + mutex_unlock(hcd->address0_mutex); > + usb_unlock_port(port_dev); > + } > usb_put_dev(udev); > if ((status == -ENOTCONN) || (status == -ENOTSUPP)) > break; > @@ -5399,8 +5405,6 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, > } > > done: > - mutex_unlock(hcd->address0_mutex); > - > hub_port_disable(hub, port1, 1); > if (hcd->driver->relinquish_port && !hub->hdev->parent) { > if (status != -ENOTCONN && status != -ENODEV) Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland