Allocate the registry bitmap during boot and sync marked pages to the
bitmap.

The registry bitmap is handed over to the kdump kernel through physical
addresses and thus needs to be a single, physically contiguous range.

A marking lasts past free and until the page frame is handed out again
in post_alloc_hook() to account for stale data left in pages that are
mid-migration or currently being reclaimed. For the same reason the
unmark comes after any init_on_alloc zeroing.

A hugetlb folio coming out of the pool never passes through
post_alloc_hook(), so it drops the marking of its previous life in
dequeue_hugetlb_folio_node_exact() instead. A folio the pool got from
the page allocator was already cleared in post_alloc_hook.

The hooks sit behind a static key patched out unless the kernel was
booted with crash_memaction= to mitigate overhead when not used.

Signed-off-by: Jan Sebastian Götte <[email protected]>
Assisted-by: Claude Opus 5 <[email protected]>
---
 mm/hugetlb.c    | 4 ++++
 mm/mm_init.c    | 3 +++
 mm/page_alloc.c | 6 ++++++
 3 files changed, 13 insertions(+)

diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index da980377d353..36f0c0d8f5f1 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -31,6 +31,7 @@
 #include <linux/numa.h>
 #include <linux/llist.h>
 #include <linux/cma.h>
+#include <linux/crash_memaction.h>
 #include <linux/migrate.h>
 #include <linux/nospec.h>
 #include <linux/delayacct.h>
@@ -1281,6 +1282,9 @@ static struct folio 
*dequeue_hugetlb_folio_node_exact(struct hstate *h,
                folio_clear_hugetlb_freed(folio);
                h->free_huge_pages--;
                h->free_huge_pages_node[nid]--;
+
+               crash_memaction_unmark_pfns(folio_pfn(folio),
+                                           folio_nr_pages(folio));
                return folio;
        }
 
diff --git a/mm/mm_init.c b/mm/mm_init.c
index 9ce6060de06d..2245972b2685 100644
--- a/mm/mm_init.c
+++ b/mm/mm_init.c
@@ -27,6 +27,7 @@
 #include <linux/stackdepot.h>
 #include <linux/swap.h>
 #include <linux/cma.h>
+#include <linux/crash_memaction.h>
 #include <linux/crash_dump.h>
 #include <linux/execmem.h>
 #include <linux/sizes.h>
@@ -2706,6 +2707,8 @@ void __init mm_core_init(void)
         */
        kho_memory_init();
 
+       crash_memaction_init();
+
        memblock_free_all();
        mem_init();
        kmem_cache_init();
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 759786240af3..ff82f632dc7d 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -54,6 +54,7 @@
 #include <linux/khugepaged.h>
 #include <linux/delayacct.h>
 #include <linux/cacheinfo.h>
+#include <linux/crash_memaction.h>
 #include <linux/pgalloc_tag.h>
 #include <asm/div64.h>
 #include "internal.h"
@@ -1854,6 +1855,11 @@ inline void post_alloc_hook(struct page *page, unsigned 
int order,
        set_page_owner(page, order, gfp_flags);
        page_table_check_alloc(page, order);
        pgalloc_tag_add(page, current, 1 << order, alloc_flags);
+
+       /*
+        * Release leftover crash_memaction markings from a previous owner of 
this page.
+        */
+       crash_memaction_unmark_pfns(page_to_pfn(page), 1UL << order);
 }
 
 static void prep_new_page(struct page *page, unsigned int order, gfp_t 
gfp_flags,

-- 
2.55.0


Reply via email to