PM: hibernate: Freeze kernel threads after image preallocation

Commit 783c810984 ("PM: hibernate: call preallocate_image() after freeze
prepare") moved hibernate_preallocate_memory() after dpm_prepare() so
that device drivers have the opportunity to release pinned/unswappable
memory during their ->prepare() callback before memory is preallocated
for the snapshot image.

However, that commit also placed hibernate_preallocate_memory() after
freeze_kernel_threads(). While it was assumed during review that swap
I/O submitted via submit_bio() is synchronous and would not depend on
frozen kernel threads, this does not hold in practice. Calling
hibernate_preallocate_memory() with kernel threads frozen leads to
intermittent deadlocks during hibernation.

Inside hibernate_preallocate_memory(), shrink_all_memory() is invoked with
.may_writepage = 1 and .may_swap = 1 to aggressively reclaim and swap out
pages. Any writeback or swap I/O that relies on freezable kernel threads,
block device helpers, or WQ_FREEZABLE workqueues (such as those in storage
drivers, device mapper, or filesystems) deadlocks waiting on tasks that
are stuck in the refrigerator.

Fix this by reordering hibernation_snapshot():
 1. Call dpm_prepare(PMSG_FREEZE) first, allowing device drivers to
    release pinned resources while kernel threads are still active.
 2. Call hibernate_preallocate_memory() second, performing page
    reclaim and swapout while storage layers, workqueues, and kernel
    threads are alive.
 3. Call freeze_kernel_threads() third, only after all memory
    preallocation and swap I/O have completed.

Additionally, restore the call to swsusp_free() in the cleanup path so
that preallocated image memory is properly freed if freeze_kernel_threads()
fails or if TEST_FREEZER is enabled.

Fixes: 783c810984 ("PM: hibernate: call preallocate_image() after freeze prepare")
Signed-off-by: Florian Schmaus <flo@geekplace.eu>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Tested-by: Matthew Leach <matthew.leach@collabora.com>
Reviewed-by: Matthew Leach <matthew.leach@collabora.com>
Link: https://patch.msgid.link/20260920-fix-hibernation-v1-1-f9940c2d7d7f@geekplace.eu
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Florian Schmaus 2026-09-20 16:35:25 +02:00 committed by Rafael J. Wysocki
parent 93f51579e7
commit 41112a787f

View File

@ -408,9 +408,18 @@ int hibernation_snapshot(int platform_mode)
if (error)
goto Close;
error = dpm_prepare(PMSG_FREEZE);
if (error)
goto Complete;
/* Preallocate image memory before freezing kernel threads and shutting down devices. */
error = hibernate_preallocate_memory();
if (error)
goto Complete;
error = freeze_kernel_threads();
if (error)
goto Close;
goto Cleanup;
if (hibernation_test(TEST_FREEZER)) {
@ -422,15 +431,6 @@ int hibernation_snapshot(int platform_mode)
goto Thaw;
}
error = dpm_prepare(PMSG_FREEZE);
if (error)
goto Complete;
/* Preallocate image memory before shutting down devices. */
error = hibernate_preallocate_memory();
if (error)
goto Complete;
console_suspend_all();
pm_restrict_gfp_mask();
@ -464,10 +464,12 @@ int hibernation_snapshot(int platform_mode)
platform_end(platform_mode);
return error;
Complete:
dpm_complete(PMSG_RECOVER);
Thaw:
thaw_kernel_threads();
Cleanup:
swsusp_free();
Complete:
dpm_complete(PMSG_RECOVER);
goto Close;
}