Re: [PATCH v5 1/3] driver core: add device_enumeration_failure_notify() helper
From: Akshay Gujar
Date: Fri Jul 24 2026 - 18:24:19 EST
On Fri, Jul 17, 2026 at 12:40:43PM +0000, Greg KH wrote:
> > Hotpluggable buses may detect that a device is physically present,
> > but enumeration can fail early due to protocol-level errors. Such
> > failures are currently only visible via kernel log messages, with no
> > structured notification to userspace.
> >
> > Introduce device_enumeration_failure_notify(), a helper in the driver
> > core that emits a KOBJ_CHANGE uevent with
> >
> > DEVICE_ENUMERATION_FAILURE=<dev_name>
> >
> > This helper is intended for use by bus drivers such as USB and PCI.
> >
> > Signed-off-by: Akshay Gujar <Akshay.Gujar@xxxxxxxxxx>
> > ---
> > drivers/base/core.c | 44 ++++++++++++++++++++++++++++++++++++++++++
> > include/linux/device.h | 2 ++
> > 2 files changed, 46 insertions(+)
> >
> > diff --git a/drivers/base/core.c b/drivers/base/core.c
> > index 4d026682944f2..6694a0c30f61b 100644
> > --- a/drivers/base/core.c
> > +++ b/drivers/base/core.c
> > @@ -3830,6 +3830,50 @@ int device_add(struct device *dev)
> > }
> > EXPORT_SYMBOL_GPL(device_add);
> >
> > +/**
> > + * device_enumeration_failure_notify - notify userspace of enumeration failure
> > + * @dev: device that failed to enumerate a connected child
> > + *
> > + * Emit a KOBJ_CHANGE uevent with
> > + * DEVICE_ENUMERATION_FAILURE=<dev_name>.
> > + *
> > + * If @dev has not yet emitted its ADD uevent, the event may be sent
> > + * from the parent device instead.
> > + *
> > + * The caller must hold a reference to @dev.
> > + *
> > + * See Documentation/ABI/testing/sysfs-uevent for more details.
> > + */
> > +void device_enumeration_failure_notify(struct device *dev)
> > +{
> > + char *envp[2] = { NULL, NULL };
> > + struct device *uevent_dev;
> > +
> > + if (!dev)
> > + return;
> > +
> > + /*
> > + * If enumeration fails before @dev has emitted its ADD uevent, the
> > + * device may still be in an early state (e.g. without a bus or class
> > + * assigned). Emit the event from the parent device instead, while
> > + * including DEVICE_ENUMERATION_FAILURE=<dev_name>.
> > + *
> > + * The caller holds a reference to @dev, so dev->parent remains valid.
> > + */
> > + uevent_dev = dev->kobj.state_add_uevent_sent ? dev : dev->parent;
>
> This is going to confuse people, if events show up for a parent device,
> and for an actual device, in different busses/times, right? Why
> shouldn't the device itself always just be the one as it's up to the bus
> to determine when to call this?
>
> For your USB example, is the uevent sent state ever hit yet when you
> want to emit this?
No. Passing &port_dev->dev directly drops the uevent in kobject_uevent_env()
because dev_uevent_filter() returns 0 for usb_port devices (no bus/class).
The event must therefore be emitted from the port's registered parent,
the hub's usb_interface device (port_dev->dev.parent).
To keep the helper simple, v6 will explicitly take the emitting device
and the failed identifier, removing all internal fallback logic:
int device_enumeration_failure_notify(struct device *dev,
const char *failed_id);
USB caller in hub_port_connect():
device_enumeration_failure_notify(port_dev->dev.parent,
dev_name(&port_dev->dev));
> > + if (!uevent_dev)
> > + return;
>
> How can that happen? A device will ALWAYS have a valid parent pointer.
With the fallback removed there is no parent handling in the helper
at all, so this check will be gone in v6.
> > +
> > + envp[0] = kasprintf(GFP_KERNEL, "DEVICE_ENUMERATION_FAILURE=%s",
> > + dev_name(dev));
> > + if (!envp[0])
> > + return;
> > +
> > + kobject_uevent_env(&uevent_dev->kobj, KOBJ_CHANGE, envp);
>
> You loose this error if something went wrong?
Will return the error to the caller.
ret = kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
kfree(envp[0]);
return ret;
Will send v6 with these changes.
Thanks,
Akshay