Skip to content

Commit e271ed5

Browse files
committed
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
2 parents 2c7e4a2 + 8887abc commit e271ed5

File tree

1 file changed

+12
-4
lines changed

1 file changed

+12
-4
lines changed

drivers/base/power/main.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,13 @@ static int dpm_async_with_cleanup(struct device *dev, void *fn)
637637

638638
static void dpm_async_resume_children(struct device *dev, async_func_t func)
639639
{
640+
/*
641+
* Prevent racing with dpm_clear_async_state() during initial list
642+
* walks in dpm_noirq_resume_devices(), dpm_resume_early(), and
643+
* dpm_resume().
644+
*/
645+
guard(mutex)(&dpm_list_mtx);
646+
640647
/*
641648
* Start processing "async" children of the device unless it's been
642649
* started already for them.
@@ -985,6 +992,8 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
985992
if (!dev->power.is_suspended)
986993
goto Complete;
987994

995+
dev->power.is_suspended = false;
996+
988997
if (dev->power.direct_complete) {
989998
/*
990999
* 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)
10471056

10481057
End:
10491058
error = dpm_run_callback(callback, dev, state, info);
1050-
dev->power.is_suspended = false;
10511059

10521060
device_unlock(dev);
10531061
dpm_watchdog_clear(&wd);
@@ -1451,7 +1459,7 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
14511459
* Move all devices to the target list to resume them
14521460
* properly.
14531461
*/
1454-
list_splice(&dpm_late_early_list, &dpm_noirq_list);
1462+
list_splice_init(&dpm_late_early_list, &dpm_noirq_list);
14551463
break;
14561464
}
14571465
}
@@ -1653,7 +1661,7 @@ int dpm_suspend_late(pm_message_t state)
16531661
* Move all devices to the target list to resume them
16541662
* properly.
16551663
*/
1656-
list_splice(&dpm_suspended_list, &dpm_late_early_list);
1664+
list_splice_init(&dpm_suspended_list, &dpm_late_early_list);
16571665
break;
16581666
}
16591667
}
@@ -1946,7 +1954,7 @@ int dpm_suspend(pm_message_t state)
19461954
* Move all devices to the target list to resume them
19471955
* properly.
19481956
*/
1949-
list_splice(&dpm_prepared_list, &dpm_suspended_list);
1957+
list_splice_init(&dpm_prepared_list, &dpm_suspended_list);
19501958
break;
19511959
}
19521960
}

0 commit comments

Comments
 (0)