[PATCH] PM: hibernate: Freeze kernel threads after image preallocation

Florian Schmaus via B4 Relay posted 1 patch 4 days, 6 hours ago
kernel/power/hibernate.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
[PATCH] PM: hibernate: Freeze kernel threads after image preallocation
Posted by Florian Schmaus via B4 Relay 4 days, 6 hours ago
From: Florian Schmaus <flo@geekplace.eu>

Commit 783c81098445 ("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: 783c81098445 ("PM: hibernate: call preallocate_image() after freeze prepare")
Signed-off-by: Florian Schmaus <flo@geekplace.eu>
---
During the review of commit 783c81098445 ("PM: hibernate: call
preallocate_image() after freeze prepare") [1], concerns were raised
regarding whether memory reclaim and swap I/O could deadlock if kernel
threads were already frozen.

At the time, it was thought that pageout to swap would not depend on
frozen threads. However, on Linux 7.2, I ran into reliable issues with
suspend-to-disk hanging during hibernation. Reordering the sequence so
that kernel threads are frozen after image preallocation (as done in
this patch) fixes the issue for me.

This patch restores the ordering where kernel threads are frozen only after
memory preallocation and swap I/O have completed, while keeping the
benefit of calling dpm_prepare() beforehand so drivers can release pinned
pages.

[1] https://patch.msgid.link/20260403-hibernation-fixes-v3-1-31bc9fa3ba2d@collabora.com
---
 kernel/power/hibernate.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index d2479c69d71a..c13f68ab7f6e 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -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;
 }
 

---
base-commit: 40288c9206c17eb66a603262e06a58d300d0f279
change-id: 20260915-fix-hibernation-aad94ce17506

Best regards,
--  
Florian Schmaus <flo@geekplace.eu>
Re: [PATCH] PM: hibernate: Freeze kernel threads after image preallocation
Posted by Matthew Leach 2 days, 11 hours ago
Hi Florian,

Florian Schmaus via B4 Relay <devnull+flo.geekplace.eu@kernel.org> writes:

> From: Florian Schmaus <flo@geekplace.eu>

[...]

> Fixes: 783c81098445 ("PM: hibernate: call preallocate_image() after freeze prepare")
> Signed-off-by: Florian Schmaus <flo@geekplace.eu>
>

Thanks for the fix, and sorry for the breakage. I've tested this on top
of 7.2 and the original issue my patch addressed remains fixed. I wasn't
able to reproduce the deadlock under high memory-pressure locally, so I
can't confirm that side of it.

Tested-by: Matthew Leach <matthew.leach@collabora.com>
Reviewed-by: Matthew Leach <matthew.leach@collabora.com>
-- 
Matt
Re: [PATCH] PM: hibernate: Freeze kernel threads after image preallocation
Posted by Rafael J. Wysocki (Intel) 2 days, 1 hour ago
On Tue, Sep 22, 2026 at 11:17 AM Matthew Leach
<matthew.leach@collabora.com> wrote:
>
> Hi Florian,
>
> Florian Schmaus via B4 Relay <devnull+flo.geekplace.eu@kernel.org> writes:
>
> > From: Florian Schmaus <flo@geekplace.eu>
>
> [...]
>
> > Fixes: 783c81098445 ("PM: hibernate: call preallocate_image() after freeze prepare")
> > Signed-off-by: Florian Schmaus <flo@geekplace.eu>
> >
>
> Thanks for the fix, and sorry for the breakage. I've tested this on top
> of 7.2 and the original issue my patch addressed remains fixed. I wasn't
> able to reproduce the deadlock under high memory-pressure locally, so I
> can't confirm that side of it.
>
> Tested-by: Matthew Leach <matthew.leach@collabora.com>
> Reviewed-by: Matthew Leach <matthew.leach@collabora.com>

Applied as 7.3-rc material, thanks!
Re: [PATCH] PM: hibernate: Freeze kernel threads after image preallocation
Posted by Thorsten Leemhuis 2 days, 15 hours ago
On 9/20/26 16:35, Florian Schmaus wrote:
> Commit 783c81098445 ("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.
> [...]
> Fixes: 783c81098445 ("PM: hibernate: call preallocate_image() after freeze prepare")
> Signed-off-by: Florian Schmaus <flo@geekplace.eu>

TWIMC, there are two reports about hibernate problems that identified
the mentioned commit as culprit (in one case while a stable backport was
prepared that was dropped meanwhile). One of the reporters mentioned
that the quoted patch fixed things in 7.2.y (see the last of the
following links):

https://lore.kernel.org/all/CALjEBWT9wyBYtWPgtg8Xd_FxRU_XnatzQMcwMB9_P2Fdj83+cQ@mail.gmail.com/#t
https://lore.kernel.org/all/CALjEBWQo0-Sdimo+aRNKUQvgDGw=jBFCcfwCXaqVdtoPrHLAQA@mail.gmail.com/
https://lore.kernel.org/all/CAKp=m=DkRA3FQdJC+1AKDtn1X8ZuO0HRF5H7PJVf15uQyBuEbg@mail.gmail.com/


Adding a stable tag would likely a nice touch.

Ciao, Thorsten
Re: [PATCH] PM: hibernate: Freeze kernel threads after image preallocation
Posted by Mario Limonciello 3 days, 1 hour ago
On 9/20/26 09:35, Florian Schmaus via B4 Relay wrote:
> From: Florian Schmaus <flo@geekplace.eu>
> 
> Commit 783c81098445 ("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: 783c81098445 ("PM: hibernate: call preallocate_image() after freeze prepare")
> Signed-off-by: Florian Schmaus <flo@geekplace.eu>
> ---
> During the review of commit 783c81098445 ("PM: hibernate: call
> preallocate_image() after freeze prepare") [1], concerns were raised
> regarding whether memory reclaim and swap I/O could deadlock if kernel
> threads were already frozen.
> 
> At the time, it was thought that pageout to swap would not depend on
> frozen threads. However, on Linux 7.2, I ran into reliable issues with
> suspend-to-disk hanging during hibernation. Reordering the sequence so
> that kernel threads are frozen after image preallocation (as done in
> this patch) fixes the issue for me.
> 
> This patch restores the ordering where kernel threads are frozen only after
> memory preallocation and swap I/O have completed, while keeping the
> benefit of calling dpm_prepare() beforehand so drivers can release pinned
> pages.
> 
> [1] https://patch.msgid.link/20260403-hibernation-fixes-v3-1-31bc9fa3ba2d@collabora.com
> ---
>   kernel/power/hibernate.c | 26 ++++++++++++++------------
>   1 file changed, 14 insertions(+), 12 deletions(-)
> 
> diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
> index d2479c69d71a..c13f68ab7f6e 100644
> --- a/kernel/power/hibernate.c
> +++ b/kernel/power/hibernate.c
> @@ -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;
>   }
>   
> 
> ---
> base-commit: 40288c9206c17eb66a603262e06a58d300d0f279
> change-id: 20260915-fix-hibernation-aad94ce17506
> 
> Best regards,
> --
> Florian Schmaus <flo@geekplace.eu>

Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>