]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
kho: make preserved pages compatible with deferred struct page init
authorEvangelos Petrongonas <epetron@amazon.de>
Thu, 23 Apr 2026 12:25:37 +0000 (14:25 +0200)
committerMike Rapoport (Microsoft) <rppt@kernel.org>
Sun, 31 May 2026 23:31:37 +0000 (02:31 +0300)
When CONFIG_DEFERRED_STRUCT_PAGE_INIT is enabled, struct page
initialization is deferred to parallel kthreads that run later
in the boot process.

During KHO restoration, kho_preserved_memory_reserve() writes metadata
for each preserved memory region. However, if the struct page has not
been initialized, this write targets uninitialized memory, potentially
leading to errors like:
BUG: unable to handle page fault for address: ...

Fix this by introducing kho_get_preserved_page(),  which ensures
all struct pages in a preserved region are initialized by calling
init_deferred_page() which is a no-op when the struct page is already
initialized.

Signed-off-by: Evangelos Petrongonas <epetron@amazon.de>
Co-developed-by: Michal Clapinski <mclapinski@google.com>
Signed-off-by: Michal Clapinski <mclapinski@google.com>
Reviewed-by: Pratyush Yadav (Google) <pratyush@kernel.org>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Link: https://patch.msgid.link/20260423122538.140993-3-mclapinski@google.com
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
kernel/liveupdate/Kconfig
kernel/liveupdate/kexec_handover.c

index 1a8513f16ef7cf27f2e52568a910fdfd11f2d583..c13af38ba23ab82952bac2d9efcec22fcb390e44 100644 (file)
@@ -1,12 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 menu "Live Update and Kexec HandOver"
-       depends on !DEFERRED_STRUCT_PAGE_INIT
 
 config KEXEC_HANDOVER
        bool "kexec handover"
        depends on ARCH_SUPPORTS_KEXEC_HANDOVER && ARCH_SUPPORTS_KEXEC_FILE
-       depends on !DEFERRED_STRUCT_PAGE_INIT
        select MEMBLOCK_KHO_SCRATCH
        select KEXEC_FILE
        select LIBFDT
index a0aa8281dba16d0491af7c559419dce61549a0c6..eb8abd04e7ffdbde0ddcf4c0438dde1a7c173628 100644 (file)
@@ -459,6 +459,31 @@ struct page *kho_restore_pages(phys_addr_t phys, unsigned long nr_pages)
 }
 EXPORT_SYMBOL_GPL(kho_restore_pages);
 
+/*
+ * With CONFIG_DEFERRED_STRUCT_PAGE_INIT, struct pages in higher memory regions
+ * may not be initialized yet at the time KHO deserializes preserved memory.
+ * KHO uses the struct page to store metadata and a later initialization would
+ * overwrite it.
+ * Ensure all the struct pages in the preservation are
+ * initialized. kho_preserved_memory_reserve() marks the reservation as noinit
+ * to make sure they don't get re-initialized later.
+ */
+static struct page *__init kho_get_preserved_page(phys_addr_t phys,
+                                                 unsigned int order)
+{
+       unsigned long pfn = PHYS_PFN(phys);
+       int nid;
+
+       if (!IS_ENABLED(CONFIG_DEFERRED_STRUCT_PAGE_INIT))
+               return pfn_to_page(pfn);
+
+       nid = early_pfn_to_nid(pfn);
+       for (unsigned long i = 0; i < (1UL << order); i++)
+               init_deferred_page(pfn + i, nid);
+
+       return pfn_to_page(pfn);
+}
+
 static int __init kho_preserved_memory_reserve(phys_addr_t phys,
                                               unsigned int order)
 {
@@ -467,7 +492,7 @@ static int __init kho_preserved_memory_reserve(phys_addr_t phys,
        u64 sz;
 
        sz = 1 << (order + PAGE_SHIFT);
-       page = phys_to_page(phys);
+       page = kho_get_preserved_page(phys, order);
 
        /* Reserve the memory preserved in KHO in memblock */
        memblock_reserve(phys, sz);