Hi Tao,
On Mon, Aug 17, 2026 at 10:48:43PM +1200, Tao Liu wrote:
Hi Dave & Kazu,
On Thu, Aug 13, 2026 at 5:22 PM Dave Young <yangrr.2009(a)tsinghua.org.cn> wrote:
>
>
>
> On 8/12/26 3:13 PM, HAGIO KAZUHITO(萩尾 一仁) wrote:
> > On 2026/08/12 11:33, Dave Young wrote:
> >>
> >>
> >> On 7/23/26 1:09 PM, HAGIO KAZUHITO(萩尾 一仁) wrote:
> >>> From: Kazuhito Hagio <k-hagio-ab(a)nec.com>
> >>>
> >>> Kernel commit d50569612c29 ("mm: rename the
'compound_head' field in the
> >>> 'struct page' to 'compound_info'") and related
patches [1] changed the
> >>> field name and its value.
> >>>
> >>> Without the patch, crash prints the following warning during startup,
> >>>
> >>> WARNING: SLUB: cannot determine how compound pages are linked
> >>>
> >>> and "bt -F" option fails with the following error.
> >>>
> >>> crash> bt -F
> >>>
> >>> bt: invalid structure member offset: page_first_page
> >>> FILE: memory.c LINE: 20238 FUNCTION: compound_head()
> >>>
> >>> [1]
https://lore.kernel.org/all/20260227194302.274384-1-kas@kernel.org/
> >>>
> >>> Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
> >>> ---
> >>> defs.h | 1 +
> >>> memory.c | 44 ++++++++++++++++++++++++++++++++++++--------
> >>> symbols.c | 1 +
> >>> 3 files changed, 38 insertions(+), 8 deletions(-)
> >>>
> >>> diff --git a/defs.h b/defs.h
> >>> index e3027e2b9141..88b7bbeb2372 100644
> >>> --- a/defs.h
> >>> +++ b/defs.h
> >>> @@ -2295,6 +2295,7 @@ struct offset_table { /* stash
of commonly-used offsets */
> >>> long page_compound_order;
> >>> long folio__folio_order;
> >>> long folio__flags_1;
> >>> + long page_compound_info;
> >>> };
> >>>
> >>> struct size_table { /* stash of commonly-used sizes */
> >>> diff --git a/memory.c b/memory.c
> >>> index 3f3aa274ab5a..7102e951f1d5 100644
> >>> --- a/memory.c
> >>> +++ b/memory.c
> >>> @@ -414,6 +414,7 @@ mem_init(void)
> >>> #define FOLIO_ORDER_V2 2
> >>> #define FOLIO_ORDER_V3 3
> >>> static int folio_order_version;
> >>> +static int compound_info_has_mask = FALSE;
> >>>
> >>> /*
> >>> * Stash a few popular offsets and some basic kernel virtual memory
> >>> @@ -547,6 +548,7 @@ vm_init(void)
> >>> MEMBER_OFFSET_INIT(page_compound_head, "page",
"compound_head");
> >>> if (INVALID_MEMBER(page_compound_head))
> >>> ANON_MEMBER_OFFSET_INIT(page_compound_head,
"page", "compound_head");
> >>> + MEMBER_OFFSET_INIT(page_compound_info, "page",
"compound_info");
> >>> MEMBER_OFFSET_INIT(page_private, "page",
"private");
> >>> MEMBER_OFFSET_INIT(page_freelist, "page",
"freelist");
> >>> MEMBER_OFFSET_INIT(page_page_type, "page",
"page_type");
> >>> @@ -1352,6 +1354,17 @@ vm_init(void)
> >>> } else if (CRASHDEBUG(1))
> >>> error(NOTE, "page_hash_table does not exist in this
kernel\n");
> >>>
> >>> + /*
> >>> + * on Linux 7.1 and later, zone.vmemmap_tails is defined only when
> >>> + * CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP is enabled.
> >>> + */
> >>> +#define is_power_of_2(n) (n - 1 < (n ^ (n - 1)))
> >>
> >> Hi Kazu, BTW, there is one nitpick found by AI, it would be better to
improve the above macro as below or just use the kernel inline function:
> >> #define IS_POWER_OF_TWO(n) ((n) > 0 && ((n) & ((n) - 1)) ==
0)
> >
> > Either is fine, but I think the former is the current is_power_of_2()
> > used in compound_info_has_mask(), and I used the same one as kernel.
>
> Hi Kazu, I agree with you it should work here, but the suggested one is more robust
as it checks the edge value and adds parentheses around 'n' to avoid side effect
of multiple expansion in some cases. Anyway up to Tao to handle it or not.
>
Frankly I'd prefer the ((n) > 0 && ((n) & ((n) - 1)) == 0) one,
because it is more easy to understand than (n - 1 < (n ^ (n - 1))).
How about we use the former instead? If Kazu agrees, we can replace it
when merge, so no need to send v2. For the patchset, LGTM, ack.
I see Kazu has replied in another email and acked the change. Thank you
both!
I just applied the two patches with the change.
>
> Thanks,
> Tao Liu
>
> > >
> > >
https://github.com/torvalds/linux/commit/4cc67b048459bebb7a60b693044ec83f...
> > >
https://github.com/torvalds/linux/blob/master/include/linux/page-flags.h#...
> > >
> > >>
> > >> Feel free to take my Tested-by
> > >
> > > Thank you for your help!
> > >
> > > Thanks,
> > > Kazu
> > >
> > >>
> > >>
> > >>> + if (VALID_MEMBER(page_compound_info) &&
> > >>> + is_power_of_2(SIZE(page)) &&
MEMBER_EXISTS("zone", "vmemmap_tails"))
> > >>> + compound_info_has_mask = TRUE;
> > >>> + if (CRASHDEBUG(1))
> > >>> + error(NOTE, "compound_info_has_mask = %d\n",
compound_info_has_mask);
> > >>> +
> > >>> kmem_cache_init();
> > >>>
> > >>> page_flags_init();
> > >>> @@ -5642,10 +5655,11 @@ PG_slab_flag_init(void)
> > >>> }
> > >>> }
> > >>>
> > >>> - if (VALID_MEMBER(page_compound_head)) {
> > >>> + if (VALID_MEMBER(page_compound_head) ||
VALID_MEMBER(page_compound_info)) {
> > >>> if (CRASHDEBUG(2))
> > >>> fprintf(fp,
> > >>> - "PG_head_tail_mask: (UNUSED):
page.compound_head exists!\n");
> > >>> + "PG_head_tail_mask: (UNUSED):
page.compound_head or "
> > >>> + "page.compound_info exists!\n");
> > >>> } else if (vt->flags & KMALLOC_SLUB) {
> > >>> /*
> > >>> * PG_slab and the following are hardwired for
> > >>> @@ -9858,7 +9872,8 @@ vaddr_to_kmem_cache(ulong vaddr, char *buf,
int verbose)
> > >>> &page_flags, sizeof(ulong),
"page.flags",
> > >>> FAULT_ON_ERROR);
> > >>> if (!page_slab(page, page_flags)) {
> > >>> - if (((vt->flags & KMALLOC_SLUB) ||
VALID_MEMBER(page_compound_head)) ||
> > >>> + if (((vt->flags & KMALLOC_SLUB) ||
VALID_MEMBER(page_compound_head) ||
> > >>> + VALID_MEMBER(page_compound_info)) ||
> > >>> ((vt->flags & KMALLOC_COMMON)
&&
> > >>> VALID_MEMBER(page_slab) &&
VALID_MEMBER(page_first_page))) {
> > >>>
readmem(compound_head(page)+OFFSET(page_flags), KVADDR,
> > >>> @@ -9873,7 +9888,8 @@ vaddr_to_kmem_cache(ulong vaddr, char *buf,
int verbose)
> > >>>
> > >>> if ((vt->flags & KMALLOC_SLUB) ||
> > >>> ((vt->flags & KMALLOC_COMMON) &&
VALID_MEMBER(page_slab) &&
> > >>> - (VALID_MEMBER(page_compound_head) ||
VALID_MEMBER(page_first_page)))) {
> > >>> + (VALID_MEMBER(page_compound_head) ||
VALID_MEMBER(page_compound_info) ||
> > >>> + VALID_MEMBER(page_first_page)))) {
> > >>> readmem(compound_head(page)+OFFSET(page_slab),
> > >>> KVADDR, &cache, sizeof(void *),
> > >>> "page.slab", FAULT_ON_ERROR);
> > >>> @@ -9904,7 +9920,8 @@ is_slab_overload_page(ulong vaddr, ulong
*page_head, char *buf)
> > >>>
> > >>> if ((vt->flags & SLAB_OVERLOAD_PAGE) &&
> > >>> is_page_ptr(vaddr, NULL) && VALID_MEMBER(page_slab)
&&
> > >>> - (VALID_MEMBER(page_compound_head) ||
VALID_MEMBER(page_first_page))) {
> > >>> + (VALID_MEMBER(page_compound_head) ||
VALID_MEMBER(page_compound_info) ||
> > >>> + VALID_MEMBER(page_first_page))) {
> > >>> readmem(compound_head(vaddr)+OFFSET(page_slab),
> > >>> KVADDR, &cache, sizeof(void *),
> > >>> "page.slab", FAULT_ON_ERROR);
> > >>> @@ -9944,7 +9961,8 @@ vaddr_to_slab(ulong vaddr)
> > >>>
> > >>> slab = 0;
> > >>>
> > >>> - if ((vt->flags & KMALLOC_SLUB) ||
VALID_MEMBER(page_compound_head))
> > >>> + if ((vt->flags & KMALLOC_SLUB) ||
VALID_MEMBER(page_compound_head) ||
> > >>> + VALID_MEMBER(page_compound_info))
> > >>> slab = compound_head(page);
> > >>> else if (vt->flags & SLAB_OVERLOAD_PAGE)
> > >>> slab = compound_head(page);
> > >>> @@ -20222,11 +20240,21 @@ get_kmem_cache_child_list(ulong
**cache_buf, ulong root)
> > >>> static ulong
> > >>> compound_head(ulong page)
> > >>> {
> > >>> - ulong flags, first_page, compound_head;
> > >>> + ulong flags, first_page, compound_head, info, mask;
> > >>>
> > >>> first_page = page;
> > >>>
> > >>> - if (VALID_MEMBER(page_compound_head)) {
> > >>> + if (VALID_MEMBER(page_compound_info)) {
> > >>> + if (readmem(page + OFFSET(page_compound_info), KVADDR,
&info,
> > >>> + sizeof(ulong), "page.compound_info",
RETURN_ON_ERROR)) {
> > >>> + if (compound_info_has_mask) {
> > >>> + mask = (info & 1) - 1;
> > >>> + mask |= info;
> > >>> + first_page = page & mask;
> > >>> + } else if (info & 1)
> > >>> + first_page = info - 1;
> > >>> + }
> > >>> + } else if (VALID_MEMBER(page_compound_head)) {
> > >>> if (readmem(page+OFFSET(page_compound_head), KVADDR,
&compound_head,
> > >>> sizeof(ulong), "page.compound_head",
RETURN_ON_ERROR)) {
> > >>> if (compound_head & 1)
> > >>> diff --git a/symbols.c b/symbols.c
> > >>> index 03511c8cbe8c..2071bdf77819 100644
> > >>> --- a/symbols.c
> > >>> +++ b/symbols.c
> > >>> @@ -10504,6 +10504,7 @@ dump_offset_table(char *spec, ulong
makestruct)
> > >>> OFFSET(page_active));
> > >>> fprintf(fp, " page_compound_head:
%ld\n",
> > >>> OFFSET(page_compound_head));
> > >>> + fprintf(fp, " page_compound_info: %ld\n",
OFFSET(page_compound_info));
> > >>> fprintf(fp, " page_private:
%ld\n", OFFSET(page_private));
> > >>> fprintf(fp, " page_page_type: %ld\n",
> > >>> OFFSET(page_page_type));
> > >> --
> > >> Crash-utility mailing list -- devel(a)lists.crash-utility.osci.io
> > >> To unsubscribe send an email to
devel-leave(a)lists.crash-utility.osci.io
> > >> https://${domain_name}/admin/lists/devel.lists.crash-utility.osci.io/
> > >> Contribution Guidelines:
https://github.com/crash-utility/crash/wiki
> > > --
> > > Crash-utility mailing list -- devel(a)lists.crash-utility.osci.io
> > > To unsubscribe send an email to devel-leave(a)lists.crash-utility.osci.io
> > > https://${domain_name}/admin/lists/devel.lists.crash-utility.osci.io/
> > > Contribution Guidelines:
https://github.com/crash-utility/crash/wiki
> > --
> > Crash-utility mailing list -- devel(a)lists.crash-utility.osci.io
> > To unsubscribe send an email to devel-leave(a)lists.crash-utility.osci.io
> > https://${domain_name}/admin/lists/devel.lists.crash-utility.osci.io/
> > Contribution Guidelines:
https://github.com/crash-utility/crash/wiki
> >
> --
> Crash-utility mailing list -- devel(a)lists.crash-utility.osci.io
> To unsubscribe send an email to devel-leave(a)lists.crash-utility.osci.io
> https://${domain_name}/admin/lists/devel.lists.crash-utility.osci.io/
> Contribution Guidelines:
https://github.com/crash-utility/crash/wiki