From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>
To: Andrew Morton <akpm@linux-foundation.org>,
Alexander Potapenko <glider@google.com>,
David Hildenbrand <david@kernel.org>,
Marco Elver <elver@google.com>,
"Rafael J. Wysocki" <rafael@kernel.org>
Cc: Dmitry Vyukov <dvyukov@google.com>, Len Brown <lenb@kernel.org>,
Mike Rapoport <rppt@kernel.org>, Pavel Machek <pavel@kernel.org>,
kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org,
linux-mm@kvack.org, linux-pm@vger.kernel.org
Subject: [PATCH 5/5] hibernation: make hibernation unavailable when debug_pagealloc is on
Date: Thu, 17 Sep 2026 09:07:07 +0300 [thread overview]
Message-ID: <20260917-hibernation-v1-5-7f7dfae3dbe0@kernel.org> (raw)
In-Reply-To: <20260917-hibernation-v1-0-7f7dfae3dbe0@kernel.org>
Back in 2008 when commit 8a235efad548a ("Hibernation: Handle
DEBUG_PAGEALLOC on x86") enabled coexistence of hibernation and
DEBUG_PAGEALLOC, the world was simpler, the combination was only supported
on x86 and a non-present page in the direct map meant that the page was
free and debug_pagealloc removed its mapping.
Nowadays there are more architectures with inconsistent views of how the
direct map should be managed, there are more debug mechanisms in MM that
can either drop a page from the direct map (e.g. KFENCE) or require that a
page must be mapped immediately after resume (e.g. init_on_free).
The latter constraint is particularly nasty, because enabling
debug_pagealloc and PAGE_POISON at the same time simply breaks resume:
BUG: unable to handle page fault for address: ffff888000100000
#PF: supervisor write access in kernel mode
#PF: error_code(0x0002) - not-present page
PGD 4f0c067 P4D 4f0c067 PUD 4f0d067 PMD 4f0e067 PTE 800fffffffeff020
Oops: Oops: 0002 [#1] SMP DEBUG_PAGEALLOC NOPTI
CPU: 0 UID: 0 PID: 477 Comm: bash Not tainted 7.3.0-rc3-00090-g4a613f1d9124 #1 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
RIP: 0010:__kernel_poison_pages+0x45/0x70
Code: 89 fa 48 c1 e6 06 48 01 fe 48 89 d1 48 2b 0d 9a ed 87 01 48 83 c2 40 48 c1 f9 06 48 c1 e1 0c 48 03 0d 97 ed 87 01 48 8d 79 08 <48> 89 01 48 83 e7 f8 48 89 81 f8 0f 00 00 48 29 f9 81 c1 00 10 00
RSP: 0018:ffffc900017dfd78 EFLAGS: 00010086
RAX: aaaaaaaaaaaaaaaa RBX: 0000000000000000 RCX: ffff888000100000
RDX: ffffea0000004040 RSI: ffffea0000004040 RDI: ffff888000100008
RBP: 0000000000000000 R08: ffff888130fcada0 R09: 00000000723e0de4
R10: 0000000096ad9215 R11: 00000000db907bcf R12: 0000000000000005
R13: 0000000000000005 R14: 0000000000000000 R15: 0000000000000000
FS: 00007f8f2243e780(0000) GS:ffff8882e8e13000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: ffff888000100000 CR3: 0000000140679000 CR4: 0000000000750ef0
PKRU: 55555554
Call Trace:
<TASK>
clear_or_poison_free_pages+0xd1/0xe0
hibernation_snapshot+0x548/0x5a0
hibernate.cold+0xcb/0x321
state_store+0xc3/0xd0
kernfs_fop_write_iter+0x163/0x240
vfs_write+0x21f/0x550
ksys_write+0x70/0xf0
do_syscall_64+0xb1/0x590
? __irq_exit_rcu+0x40/0x110
entry_SYSCALL_64_after_hwframe+0x76/0x7e
RIP: 0033:0x7f8f224d0687
Code: 48 89 fa 4c 89 df e8 58 b3 00 00 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f 1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff
RSP: 002b:00007ffe7bbe0910 EFLAGS: 00000202 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 00007f8f2243e780 RCX: 00007f8f224d0687
RDX: 0000000000000005 RSI: 000055e3e53135d0 RDI: 0000000000000001
RBP: 000055e3e53135d0 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000005
R13: 00007f8f226295c0 R14: 00007f8f22626e80 R15: 0000000000000000
</TASK>
Modules linked in:
CR2: ffff888000100000
It's possible to build a complex infrastructure involving a new page flag
and/or page_type to allow robust hibernation and restore with
debug_pagealloc enabled.
This infrastructure requires a proper detection whether it is safe to
temporarily remap a page to include it in the hibernation snapshot because
relying on kernel_page_present() is too permissive and may include pages
that were deliberately removed from the direct map for security reasons.
This complexity does not seem justified to deal with an esoteric use case
of hibernating a system that runs with debug_pagealloc enabled.
Make hibernation unavailable when debug_pagealloc is enabled and simplify
hibernate_{map,unmap}_page() that don't need to deal with debug_pagealloc
anymore.
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
kernel/power/hibernate.c | 1 +
kernel/power/snapshot.c | 31 +++++--------------------------
2 files changed, 6 insertions(+), 26 deletions(-)
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 281ad49411481..37e41c08f4f36 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -110,6 +110,7 @@ bool hibernation_available(void)
{
return nohibernate == 0 &&
!security_locked_down(LOCKDOWN_HIBERNATION) &&
+ !debug_pagealloc_enabled() &&
!secretmem_active() && !cxl_mem_active();
}
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 6583b57722e25..baa4fc9e5ad6f 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -85,12 +85,7 @@ static inline int hibernate_map_page(struct page *page)
if (is_kfence_address(page_address(page)))
return kfence_force_mapping(page) ? 0 : -EFAULT;
- if (IS_ENABLED(CONFIG_ARCH_HAS_SET_DIRECT_MAP)) {
- return set_direct_map_default_noflush(page, 1);
- } else {
- debug_pagealloc_map_pages(page, 1);
- return 0;
- }
+ return 0;
}
static inline int hibernate_unmap_page(struct page *page)
@@ -98,17 +93,6 @@ static inline int hibernate_unmap_page(struct page *page)
if (is_kfence_address(page_address(page)))
return kfence_restore_mapping(page) ? 0 : -EFAULT;
- if (IS_ENABLED(CONFIG_ARCH_HAS_SET_DIRECT_MAP)) {
- unsigned long addr = (unsigned long)page_address(page);
- int ret = set_direct_map_invalid_noflush(page, 1);
-
- if (ret)
- return ret;
-
- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
- } else {
- debug_pagealloc_unmap_pages(page, 1);
- }
return 0;
}
@@ -1446,10 +1430,10 @@ static inline bool do_copy_page(long *dst, long *src)
/*
* safe_copy_page - Copy a page in a safe way.
*
- * Check if the page we are going to copy is marked as present in the kernel
- * page tables. This always is the case if CONFIG_DEBUG_PAGEALLOC or
- * CONFIG_ARCH_HAS_SET_DIRECT_MAP is not set. In that case kernel_page_present()
- * always returns 'true'.
+ * Page could be not present in the kernel page tables. Try to map it before
+ * copiyng and unmap back as needed.
+ * If the kernel page table update fails, bail out with an error.
+ *
* Sets @zeros_only to true if the page was entirely composed of zeros.
*
* Returns 0 on success, a negative error code on failure.
@@ -1458,11 +1442,6 @@ static int safe_copy_page(void *dst, struct page *s_page, bool *zeros_only)
{
int err;
- if (kernel_page_present(s_page)) {
- *zeros_only = do_copy_page(dst, page_address(s_page));
- return 0;
- }
-
err = hibernate_map_page(s_page);
if (err)
return err;
--
2.53.0
prev parent reply other threads:[~2026-09-17 6:07 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-17 6:07 [PATCH 0/5] hibernation: make safe_copy_page more robust and remove debug_pagealloc support Mike Rapoport (Microsoft)
2026-09-17 6:07 ` [PATCH 1/5] hibernation: make swsusp_page helpers static Mike Rapoport (Microsoft)
2026-09-17 6:07 ` [PATCH 2/5] hibernation: ensure secretmem pages don't reach a snapshot Mike Rapoport (Microsoft)
2026-09-17 6:07 ` [PATCH 3/5] hibernate: handle potential errors in hibernate_{map,unmap}_page() Mike Rapoport (Microsoft)
2026-09-17 6:07 ` [PATCH 4/5] hibernation, KFENCE: explicitly map/unmap KFENCE pages Mike Rapoport (Microsoft)
2026-09-17 6:07 ` Mike Rapoport (Microsoft) [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260917-hibernation-v1-5-7f7dfae3dbe0@kernel.org \
--to=rppt@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=david@kernel.org \
--cc=dvyukov@google.com \
--cc=elver@google.com \
--cc=glider@google.com \
--cc=kasan-dev@googlegroups.com \
--cc=lenb@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-pm@vger.kernel.org \
--cc=pavel@kernel.org \
--cc=rafael@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®