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

Tao Liu <[email protected]>
Newsgroups org.infradead.lists.kexec
Message-ID <CAO7dBbU6tfVHLO6LW5ZQXbApqychfo=hAtXd8pD+Z7MXFF7fgg@mail.gmail.com>
Hi Stephen,

On Tue, Jul 14, 2026 at 12:46 PM Stephen Brennan
<[email protected]> 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 <[email protected]>
> ---
>  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.

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
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.