[PATCH makedumpfile 3/9] Share page information with extension callbacks

Stephen Brennan stephen.s.brennan at oracle.com
Mon Jul 13 17:45:36 PDT 2026


In __exclude_unnecessary_pages(), we extract several fields related
to the page. Some of these, like compound_order and compound_dtor, have
logic specific to the kernel version.

Extensions can, of course, determine these values for themselves, but
it's extra work, and duplicates logic that may need to be updated
frequently with new kernel versions. What's more, if we put all the
values together in a single structure, helpers like isSlab() and others
can be implemented in terms of that structure and shared with the
extensions in order to further simplify their implementation.

With that in mind, group the per-page variables into a structure and
share them with extension callbacks. This breaks the extension API,
but since a release hasn't yet happened, it seems reasonable to do so.

Signed-off-by: Stephen Brennan <stephen.s.brennan at oracle.com>
---
 extension.c    |  8 ++---
 extension.h    |  3 +-
 makedumpfile.c | 83 +++++++++++++++++++++++++-------------------------
 makedumpfile.h | 16 ++++++++++
 4 files changed, 64 insertions(+), 46 deletions(-)

diff --git a/extension.c b/extension.c
index 5188c1f..9b29f0c 100644
--- a/extension.c
+++ b/extension.c
@@ -10,7 +10,7 @@
 #include "kallsyms.h"
 #include "btf_info.h"
 
-typedef int (*callback_fn)(unsigned long, const void *);
+typedef int (*callback_fn)(unsigned long, const void *, const struct pginfo *);
 
 struct extension_handle_cb {
 	void *handle;
@@ -306,14 +306,14 @@ fail:
  * 1) Include the page if anyone says PG_INCLUDE, and
  * 2) Exclude the page if no one says PG_INCLUDE, but one or more say PG_EXCLUDE.
  */
-int run_extension_callback(unsigned long pfn, const void *pcache)
+int run_extension_callback(unsigned long pfn, const void *pcache, const struct pginfo *inf)
 {
 	int result;
 	int ret = PG_UNDECID;
 
 	for (int i = 0; i < handle_cbs_len; i++) {
 		if (handle_cbs[i]->cb) {
-			result = handle_cbs[i]->cb(pfn, pcache);
+			result = handle_cbs[i]->cb(pfn, pcache, inf);
 			if (result == PG_INCLUDE) {
 				ret = result;
 				goto out;
@@ -341,7 +341,7 @@ bool add_extension_opts(char *opt)
 	return false;
 }
 
-int run_extension_callback(unsigned long pfn, const void *pcache)
+int run_extension_callback(unsigned long pfn, const void *pcache, const struct pginfo *i)
 {
 	return PG_UNDECID;
 }
diff --git a/extension.h b/extension.h
index ba8d32a..22af9a6 100644
--- a/extension.h
+++ b/extension.h
@@ -2,12 +2,13 @@
 #define _EXTENSION_H
 #include <stdbool.h>
 
+struct pginfo;
 enum {
 	PG_INCLUDE,	// Exntesion will keep the page
 	PG_EXCLUDE,	// Exntesion will discard the page
 	PG_UNDECID,	// Exntesion makes no decision
 };
-int run_extension_callback(unsigned long pfn, const void *pcache);
+int run_extension_callback(unsigned long pfn, const void *pcache, const struct pginfo *i);
 void init_extensions(void);
 void cleanup_extensions(void);
 bool add_extension_opts(char *opt);
diff --git a/makedumpfile.c b/makedumpfile.c
index e882b84..a4c9bbf 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -6466,12 +6466,13 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 	mdf_pfn_t pfn_read_start, pfn_read_end;
 	unsigned char *page_cache;
 	unsigned char *pcache;
-	unsigned int _count, _mapcount = 0, compound_order = 0;
+	struct pginfo i;
 	unsigned int order_offset, dtor_offset;
-	unsigned long flags, mapping, private = 0;
-	unsigned long compound_dtor, compound_head = 0;
 	int filter_pg;
 
+	i._mapcount = i.compound_order = 0;
+	i.private = i.compound_dtor = i.compound_head = 0;
+
 	/*
 	 * If a multi-page exclusion is pending, do it first
 	 */
@@ -6543,21 +6544,21 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 			pfn_read_end   = pfn + pfn_mm - 1;
 		}
 
-		flags   = ULONG(pcache + OFFSET(page.flags));
-		_count  = UINT(pcache + OFFSET(page._refcount));
-		mapping = ULONG(pcache + OFFSET(page.mapping));
+		i.flags   = ULONG(pcache + OFFSET(page.flags));
+		i._count  = UINT(pcache + OFFSET(page._refcount));
+		i.mapping = ULONG(pcache + OFFSET(page.mapping));
 
 		if (OFFSET(page._mapcount) != NOT_FOUND_STRUCTURE)
-			_mapcount = UINT(pcache + OFFSET(page._mapcount));
+			i._mapcount = UINT(pcache + OFFSET(page._mapcount));
 
-		compound_order = 0;
-		compound_dtor = 0;
+		i.compound_order = 0;
+		i.compound_dtor = 0;
 		/*
 		 * The last pfn of the mem_map cache must not be compound head
 		 * page since all compound pages are aligned to its page order
 		 * and PGMM_CACHED is a power of 2.
 		 */
-		if ((index_pg < PGMM_CACHED - 1) && isCompoundHead(flags)) {
+		if ((index_pg < PGMM_CACHED - 1) && isCompoundHead(i.flags)) {
 			unsigned char *addr = pcache + SIZE(page);
 
 			/*
@@ -6567,10 +6568,10 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 			if (NUMBER(PAGE_HUGETLB_MAPCOUNT_VALUE) != NOT_FOUND_NUMBER) {
 				unsigned long _flags_1 = ULONG(addr + OFFSET(page.flags));
 
-				compound_order = _flags_1 & 0xff;
+				i.compound_order = _flags_1 & 0xff;
 
-				if (_mapcount == (int)NUMBER(PAGE_HUGETLB_MAPCOUNT_VALUE))
-					compound_dtor = IS_HUGETLB;
+				if (i._mapcount == (int)NUMBER(PAGE_HUGETLB_MAPCOUNT_VALUE))
+					i.compound_dtor = IS_HUGETLB;
 
 				goto check_order;
 			}
@@ -6582,19 +6583,19 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 			if (NUMBER(PG_hugetlb) != NOT_FOUND_NUMBER) {
 				unsigned long _flags_1 = ULONG(addr + OFFSET(page.flags));
 
-				compound_order = _flags_1 & 0xff;
+				i.compound_order = _flags_1 & 0xff;
 
 				if (_flags_1 & (1UL << NUMBER(PG_hugetlb)))
-					compound_dtor = IS_HUGETLB;
+					i.compound_dtor = IS_HUGETLB;
 
 				goto check_order;
 			}
 
 			if (order_offset) {
 				if (info->kernel_version >= KERNEL_VERSION(4, 16, 0))
-					compound_order = UCHAR(addr + order_offset);
+					i.compound_order = UCHAR(addr + order_offset);
 				else
-					compound_order = USHORT(addr + order_offset);
+					i.compound_order = USHORT(addr + order_offset);
 			}
 
 			if (dtor_offset) {
@@ -6603,40 +6604,40 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 				 * to the ID of it since linux-4.4.
 				 */
 				if (info->kernel_version >= KERNEL_VERSION(4, 16, 0))
-					compound_dtor = UCHAR(addr + dtor_offset);
+					i.compound_dtor = UCHAR(addr + dtor_offset);
 				else if (info->kernel_version >= KERNEL_VERSION(4, 4, 0))
-					compound_dtor = USHORT(addr + dtor_offset);
+					i.compound_dtor = USHORT(addr + dtor_offset);
 				else
-					compound_dtor = ULONG(addr + dtor_offset);
+					i.compound_dtor = ULONG(addr + dtor_offset);
 			}
 check_order:
-			if ((compound_order >= sizeof(unsigned long) * 8)
-			    || ((pfn & ((1UL << compound_order) - 1)) != 0)) {
+			if ((i.compound_order >= sizeof(unsigned long) * 8)
+			    || ((pfn & ((1UL << i.compound_order) - 1)) != 0)) {
 				/* Invalid order */
-				compound_order = 0;
+				i.compound_order = 0;
 			}
 		}
 		if (OFFSET(page.compound_head) != NOT_FOUND_STRUCTURE)
-			compound_head = ULONG(pcache + OFFSET(page.compound_head));
+			i.compound_head = ULONG(pcache + OFFSET(page.compound_head));
 
 		if (OFFSET(page.private) != NOT_FOUND_STRUCTURE)
-			private = ULONG(pcache + OFFSET(page.private));
+			i.private = ULONG(pcache + OFFSET(page.private));
 
-		nr_pages = 1 << compound_order;
+		nr_pages = 1 << i.compound_order;
 		pfn_counter = NULL;
 
 		/*
 		 * Excludable compound tail pages must have already been excluded by
 		 * exclude_range(), don't need to check them here.
 		 */
-		if (compound_head & 1)
+		if (i.compound_head & 1)
 			continue;
 
 		/*
 		 * Include pages that specified by user via
 		 * makedumpfile extensions
 		 */
-		filter_pg = run_extension_callback(pfn, pcache);
+		filter_pg = run_extension_callback(pfn, pcache, &i);
 		if (filter_pg == PG_INCLUDE)
 			continue;
 
@@ -6646,14 +6647,14 @@ check_order:
 		 */
 		if ((info->dump_level & DL_EXCLUDE_FREE)
 		    && info->page_is_buddy
-		    && info->page_is_buddy(flags, _mapcount, private, _count)) {
+		    && info->page_is_buddy(i.flags, i._mapcount, i.private, i._count)) {
 			if ((ARRAY_LENGTH(zone.free_area) != NOT_FOUND_STRUCTURE) &&
-			    (private >= ARRAY_LENGTH(zone.free_area))) {
+			    (i.private >= ARRAY_LENGTH(zone.free_area))) {
 				MSG("WARNING: Invalid free page order: pfn=%llx, order=%lu, max order=%lu\n",
-				    pfn, private, ARRAY_LENGTH(zone.free_area) - 1);
+				    pfn, i.private, ARRAY_LENGTH(zone.free_area) - 1);
 				continue;
 			}
-			nr_pages = 1 << private;
+			nr_pages = 1 << i.private;
 			pfn_counter = &pfn_free;
 		}
 		/*
@@ -6663,7 +6664,7 @@ check_order:
 		 * accepted immediately without being on the list.
 		 */
 		else if ((info->dump_level & DL_EXCLUDE_FREE)
-			&& isUnaccepted(_mapcount)) {
+			&& isUnaccepted(i._mapcount)) {
 			nr_pages = 1 << (ARRAY_LENGTH(zone.free_area) - 1);
 			pfn_counter = &pfn_free;
 		}
@@ -6671,17 +6672,17 @@ check_order:
 		 * Exclude the non-private cache page.
 		 */
 		else if ((info->dump_level & DL_EXCLUDE_CACHE)
-		    && is_cache_page(flags)
-		    && !isPrivate(flags) && !isAnon(mapping, flags, _mapcount)) {
+		    && is_cache_page(i.flags)
+		    && !isPrivate(i.flags) && !isAnon(i.mapping, i.flags, i._mapcount)) {
 			pfn_counter = &pfn_cache;
 		}
 		/*
 		 * Exclude the cache page whether private or non-private.
 		 */
 		else if ((info->dump_level & DL_EXCLUDE_CACHE_PRI)
-		    && is_cache_page(flags)
-		    && !isAnon(mapping, flags, _mapcount)) {
-			if (isPrivate(flags))
+		    && is_cache_page(i.flags)
+		    && !isAnon(i.mapping, i.flags, i._mapcount)) {
+			if (isPrivate(i.flags))
 				pfn_counter = &pfn_cache_private;
 			else
 				pfn_counter = &pfn_cache;
@@ -6692,19 +6693,19 @@ check_order:
 		 *  - hugetlbfs pages
 		 */
 		else if ((info->dump_level & DL_EXCLUDE_USER_DATA)
-			 && (isAnon(mapping, flags, _mapcount) || isHugetlb(compound_dtor))) {
+			 && (isAnon(i.mapping, i.flags, i._mapcount) || isHugetlb(i.compound_dtor))) {
 			pfn_counter = &pfn_user;
 		}
 		/*
 		 * Exclude the hwpoison page.
 		 */
-		else if (isHWPOISON(flags)) {
+		else if (isHWPOISON(i.flags)) {
 			pfn_counter = &pfn_hwpoison;
 		}
 		/*
 		 * Exclude pages that are logically offline.
 		 */
-		else if (isOffline(flags, _mapcount)) {
+		else if (isOffline(i.flags, i._mapcount)) {
 			pfn_counter = &pfn_offline;
 		}
 		/*
diff --git a/makedumpfile.h b/makedumpfile.h
index 4f707c7..87f973d 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -1507,6 +1507,22 @@ struct ppc64_vmemmap {
 	unsigned long		virt;
 };
 
+/* Per-page information determined during page filtering which may be useful
+ * to extensions making their decisions */
+struct pginfo {
+	unsigned long flags;
+	unsigned long mapping;
+	/* Present whenever OFFSET(page.private) != NOT_FOUND_STRUCTURE */
+	unsigned long private;
+	unsigned long compound_dtor;
+	/* Present whenever OFFSET(page.compound_head) != NOT_FOUND_STRUCTURE */
+	unsigned long compound_head;
+	unsigned int _count;
+	/* Present whenever OFFSET(page._mapcount) != NOT_FOUND_STRUCTURE */
+	unsigned int _mapcount;
+	unsigned int compound_order;
+};
+
 struct DumpInfo {
 	int32_t		kernel_version;      /* version of first kernel*/
 	struct timeval	timestamp;
-- 
2.47.3




More information about the kexec mailing list