aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-06-05 12:47:12 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2025-06-05 12:47:12 -0700
commite271ed52b344ac02d4581286961d0c40acc54c03 (patch)
tree2545a1517c0c9732ea0ba512a6a48015a114ebff /drivers
parentMerge tag 'net-6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (diff)
parentPM: sleep: Add locking to dpm_async_resume_children() (diff)
downloadlinux-rng-e271ed52b344ac02d4581286961d0c40acc54c03.tar.xz
linux-rng-e271ed52b344ac02d4581286961d0c40acc54c03.zip
Merge tag 'pm-6.16-rc1-3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management fixes from Rafael Wysocki: "Fix three issues introduced into device suspend/resume error paths in the PM core by some of the recent updates. First off, replace list_splice() with list_splice_init() in three places in device suspend error paths to avoid attempting to use an uninitialized list head going forward. Second, rearrange device_resume() to avoid leaking the power.is_suspended device PM flag to the next system suspend/resume cycle where it can confuse rolling back after an error or early wakeup. Finally, add synchronization to dpm_async_resume_children() to avoid resetting the async state mistakenly for devices whose resume callbacks have already been queued up for asynchronous execution in the given device resume phase, which fortunately can happen only if the preceding system suspend transition has been aborted" * tag 'pm-6.16-rc1-3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: PM: sleep: Add locking to dpm_async_resume_children() PM: sleep: Fix power.is_suspended cleanup for direct-complete devices PM: sleep: Fix list splicing in device suspend error paths
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/power/main.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 19fd55b8ac77..77c7a99f0870 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -638,6 +638,13 @@ static int dpm_async_with_cleanup(struct device *dev, void *fn)
static void dpm_async_resume_children(struct device *dev, async_func_t func)
{
/*
+ * Prevent racing with dpm_clear_async_state() during initial list
+ * walks in dpm_noirq_resume_devices(), dpm_resume_early(), and
+ * dpm_resume().
+ */
+ guard(mutex)(&dpm_list_mtx);
+
+ /*
* Start processing "async" children of the device unless it's been
* started already for them.
*
@@ -985,6 +992,8 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
if (!dev->power.is_suspended)
goto Complete;
+ dev->power.is_suspended = false;
+
if (dev->power.direct_complete) {
/*
* Allow new children to be added under the device after this
@@ -1047,7 +1056,6 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
End:
error = dpm_run_callback(callback, dev, state, info);
- dev->power.is_suspended = false;
device_unlock(dev);
dpm_watchdog_clear(&wd);
@@ -1451,7 +1459,7 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
* Move all devices to the target list to resume them
* properly.
*/
- list_splice(&dpm_late_early_list, &dpm_noirq_list);
+ list_splice_init(&dpm_late_early_list, &dpm_noirq_list);
break;
}
}
@@ -1653,7 +1661,7 @@ int dpm_suspend_late(pm_message_t state)
* Move all devices to the target list to resume them
* properly.
*/
- list_splice(&dpm_suspended_list, &dpm_late_early_list);
+ list_splice_init(&dpm_suspended_list, &dpm_late_early_list);
break;
}
}
@@ -1946,7 +1954,7 @@ int dpm_suspend(pm_message_t state)
* Move all devices to the target list to resume them
* properly.
*/
- list_splice(&dpm_prepared_list, &dpm_suspended_list);
+ list_splice_init(&dpm_prepared_list, &dpm_suspended_list);
break;
}
}