[PATCH 2/2 makedumpfile] Fix wrong exclusion of Slab pages on Linux 6.10-rc1 and later

HAGIO KAZUHITO(萩尾 一仁) k-hagio-ab at nec.com
Thu Jun 6 23:34:05 PDT 2024


* Required for kernel 6.10

Kernel commit 46df8e73a4a3 ("mm: free up PG_slab") moved the PG_slab
flag from page.flags into page._mapcount (slab.__page_type), and
introduced NUMBER(PAGE_SLAB_MAPCOUNT_VALUE) entry into vmcoreinfo.

Without the patch, "makedumpfile -d 8" option wrongly excludes Slab
pages and crash cannot open the dumpfile with an error like this:

  $ crash --kaslr auto vmlinux dumpfile
  ...
  please wait... (gathering task table data)
  crash: page excluded: kernel virtual address: ffff909980440270 type: "xa_node.slots[off]"

Signed-off-by: Kazuhito Hagio <k-hagio-ab at nec.com>
---
NOTE: This patch can be applied on top of "[PATCH makedumpfile] Fix
failure of hugetlb pages exclusion on Linux 6.9 and later".

 makedumpfile.c | 24 +++++++++++++++++++-----
 makedumpfile.h |  6 +++---
 2 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/makedumpfile.c b/makedumpfile.c
index a6cadc9..cc39f73 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -275,13 +275,26 @@ isHugetlb(unsigned long dtor)
 		   && (SYMBOL(free_huge_page) == dtor));
 }
 
+static inline int
+isSlab(unsigned long flags, unsigned int _mapcount)
+{
+	/* Linux 6.10 and later */
+	if (NUMBER(PAGE_SLAB_MAPCOUNT_VALUE) != NOT_FOUND_NUMBER) {
+		unsigned int PG_slab = ~NUMBER(PAGE_SLAB_MAPCOUNT_VALUE);
+		if ((_mapcount & (PAGE_TYPE_BASE | PG_slab)) == PAGE_TYPE_BASE)
+			return TRUE;
+	}
+
+	return flags & (1UL << NUMBER(PG_slab));
+}
+
 static int
 isOffline(unsigned long flags, unsigned int _mapcount)
 {
 	if (NUMBER(PAGE_OFFLINE_MAPCOUNT_VALUE) == NOT_FOUND_NUMBER)
 		return FALSE;
 
-	if (flags & (1UL << NUMBER(PG_slab)))
+	if (isSlab(flags, _mapcount))
 		return FALSE;
 
 	if (_mapcount == (int)NUMBER(PAGE_OFFLINE_MAPCOUNT_VALUE))
@@ -2977,6 +2990,7 @@ read_vmcoreinfo(void)
 	READ_NUMBER("PAGE_BUDDY_MAPCOUNT_VALUE", PAGE_BUDDY_MAPCOUNT_VALUE);
 	READ_NUMBER("PAGE_HUGETLB_MAPCOUNT_VALUE", PAGE_HUGETLB_MAPCOUNT_VALUE);
 	READ_NUMBER("PAGE_OFFLINE_MAPCOUNT_VALUE", PAGE_OFFLINE_MAPCOUNT_VALUE);
+	READ_NUMBER("PAGE_SLAB_MAPCOUNT_VALUE", PAGE_SLAB_MAPCOUNT_VALUE);
 	READ_NUMBER("phys_base", phys_base);
 	READ_NUMBER("KERNEL_IMAGE_SIZE", KERNEL_IMAGE_SIZE);
 
@@ -6043,7 +6057,7 @@ static int
 page_is_buddy_v3(unsigned long flags, unsigned int _mapcount,
 			unsigned long private, unsigned int _count)
 {
-	if (flags & (1UL << NUMBER(PG_slab)))
+	if (isSlab(flags, _mapcount))
 		return FALSE;
 
 	if (_mapcount == (int)NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE))
@@ -6618,7 +6632,7 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 		 */
 		else if ((info->dump_level & DL_EXCLUDE_CACHE)
 		    && is_cache_page(flags)
-		    && !isPrivate(flags) && !isAnon(mapping, flags)) {
+		    && !isPrivate(flags) && !isAnon(mapping, flags, _mapcount)) {
 			pfn_counter = &pfn_cache;
 		}
 		/*
@@ -6626,7 +6640,7 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 		 */
 		else if ((info->dump_level & DL_EXCLUDE_CACHE_PRI)
 		    && is_cache_page(flags)
-		    && !isAnon(mapping, flags)) {
+		    && !isAnon(mapping, flags, _mapcount)) {
 			if (isPrivate(flags))
 				pfn_counter = &pfn_cache_private;
 			else
@@ -6638,7 +6652,7 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 		 *  - hugetlbfs pages
 		 */
 		else if ((info->dump_level & DL_EXCLUDE_USER_DATA)
-			 && (isAnon(mapping, flags) || isHugetlb(compound_dtor))) {
+			 && (isAnon(mapping, flags, _mapcount) || isHugetlb(compound_dtor))) {
 			pfn_counter = &pfn_user;
 		}
 		/*
diff --git a/makedumpfile.h b/makedumpfile.h
index f08c49f..6b43a8b 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -161,9 +161,8 @@ test_bit(int nr, unsigned long addr)
 #define isSwapBacked(flags)	test_bit(NUMBER(PG_swapbacked), flags)
 #define isHWPOISON(flags)	(test_bit(NUMBER(PG_hwpoison), flags) \
 				&& (NUMBER(PG_hwpoison) != NOT_FOUND_NUMBER))
-#define isSlab(flags)		test_bit(NUMBER(PG_slab), flags)
-#define isAnon(mapping, flags)	(((unsigned long)mapping & PAGE_MAPPING_ANON) != 0 \
-				&& !isSlab(flags))
+#define isAnon(mapping, flags, _mapcount) \
+	(((unsigned long)mapping & PAGE_MAPPING_ANON) != 0 && !isSlab(flags, _mapcount))
 
 #define PAGE_TYPE_BASE		(0xf0000000)
 
@@ -2259,6 +2258,7 @@ struct number_table {
 	long	PAGE_BUDDY_MAPCOUNT_VALUE;
 	long	PAGE_HUGETLB_MAPCOUNT_VALUE;
 	long	PAGE_OFFLINE_MAPCOUNT_VALUE;
+	long	PAGE_SLAB_MAPCOUNT_VALUE;
 	long	SECTION_SIZE_BITS;
 	long	MAX_PHYSMEM_BITS;
 	long    HUGETLB_PAGE_DTOR;


More information about the kexec mailing list