Re: [PATCH] USB: Skip resume if pm_runtime_set_active() fails

From: Alan Stern
Date: Sun Feb 23 2025 - 21:15:14 EST


On Mon, Feb 24, 2025 at 09:33:25AM +0800, Ma Ke wrote:
> A race condition occurs during system suspend if interrupted between
> usb_suspend() and the parent device’s PM suspend (e.g., a power
> domain).

I don't understand exactly what you mean. Is this supposed to be a
scenario where a USB device is suspended during a system sleep
transition, but before the device's parent can be suspended, the
sleep transition is aborted?

> This triggers PM resume workflows (via usb_resume()), but if
> parent device is already runtime-suspended, pm_runtime_set_active()
> fails.

In other words, before the device can be resumed the parent goes into
runtime suspend? I don't understand how that could happen. The PM core
is careful to make sure that unwanted runtime PM changes don't occur
during system sleep/resume transitions.

And if somehow this can happen, doesn't that indicate the real problem
lies in the PM core? After all, why shouldn't the same sort of race
condition affect a device on any bus, not just USB devices?

> Subsequent operations like pm_runtime_enable() and interface
> unbinding may leave the USB device in an inconsistent state or trigger
> unintended behavior.
>
> Found by code review.
>
> Cc: stable@xxxxxxxxxxxxxxx
> Fixes: 98d9a82e5f75 ("USB: cleanup the handling of the PM complete call")
> Signed-off-by: Ma Ke <make24@xxxxxxxxxxx>
> ---
> drivers/usb/core/driver.c | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
> index 460d4dde5994..7478fcc11fd4 100644
> --- a/drivers/usb/core/driver.c
> +++ b/drivers/usb/core/driver.c
> @@ -1624,11 +1624,17 @@ int usb_resume(struct device *dev, pm_message_t msg)
> status = usb_resume_both(udev, msg);
> if (status == 0) {
> pm_runtime_disable(dev);
> - pm_runtime_set_active(dev);
> + status = pm_runtime_set_active(dev);
> + if (status) {
> + pm_runtime_enable(dev);

The patch description says that pm_runtime_enable() following an
unsuccessful pm_runtime_set_active() may trigger unintended behavior.
So why does the patch do it?

Alan Stern

> + goto out;
> + }
> +
> pm_runtime_enable(dev);
> unbind_marked_interfaces(udev);
> }
>
> +out:
> /* Avoid PM error messages for devices disconnected while suspended
> * as we'll display regular disconnect messages just a bit later.
> */
> --
> 2.25.1
>