Message ID | 20230324090955.462581-1-u.kleine-koenig@pengutronix.de (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | ACPI: bus: Only call notify for a completely bound ACPI device | expand |
Hello, On Fri, Mar 24, 2023 at 10:09:55AM +0100, Uwe Kleine-König wrote: > Commit d6fb6ee1820c ("ACPI: bus: Drop driver member of struct > acpi_device") removed acpi_device::driver in favour of struct > acpi_device::dev.driver. > > However there is a problem: While the two pointers are equivalent after > the device is completely probed, there is a small time frame where > acpi_device::dev->driver is already set but acpi_device::driver wasn't. > > The function acpi_bus_notify() used to have a check for > acpi_device::driver that was changed to a check for adev->dev.driver in > Commit d6fb6ee1820c. > > Pierre Asselin reports that starting with above change his laptop > crashed during boot when on AC power. That's because acpi_bus_notify() > is called in that small time frame (triggered by acpi_ac_add()) which > results in a call to acpi_ac_notify while this function isn't ready yet. > > So in acpi_bus_notify() check for the device being bound (which becomes > true only after the acpi probe call succeeds) instead of for > acpi_device::dev.driver. > > Note that usually you have to hold the device lock to call > device_is_bound(). I don't think this is the case here, so there likely > is a race condition. The problem might be that the driver unbinds after > the check but before adev->dev.driver is evaluated. However this race > already existed before commit d6fb6ee1820c, so the change here is a net > improvement even though it might not result in a completely correct > handling. > > A similar check in the acpi sysfs code is also converted. This is less > critical as it happens in code that is run when a sysfs file is > accessed. That shouldn't happen for a device that isn't bound. > > Fixes: d6fb6ee1820c ("ACPI: bus: Drop driver member of struct acpi_device") > Reported-by: Pierre Asselin <pa@panix.com> > Link: https://lore.kernel.org/linux-acpi/9f6cba7a8a57e5a687c934e8e406e28c.squirrel@mail.panix.com > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> > --- > drivers/acpi/bus.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c > index 9531dd0fef50..a5a8f82981ce 100644 > --- a/drivers/acpi/bus.c > +++ b/drivers/acpi/bus.c > @@ -518,7 +518,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) > if (!adev) > goto err; > > - if (adev->dev.driver) { > + if (device_is_bound(&adev->dev)) { > struct acpi_driver *driver = to_acpi_driver(adev->dev.driver); > > if (driver && driver->ops.notify && > there is a hunk that I failed to add to the commit: diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index 0fbfbaa8d8e3..2ee756d68052 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c @@ -376,7 +376,7 @@ eject_store(struct device *d, struct device_attribute *attr, return -EINVAL; if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled) - && !d->driver) + && !device_is_bound(d)) return -ENODEV; status = acpi_get_type(acpi_device->handle, ¬_used); Rafael sait in the thread where Pierre reported the problem that he has a different fix in mind. So I guess it's not worth to send a v2. Best regards Uwe
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 9531dd0fef50..a5a8f82981ce 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -518,7 +518,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) if (!adev) goto err; - if (adev->dev.driver) { + if (device_is_bound(&adev->dev)) { struct acpi_driver *driver = to_acpi_driver(adev->dev.driver); if (driver && driver->ops.notify &&
Commit d6fb6ee1820c ("ACPI: bus: Drop driver member of struct acpi_device") removed acpi_device::driver in favour of struct acpi_device::dev.driver. However there is a problem: While the two pointers are equivalent after the device is completely probed, there is a small time frame where acpi_device::dev->driver is already set but acpi_device::driver wasn't. The function acpi_bus_notify() used to have a check for acpi_device::driver that was changed to a check for adev->dev.driver in Commit d6fb6ee1820c. Pierre Asselin reports that starting with above change his laptop crashed during boot when on AC power. That's because acpi_bus_notify() is called in that small time frame (triggered by acpi_ac_add()) which results in a call to acpi_ac_notify while this function isn't ready yet. So in acpi_bus_notify() check for the device being bound (which becomes true only after the acpi probe call succeeds) instead of for acpi_device::dev.driver. Note that usually you have to hold the device lock to call device_is_bound(). I don't think this is the case here, so there likely is a race condition. The problem might be that the driver unbinds after the check but before adev->dev.driver is evaluated. However this race already existed before commit d6fb6ee1820c, so the change here is a net improvement even though it might not result in a completely correct handling. A similar check in the acpi sysfs code is also converted. This is less critical as it happens in code that is run when a sysfs file is accessed. That shouldn't happen for a device that isn't bound. Fixes: d6fb6ee1820c ("ACPI: bus: Drop driver member of struct acpi_device") Reported-by: Pierre Asselin <pa@panix.com> Link: https://lore.kernel.org/linux-acpi/9f6cba7a8a57e5a687c934e8e406e28c.squirrel@mail.panix.com Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> --- drivers/acpi/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) base-commit: fe15c26ee26efa11741a7b632e9f23b01aca4cc6