[PATCH] PM: hibernate: align default resume swap with image-device checks

From: DaeMyung Kang

Date: Wed Apr 15 2026 - 04:14:08 EST


snapshot_open(O_RDONLY) pins the configured default resume swap area for
hibernation image writes, but it does not fully propagate that choice to
the image-device checks used by the block layer.

In particular, snapshot_open() uses swsusp_resume_device without
swsusp_resume_block when pinning the default resume swap area, and it
leaves snapshot_state.dev unset even after the pin succeeds. As a
result, the default resume swap selected at open time is not kept
aligned with is_hibernate_resume_dev() and can still be rejected by the
block layer in blkdev_write_iter() with -ETXTBSY until user space
explicitly selects the same area via SNAPSHOT_SET_SWAP_AREA.

Use swsusp_resume_block when pinning the default resume swap area and
record the device immediately after a successful pin so that the
hibernation image-device bookkeeping matches the configured resume
area. Also clear snapshot_state.dev on the open-time error path so it
never advertises a session that failed to fully open.

uswsusp itself is not affected because it always calls
SNAPSHOT_SET_SWAP_AREA right after open, which immediately overrides
snapshot_state.dev and re-pins the swap area. The user-visible change
is for minimal hibernation user space that relies on resume= and
resume_offset= alone: such tools no longer have to restate the resume
area via SNAPSHOT_SET_SWAP_AREA just to satisfy blkdev_write_iter()'s
IS_SWAPFILE gate or to obtain SWP_HIBERNATION swapoff protection. This
also matches the intent of the existing "The image device should be
accessible" comment in snapshot_open(). For the configured default
resume area, this gives snapshot_open() the same pin and
recorded-device state that SNAPSHOT_SET_SWAP_AREA would establish for
that same area, so user space relying on resume= and resume_offset=
does not need a follow-up SNAPSHOT_SET_SWAP_AREA just to satisfy the
IS_SWAPFILE gate and obtain swapoff protection.

Signed-off-by: DaeMyung Kang <charsyam@xxxxxxxxx>
---
Based on linux-next/master at commit e6efabc0afca ("Add linux-next
specific files for 20260414").

Tested in QEMU: with swap on a block device pointed to by
/sys/power/resume, opening /dev/snapshot O_RDONLY and then writing to
the swap block device returned -ETXTBSY before this change and -ENOSPC
(i.e. no longer rejected by the IS_SWAPFILE gate) after.

kernel/power/user.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/kernel/power/user.c b/kernel/power/user.c
index d0fcfba7ac23..c51b8185de4b 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -69,9 +69,13 @@ static int snapshot_open(struct inode *inode, struct file *filp)
data = &snapshot_state;
filp->private_data = data;
memset(&data->handle, 0, sizeof(struct snapshot_handle));
+ data->dev = 0;
if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
/* Hibernating. The image device should be accessible. */
- data->swap = pin_hibernation_swap_type(swsusp_resume_device, 0);
+ data->swap = pin_hibernation_swap_type(swsusp_resume_device,
+ swsusp_resume_block);
+ if (data->swap >= 0)
+ data->dev = swsusp_resume_device;
data->mode = O_RDONLY;
data->free_bitmaps = false;
error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION);
@@ -92,13 +96,13 @@ static int snapshot_open(struct inode *inode, struct file *filp)
}
if (error) {
unpin_hibernation_swap_type(data->swap);
+ data->dev = 0;
hibernate_release();
}

data->frozen = false;
data->ready = false;
data->platform_support = false;
- data->dev = 0;

Unlock:
unlock_system_sleep(sleep_flags);
--
2.43.0