On Mo, 2018-11-19 at 16:52 +0100, Nicolas Saenz Julienne wrote: > > > > /* USB 2.0 spec Section 11.24.2.3 */ > > > @@ -1268,6 +1288,7 @@ static void hub_quiesce(struct usb_hub *hub, > > > enum hub_quiescing_type type) > > > } > > > > > > /* Stop hub_wq and related activity */ > > > + del_timer_sync(&hub->irq_urb_retry); > > > > That is a race condition. You kill the timer here, but the URB may > > still be in flight. And if it fails, it will restart the error > > handler. You have to introduce a flag or poison the URB. > > I see, wouldn't checking "hub->quiescing" in hub_irq()'s submit error > path do the work? Something the likes of this: > > @@ -713,8 +729,12 @@ static void hub_irq(struct urb *urb) > return; > > status = usb_submit_urb(hub->urb, GFP_ATOMIC); > - if (status != 0 && status != -ENODEV && status != -EPERM) > + if (status != 0 && status != -ENODEV && status != -EPERM && > + status != -ESHUTDOWN && !hub->quiescing) { The problem with doing such things is that the interrupt and the disconnect can run on two different CPUs. Thus if you use a flag you need to make sure they don't race and you need to get memory ordering right. Doable, but not easy. There is a reason URBs can be poisoned. Regards Oliver