From: Stephen Brennan <stephen.s.brennan@oracle.com>
To: Tao Liu <ltao@redhat.com>
Cc: yamazaki-msmt@nec.com, k-hagio-ab@nec.com, kexec@lists.infradead.org
Subject: Re: [PATCH makedumpfile 3/9] Share page information with extension callbacks
Date: Mon, 17 Aug 2026 08:27:21 -0700 [thread overview]
Message-ID: <87ecfwdaxy.fsf@oracle.com> (raw)
In-Reply-To: <CAO7dBbU6tfVHLO6LW5ZQXbApqychfo=hAtXd8pD+Z7MXFF7fgg@mail.gmail.com>
Tao Liu <ltao@redhat.com> writes:
> Hi Stephen,
>
> On Tue, Jul 14, 2026 at 12:46 PM Stephen Brennan
> <stephen.s.brennan@oracle.com> wrote:
>>
>> 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@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 *);
>>
> The function signature of callbacks are changed, it will be better to
> update them in extensions/sample.c as well:
>
> int extension_callback(unsigned long pfn, const void *pcache)
> {
> return PG_UNDECID;
> }
>
> Since it will serve as a reference for future extension authors.
Hi Tao,
Thanks for the catch, I will send a v2 with this and a few other fixes.
Thanks,
Stephen
> Thaks,
> Tao Liu
>
>> 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
>>
next prev parent reply other threads:[~2026-08-17 15:27 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-14 0:45 [PATCH makedumpfile 0/9] Improvements to makedumpfile extensions, plus userspace stack tracing extension Stephen Brennan
2026-07-14 0:45 ` [PATCH makedumpfile 1/9] Do not call extensions for tail pages Stephen Brennan
2026-07-14 0:45 ` [PATCH makedumpfile 2/9] Honor CFLAGS in extension/Makefile Stephen Brennan
2026-07-14 0:45 ` [PATCH makedumpfile 3/9] Share page information with extension callbacks Stephen Brennan
2026-08-12 4:01 ` Tao Liu
2026-08-17 15:27 ` Stephen Brennan [this message]
2026-07-14 0:45 ` [PATCH makedumpfile 4/9] Introduce a stat for pages retained by extension Stephen Brennan
2026-08-13 2:15 ` Tao Liu
2026-08-13 4:54 ` HAGIO KAZUHITO(萩尾 一仁)
2026-08-17 3:44 ` Tao Liu
2026-08-17 19:58 ` Stephen Brennan
2026-07-14 0:45 ` [PATCH makedumpfile 5/9] Move page checks into makedumpfile.h Stephen Brennan
2026-07-14 0:45 ` [PATCH makedumpfile 6/9] Simplify arguments for page checks Stephen Brennan
2026-07-14 0:45 ` [PATCH makedumpfile 7/9] Add PG_INCLUDE_HEAD extension return status Stephen Brennan
2026-08-07 16:24 ` Stephen Brennan
2026-07-14 0:45 ` [PATCH makedumpfile 8/9] Add userstack extension Stephen Brennan
2026-07-14 0:45 ` [PATCH makedumpfile 9/9] Add elfheader extension Stephen Brennan
2026-08-03 15:55 ` [PATCH makedumpfile 0/9] Improvements to makedumpfile extensions, plus userspace stack tracing extension Stephen Brennan
2026-08-04 4:43 ` Tao Liu
2026-08-07 1:52 ` HAGIO KAZUHITO(萩尾 一仁)
2026-08-07 7:57 ` Tao Liu
2026-08-07 21:24 ` Stephen Brennan
2026-08-08 4:44 ` HAGIO KAZUHITO(萩尾 一仁)
2026-08-11 6:11 ` Tao Liu
2026-08-12 1:31 ` HAGIO KAZUHITO(萩尾 一仁)
2026-08-12 5:07 ` Tao Liu
2026-08-13 2:51 ` Tao Liu
2026-08-17 20:02 ` Stephen Brennan
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=87ecfwdaxy.fsf@oracle.com \
--to=stephen.s.brennan@oracle.com \
--cc=k-hagio-ab@nec.com \
--cc=kexec@lists.infradead.org \
--cc=ltao@redhat.com \
--cc=yamazaki-msmt@nec.com \
/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