* [PATCH v2] usb: gadget: goku_udc: fix kobject warning on probe failure
@ 2026-08-26 8:26 Cheng Lingfei
2026-08-26 8:33 ` Greg Kroah-Hartman
0 siblings, 1 reply; 2+ messages in thread
From: Cheng Lingfei @ 2026-08-26 8:26 UTC (permalink / raw)
To: Greg Kroah-Hartman, Alan Stern, Felipe Balbi, Peter Chen
Cc: linux-usb, linux-kernel, syzbot+06ec7624018233e17113,
Cheng Lingfei
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.
The legacy diagnostic proc entry uses a single global name. This causes a
collision when more than one controller is probed. Replace it with a
per-device debugfs entry.
Fixes: 3301c215a2bb ("USB: UDC: Expand device model API interface")
Reported-by: syzbot+06ec7624018233e17113@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=06ec7624018233e17113
Tested-by: syzbot+06ec7624018233e17113@syzkaller.appspotmail.com
Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://lore.kernel.org/2026082616-glue-atlas-0cfd@gregkh
Assisted-by: Codex:gpt-5.6
Signed-off-by: Cheng Lingfei <chenglingfei@foxmail.com>
---
Changes in v2:
- Replace legacy procfs with per-device debugfs entries.
- Add Assisted-by: tag as requested.
- Link to v1: https://patch.msgid.link/20260826-b4-fix-usb-v1-1-a090b5b3534c@foxmail.com
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: Felipe Balbi <balbi@kernel.org>
To: Alan Stern <stern@rowland.harvard.edu>
To: Peter Chen <peter.chen@nxp.com>
Cc: linux-usb@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
drivers/usb/gadget/udc/goku_udc.c | 74 +++++++++++++++++++++++++--------------
drivers/usb/gadget/udc/goku_udc.h | 8 +++--
2 files changed, 53 insertions(+), 29 deletions(-)
diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c
index ac2a984c2f87..e6941b9d0f6b 100644
--- a/drivers/usb/gadget/udc/goku_udc.c
+++ b/drivers/usb/gadget/udc/goku_udc.c
@@ -20,6 +20,8 @@
// #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>
#include <linux/pci.h>
@@ -30,9 +32,9 @@
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/device.h>
+#include <linux/usb.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/prefetch.h>
@@ -1050,9 +1052,7 @@ static inline const char *dmastr(void)
return "(dma IN)";
}
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-
-static const char proc_node_name [] = "driver/udc";
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
#define FOURBITS "%s%s%s%s"
#define EIGHTBITS FOURBITS FOURBITS
@@ -1134,7 +1134,7 @@ static const char *udc_ep_status(u32 status)
return "?";
}
-static int udc_proc_read(struct seq_file *m, void *v)
+static int goku_debugfs_show(struct seq_file *m, void *v)
{
struct goku_udc *dev = m->private;
struct goku_udc_regs __iomem *regs = dev->regs;
@@ -1246,7 +1246,33 @@ static int udc_proc_read(struct seq_file *m, void *v)
local_irq_restore(flags);
return 0;
}
-#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+DEFINE_SHOW_ATTRIBUTE(goku_debugfs);
+
+static void goku_debugfs_create(struct goku_udc *dev)
+{
+ dev->debugfs_root =
+ debugfs_create_dir(dev_name(&dev->pdev->dev), usb_debug_root);
+ debugfs_create_file("goku_udc_state", 0400, dev->debugfs_root, dev,
+ &goku_debugfs_fops);
+}
+
+static void goku_debugfs_remove(struct goku_udc *dev)
+{
+ debugfs_remove_recursive(dev->debugfs_root);
+ dev->debugfs_root = NULL;
+}
+
+#else
+
+static inline void goku_debugfs_create(struct goku_udc *dev)
+{
+}
+
+static inline void goku_debugfs_remove(struct goku_udc *dev)
+{
+}
+
+#endif /* CONFIG_USB_GADGET_DEBUG_FS */
/*-------------------------------------------------------------------------*/
@@ -1701,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);
}
@@ -1714,13 +1740,12 @@ 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);
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- remove_proc_entry(proc_node_name, NULL);
-#endif
+ goku_debugfs_remove(dev);
if (dev->regs)
udc_reset(dev);
if (dev->got_irq)
@@ -1736,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
@@ -1751,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);
@@ -1771,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) {
@@ -1814,22 +1840,16 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_master(pdev);
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- proc_create_single_data(proc_node_name, 0, NULL, udc_proc_read, dev);
-#endif
-
- 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 70023d401079..ed39e7080536 100644
--- a/drivers/usb/gadget/udc/goku_udc.h
+++ b/drivers/usb/gadget/udc/goku_udc.h
@@ -247,7 +247,12 @@ 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;
+#endif
/* pci state used to access those endpoints */
struct pci_dev *pdev;
@@ -286,4 +291,3 @@ struct goku_udc {
xprintk(dev , KERN_WARNING , fmt , ## args)
#define INFO(dev,fmt,args...) \
xprintk(dev , KERN_INFO , fmt , ## args)
-
---
base-commit: 3aa1dcaa4f6f5ae08936491e08bd456f331f2d40
change-id: 20260826-b4-fix-usb-c1a4f0505d8c
Best regards,
--
Cheng Lingfei <chenglingfei@foxmail.com>
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH v2] usb: gadget: goku_udc: fix kobject warning on probe failure
2026-08-26 8:26 [PATCH v2] usb: gadget: goku_udc: fix kobject warning on probe failure Cheng Lingfei
@ 2026-08-26 8:33 ` Greg Kroah-Hartman
0 siblings, 0 replies; 2+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-26 8:33 UTC (permalink / raw)
To: Cheng Lingfei
Cc: Alan Stern, Felipe Balbi, Peter Chen, linux-usb, linux-kernel,
syzbot+06ec7624018233e17113
On Wed, Aug 26, 2026 at 04:26:47PM +0800, Cheng Lingfei wrote:
> 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.
>
> The legacy diagnostic proc entry uses a single global name. This causes a
> collision when more than one controller is probed. Replace it with a
> per-device debugfs entry.
>
> Fixes: 3301c215a2bb ("USB: UDC: Expand device model API interface")
> Reported-by: syzbot+06ec7624018233e17113@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=06ec7624018233e17113
> Tested-by: syzbot+06ec7624018233e17113@syzkaller.appspotmail.com
> Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Link: https://lore.kernel.org/2026082616-glue-atlas-0cfd@gregkh
> Assisted-by: Codex:gpt-5.6
> Signed-off-by: Cheng Lingfei <chenglingfei@foxmail.com>
> ---
> Changes in v2:
> - Replace legacy procfs with per-device debugfs entries.
debugfs changes should be a separate change, please make this a patch
series.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-08-26 8:33 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-26 8:26 [PATCH v2] usb: gadget: goku_udc: fix kobject warning on probe failure Cheng Lingfei
2026-08-26 8:33 ` Greg Kroah-Hartman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox