summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorDavid Carlier <devnexen@gmail.com>2026-04-30 20:56:51 +0100
committerAndrew Morton <akpm@linux-foundation.org>2026-10-19 21:39:12 -0700
commita54fed3c745932afda5fb0db4e095c8b9d6495f4 (patch)
tree1bfa9557de3d511270786c628c804fc5471002af /kernel
parent4eeaa4532f9a20da4f91074e29047b1fdaa70d35 (diff)
downloadlinux-next-a54fed3c745932afda5fb0db4e095c8b9d6495f4.tar.gz
linux-next-a54fed3c745932afda5fb0db4e095c8b9d6495f4.zip
mm/swap, PM: hibernate: atomically replace hibernation pin
snapshot_set_swap_area() unpins the previously selected swap device and pins the new one in two separate swap_lock critical sections. In the gap between them, swapoff() observes SWP_HIBERNATION cleared, bypasses the guard, and tears down the device, reopening the race the SWP_HIBERNATION pin was meant to close. The window is reachable on any SNAPSHOT_SET_SWAP_AREA call after the snapshot device is opened for hibernation, and on any retry after the resume path's first selection. Add repin_hibernation_swap_type(), which looks up the new device, clears the old SWP_HIBERNATION flag and sets the new one under a single swap_lock acquisition. The same-device case is short- circuited so userspace can re-select the same swap area without tripping WARN_ON_ONCE and -EBUSY. Switch snapshot_set_swap_area() to the new helper. A failed lookup now preserves the previous pin instead of dropping it, so a bad SNAPSHOT_SET_SWAP_AREA leaves the prior selection intact. The open and release paths keep using pin_hibernation_swap_type() and unpin_hibernation_swap_type(). The race was identified during AI-assisted review of the SWP_HIBERNATION pinning series. [akpm@linux-foundation.org: coding-style cleanups] Link: https://lore.kernel.org/20260430195651.287659-1-devnexen@gmail.com Fixes: 8e6e0d845823 ("mm/swap, PM: hibernate: fix swapoff race in uswsusp by pinning swap device") Signed-off-by: David Carlier <devnexen@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Assisted-by: Codex (gpt-5-codex) Cc: Baoquan He <bhe@redhat.com> Cc: Barry Song <baohua@kernel.org> Cc: Chris Li <chrisl@kernel.org> Cc: Kairui Song <kasong@tencent.com> Cc: Kemeng Shi <shikemeng@huaweicloud.com> Cc: Len Brown <lenb@kernel.org> Cc: Nhat Pham <nphamcs@gmail.com> Cc: "Rafael J. Wysocki" <rafael@kernel.org> Cc: DaeMyung Kang <charsyam@gmail.com> Cc: Youngjun Park <youngjun.park@lge.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/user.c17
1 files changed, 5 insertions, 12 deletions
diff --git a/kernel/power/user.c b/kernel/power/user.c
index d0fcfba7ac23..6e4f40e49319 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -218,6 +218,7 @@ static int snapshot_set_swap_area(struct snapshot_data *data,
{
sector_t offset;
dev_t swdev;
+ int new_type;
if (swsusp_swap_in_use())
return -EPERM;
@@ -238,19 +239,11 @@ static int snapshot_set_swap_area(struct snapshot_data *data,
offset = swap_area.offset;
}
- /*
- * Unpin the swap device if a swap area was already
- * set by SNAPSHOT_SET_SWAP_AREA.
- */
- unpin_hibernation_swap_type(data->swap);
+ new_type = repin_hibernation_swap_type(data->swap, swdev, offset);
+ if (new_type < 0)
+ return new_type;
- /*
- * User space encodes device types as two-byte values,
- * so we need to recode them
- */
- data->swap = pin_hibernation_swap_type(swdev, offset);
- if (data->swap < 0)
- return swdev ? -ENODEV : -EINVAL;
+ data->swap = new_type;
data->dev = swdev;
return 0;
}