On 10/13/25 12:58 PM, Rafael J. Wysocki wrote:
On Mon, Oct 13, 2025 at 7:48 PM Mario Limonciello (AMD)
<[email protected]> wrote:

From: Mario Limonciello <[email protected]>

After the hibernation snapshot is created all devices will have
their thaw() callback called before the next stage.  For the most
common scenarios of hibernation this is not necessary because the
device will be powered off anyway.

And how exactly is the image going to be saved?

It is only in memory when the "thaw" callbacks are invoked.

Ah; right.

I suppose one option would be to thaw "just" the backing device, but this could turn into a relatively complex mess because it would have relationships (parent/child or device link) to other devices that need to thaw too then.


If the hibernation snapshot was successfully created skip thawing
devices until it's needed for userspace created hibernation image
or hybrid sleep. To accomplish this use PMSG_INVALID in
hibernation_snapshot() and set the dpm functions to skip running.

Signed-off-by: Mario Limonciello <[email protected]>
---
  drivers/base/power/main.c |  6 ++++++
  kernel/power/hibernate.c  | 13 ++++++++++---
  kernel/power/user.c       |  3 +++
  3 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 8179fd53171dc..58f5270a173e8 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1143,6 +1143,9 @@ void dpm_resume(pm_message_t state)
         struct device *dev;
         ktime_t starttime = ktime_get();

+       if (state.event == PM_EVENT_INVALID)
+               return;
+
         trace_suspend_resume(TPS("dpm_resume"), state.event, true);

         pm_transition = state;
@@ -1245,6 +1248,9 @@ void dpm_complete(pm_message_t state)
  {
         struct list_head list;

+       if (state.event == PM_EVENT_INVALID)
+               return;
+
         trace_suspend_resume(TPS("dpm_complete"), state.event, true);

         INIT_LIST_HEAD(&list);
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index aadf82f57e868..7af2e392c574a 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -480,13 +480,14 @@ int hibernation_snapshot(int platform_mode)
         if (error || !in_suspend)
                 swsusp_free();

-       msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE;
+       msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_INVALID) : PMSG_RESTORE;
         dpm_resume(msg);

-       if (error || !in_suspend)
+       if (error || !in_suspend) {
                 pm_restore_gfp_mask();
+               console_resume_all();
+       }

-       console_resume_all();
         dpm_complete(msg);

   Close:
@@ -707,7 +708,13 @@ static void power_down(void)

  #ifdef CONFIG_SUSPEND
         if (hibernation_mode == HIBERNATION_SUSPEND) {
+               /* recover from hibernation_snapshot() */
+               dpm_resume(PMSG_THAW);
+               console_resume_all();
+               dpm_complete(PMSG_THAW);
                 pm_restore_gfp_mask();
+
+               /* run suspend sequence */
                 error = suspend_devices_and_enter(mem_sleep_current);
                 if (!error)
                         goto exit;
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 3f9e3efb9f6e7..d70c963b1ba88 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -310,6 +310,9 @@ static long snapshot_ioctl(struct file *filp, unsigned int 
cmd,
                 pm_restore_gfp_mask();
                 error = hibernation_snapshot(data->platform_support);
                 if (!error) {
+                       dpm_resume(PMSG_THAW);
+                       console_resume_all();
+                       dpm_complete(PMSG_THAW);
                         error = put_user(in_suspend, (int __user *)arg);
                         data->ready = !freezer_test_done && !error;
                         freezer_test_done = false;
--
2.43.0


Reply via email to