Add Kairui and Baoquan who could help to review this patch
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)))
> + 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