[PATCH v3 2/2] usb: gadget: goku_udc: fix kobject warning on probe failure
From: Cheng Lingfei
Date: Wed Aug 26 2026 - 05:16:42 EST
goku_probe() calls goku_remove() when hardware initialization fails, but
the gadget device is initialized only near the end of probe. As a result,
goku_remove() calls usb_del_gadget_udc(), which drops a reference to an
uninitialized gadget device and triggers a kobject warning.
Initialize the gadget device immediately after allocating the controller,
but add it only after all hardware resources have been acquired. Track the
gadget registration state so goku_remove() can safely clean up both partial
probe state and a fully initialized device.
Use the split gadget removal API and drop the final gadget reference only
after all hardware resources have been released. Obtain the controller from
the embedded gadget device in the release callback because driver data is
set on the PCI device rather than the gadget device.
Fixes: 3301c215a2bb ("USB: UDC: Expand device model API interface")
Reported-by: syzbot+06ec7624018233e17113@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=06ec7624018233e17113
Tested-by: syzbot+06ec7624018233e17113@xxxxxxxxxxxxxxxxxxxxxxxxx
Assisted-by: Codex:gpt-5.6
Signed-off-by: Cheng Lingfei <chenglingfei@xxxxxxxxxxx>
---
drivers/usb/gadget/udc/goku_udc.c | 28 ++++++++++++++--------------
drivers/usb/gadget/udc/goku_udc.h | 3 ++-
2 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c
index 5ad8633f522b..615cc6b8f354 100644
--- a/drivers/usb/gadget/udc/goku_udc.c
+++ b/drivers/usb/gadget/udc/goku_udc.c
@@ -20,6 +20,7 @@
// #define VERBOSE /* extra debug messages (success too) */
// #define USB_TRACE /* packet-level success messages */
+#include <linux/container_of.h>
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -1726,7 +1727,7 @@ static irqreturn_t goku_irq(int irq, void *_dev)
static void gadget_release(struct device *_dev)
{
- struct goku_udc *dev = dev_get_drvdata(_dev);
+ struct goku_udc *dev = container_of(_dev, struct goku_udc, gadget.dev);
kfree(dev);
}
@@ -1739,7 +1740,8 @@ static void goku_remove(struct pci_dev *pdev)
DBG(dev, "%s\n", __func__);
- usb_del_gadget_udc(&dev->gadget);
+ if (dev->added)
+ usb_del_gadget(&dev->gadget);
BUG_ON(dev->driver);
@@ -1759,6 +1761,8 @@ static void goku_remove(struct pci_dev *pdev)
dev->regs = NULL;
INFO(dev, "unbind\n");
+
+ usb_put_gadget(&dev->gadget);
}
/* wrap this driver around the specified pci device, but
@@ -1774,16 +1778,13 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (!pdev->irq) {
printk(KERN_ERR "Check PCI %s IRQ setup!\n", pci_name(pdev));
- retval = -ENODEV;
- goto err;
+ return -ENODEV;
}
/* alloc, and start init */
dev = kzalloc_obj(*dev);
- if (!dev) {
- retval = -ENOMEM;
- goto err;
- }
+ if (!dev)
+ return -ENOMEM;
pci_set_drvdata(pdev, dev);
spin_lock_init(&dev->lock);
@@ -1794,6 +1795,8 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* the "gadget" abstracts/virtualizes the controller */
dev->gadget.name = driver_name;
+ usb_initialize_gadget(&pdev->dev, &dev->gadget, gadget_release);
+
/* now all the pci goodies ... */
retval = pci_enable_device(pdev);
if (retval < 0) {
@@ -1836,19 +1839,16 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (use_dma)
pci_set_master(pdev);
- retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
- gadget_release);
+ retval = usb_add_gadget(&dev->gadget);
if (retval)
goto err;
+ dev->added = 1;
goku_debugfs_create(dev);
return 0;
err:
- if (dev)
- goku_remove (pdev);
- /* gadget_release is not registered yet, kfree explicitly */
- kfree(dev);
+ goku_remove(pdev);
return retval;
}
diff --git a/drivers/usb/gadget/udc/goku_udc.h b/drivers/usb/gadget/udc/goku_udc.h
index 4885b1dae928..ed39e7080536 100644
--- a/drivers/usb/gadget/udc/goku_udc.h
+++ b/drivers/usb/gadget/udc/goku_udc.h
@@ -247,7 +247,8 @@ struct goku_udc {
got_region:1,
req_config:1,
configured:1,
- enabled:1;
+ enabled:1,
+ added:1;
#ifdef CONFIG_USB_GADGET_DEBUG_FS
struct dentry *debugfs_root;
--
2.53.0