Abusing the kernel's device model, some UDC drivers (including dwc3 and cdns3) register and unregister their gadget structures multiple times. This is strictly forbidden; device structures may not be reused. Commit fac323471df6 ("usb: udc: allow adding and removing the same gadget device") attempted to work around this restriction by zeroing out the memory occupied by a gadget's embedded struct device when the gadget is unregistered. However, it does so at the wrong time, immediately following the call to device_unregister(). At that point there may still be outstanding references to the device, and overwriting its memory is likely to cause trouble. Even worse, if there are no outstanding references then the gadget's memory may have been deallocated, and so gadget must be considered to be a stale pointer when it is passed to memset(). This patch fixes the problem by moving the offending memset to the device's release routine, which gets called only when all references have been dropped. (Actually the call gets moved to the default release routine, renamed from "usb_udc_nop_release" to "usb_udc_zero_release" to indicate that it now zeroes out the memory. This routine is the one used by dwc3 and cdns3; other drivers may not use it.) This doesn't fix the underlying problem. UDC drivers that register their gadgets multiple times should be rewritten to allocate their gadget structures dynamically, using a new one each time. Until that is done, this will at least remove one potential source of errors. On the other hand, the patch may create new errors if the release routine doesn't get called until after the gadget has been re-registered. Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> CC: Roger Quadros <rogerq@xxxxxx> CC: Peter Chen <peter.chen@xxxxxxx> CC: Anton Vasilyev <vasilyev@xxxxxxxxx> CC: Evgeny Novikov <novikov@xxxxxxxxx> CC: Benjamin Herrenschmidt <benh@xxxxxxxxxxxxxxxxxxx> --- drivers/usb/gadget/udc/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) Index: usb-devel/drivers/usb/gadget/udc/core.c =================================================================== --- usb-devel.orig/drivers/usb/gadget/udc/core.c +++ usb-devel/drivers/usb/gadget/udc/core.c @@ -1138,9 +1138,10 @@ static void usb_udc_release(struct devic static const struct attribute_group *usb_udc_attr_groups[]; -static void usb_udc_nop_release(struct device *dev) +static void usb_udc_zero_release(struct device *dev) { dev_vdbg(dev, "%s\n", __func__); + memset(dev, 0, sizeof(*dev)); } /* should be called with udc_lock held */ @@ -1184,7 +1185,7 @@ int usb_add_gadget_udc_release(struct de if (release) gadget->dev.release = release; else - gadget->dev.release = usb_udc_nop_release; + gadget->dev.release = usb_udc_zero_release; device_initialize(&gadget->dev); @@ -1338,7 +1339,6 @@ void usb_del_gadget_udc(struct usb_gadge flush_work(&gadget->work); device_unregister(&udc->dev); device_unregister(&gadget->dev); - memset(&gadget->dev, 0x00, sizeof(gadget->dev)); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc);