Re: [PATCH v2 2/2] driver core: bus: Correct API bus_rescan_devices() behavior

From: Zijun Hu
Date: Thu Sep 12 2024 - 20:03:42 EST


On 2024/9/13 07:45, Zijun Hu wrote:
> From: Zijun Hu <quic_zijuhu@xxxxxxxxxxx>
>
> API bus_rescan_devices() should ideally scan drivers for a bus's
> devices as many as possible, but it will really stop scanning for
> remaining devices even if a device encounters inconsequential errors
> such as -EPROBE_DEFER, -ENODEV and -EBUSY, fixed by ignoring such

Scenarios which encounter -EPROBE_DEFER:
- amba_match(), as bus_type @amba_bustype's match(), may return
this error code.
- really_probe() may return this error code if any of a device's
suppliers has no driver bound.
- other functions called by really_probe() to operate device related
hardware resources may potentially return this error code such
as pinctrl_bind_pins().

> inconsequential errors and continue to scan drivers for next device.
>
> By the way, in order to eliminate risk:
> - the API's return value is not changed by recording the first
> error code during scanning which is returned.
> - API device_reprobe()'s existing logic is not changed as well.
>
> Signed-off-by: Zijun Hu <quic_zijuhu@xxxxxxxxxxx>
> ---
> drivers/base/bus.c | 38 +++++++++++++++++++++++++-------------
> 1 file changed, 25 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/base/bus.c b/drivers/base/bus.c
> index 4b5958c5ee7d..fa68acd55bf8 100644
> --- a/drivers/base/bus.c
> +++ b/drivers/base/bus.c
> @@ -58,9 +58,6 @@ static int __must_check bus_rescan_single_device(struct device *dev)
> return ret;
> }
>
> -static int __must_check bus_rescan_devices_helper(struct device *dev,
> - void *data);
> -
> /**
> * bus_to_subsys - Turn a struct bus_type into a struct subsys_private
> *
> @@ -797,15 +794,23 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
> void *data)
> {
> int ret = 0;
> + int *first_error = data;
>
> - if (!dev->driver) {
> - if (dev->parent && dev->bus->need_parent_lock)
> - device_lock(dev->parent);
> - ret = device_attach(dev);
> - if (dev->parent && dev->bus->need_parent_lock)
> - device_unlock(dev->parent);
> - }
> - return ret < 0 ? ret : 0;
> + ret = bus_rescan_single_device(dev);
> +
> + if (ret >= 0)
> + return 0;
> +
> + if (!*first_error)
> + *first_error = ret;
> + /*
> + * Ignore these inconsequential errors and continue to
> + * scan drivers for next device.
> + */
> + if (ret == -EPROBE_DEFER || ret == -ENODEV || ret == -EBUSY)
> + return 0;
> +
> + return ret;
> }
>
> /**
> @@ -818,7 +823,10 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
> */
> int bus_rescan_devices(const struct bus_type *bus)
> {
> - return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);
> + int err = 0;
> +
> + bus_for_each_dev(bus, NULL, &err, bus_rescan_devices_helper);
> + return err;
> }
> EXPORT_SYMBOL_GPL(bus_rescan_devices);
>
> @@ -833,9 +841,13 @@ EXPORT_SYMBOL_GPL(bus_rescan_devices);
> */
> int device_reprobe(struct device *dev)
> {
> + int ret;
> +
> if (dev->driver)
> device_driver_detach(dev);
> - return bus_rescan_devices_helper(dev, NULL);
> +
> + ret = bus_rescan_single_device(dev);
> + return ret < 0 ? ret : 0;
> }
> EXPORT_SYMBOL_GPL(device_reprobe);
>
>