In the soft disconnect scenarios, the USB connection will be lost momentarily, so the proper gadget state should be reflected during the time the connection is unavailable. Add a flush_work() call, to ensure that gadget->work is completed before continuing with the UDC unbind sequence. Since usb_gadget_set_state() queues work to a workqueue, depending on when the queue is scheduled, this avoids a possible use after freed scenario as the USB gadget will most likely be freed shortly after the UDC driver is unbounded. Signed-off-by: Wesley Cheng <quic_wcheng@xxxxxxxxxxx> --- drivers/usb/gadget/udc/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 4b3d5075621a..7e401cb5a265 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -775,8 +775,10 @@ static int usb_gadget_disconnect_locked(struct usb_gadget *gadget) } ret = gadget->ops->pullup(gadget, 0); - if (!ret) + if (!ret) { gadget->connected = 0; + usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); + } mutex_lock(&udc_lock); if (gadget->udc->driver) @@ -1669,6 +1671,7 @@ static void gadget_unbind_driver(struct device *dev) synchronize_irq(gadget->irq); mutex_unlock(&udc->connect_lock); + flush_work(&gadget->work); udc->driver->unbind(gadget); mutex_lock(&udc->connect_lock);