[PATCH v3 2/4] PM: hibernate: do not free the image in place while restore I/O is in flight
From: Xiong Xin
Date: Thu Oct 01 2026 - 23:42:51 EST
snapshot_write_next() calls swsusp_free() to release all snapshot pages
when one of its internal allocations fails, in prepare_image(),
get_buffer() or get_highmem_page_buffer(). At that point read bios
submitted by load_image() or load_compressed_image() may still be in
flight: the bios do not take page references, so nothing prevents the
freed pages from being handed out again while the device is still
writing the image data into them.
Drop the in-place releases and let the error paths of
load_image_and_restore() and hibernate() free the image, after
swsusp_read() has drained the batch.
Fixes: 343df3c79c62 ("suspend: simplify block I/O handling")
Assisted-by: GLM:glm-5.3
Signed-off-by: Xiong Xin <xiongxin@xxxxxxxxxx>
---
New in v3: without it, patch 4 could touch snapshot pages that this
in-place release has already freed.
kernel/power/snapshot.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index b209712cb2c3..244f4a19c025 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -2520,10 +2520,8 @@ static void *get_highmem_page_buffer(struct page *page,
* use a "safe" page frame to store the loaded page.
*/
pbe = chain_alloc(ca, sizeof(struct highmem_pbe));
- if (!pbe) {
- swsusp_free();
+ if (!pbe)
return ERR_PTR(-ENOMEM);
- }
pbe->orig_page = page;
if (safe_highmem_pages > 0) {
struct page *tmp;
@@ -2702,7 +2700,6 @@ static int prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm,
return 0;
Free:
- swsusp_free();
return error;
}
@@ -2737,10 +2734,8 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
* use a "safe" page frame to store the loaded page.
*/
pbe = chain_alloc(ca, sizeof(struct pbe));
- if (!pbe) {
- swsusp_free();
+ if (!pbe)
return ERR_PTR(-ENOMEM);
- }
pbe->orig_address = page_address(page);
pbe->address = __get_safe_page(ca->gfp_mask);
if (!pbe->address)
--
2.25.1