From 744dfa3a190d3dd2b1cc42d3378a1cb299958c0a Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 18 May 2026 19:31:38 +0800 Subject: [PATCH 12/39] add folio_order function The folio_order() has three versions: 1.) In verion 1, folio_order() uses page[1].compound_order to get the folio order. We use "folio_batch" as the indicator. Please refer to patch set: https://lore.kernel.org/all/20211208042256.1923824-1-willy@infradead.org/ 2.) In version 2, the following patch introduces _folio_order: c3a15bff46cb5149 "mm: reimplement folio_order() and folio_nr_pages()" We use "_folio_order" as the indicator. Please refer to patch set: https://lore.kernel.org/all/20220808193430.3378317-1-willy@infradead.org/ 3.) In version 3, the following patch replaces the _folio_order with _flags_1: ebc1baf5c9b46c22 "mm: free up a word in the first tail page" folio_order() uses _flags_1 to get the folio order. We use "free_huge_folio" as the indicator. Please refer to patch set: https://lore.kernel.org/linux-mm/20230816151201.3655946-1-willy@infradead.org/ (Note, we do not use the struct modifications within the patch set as the indicator, since they have been removed in later kernel.) This patch will be used in later patches. Signed-off-by: Huang Shijie --- defs.h | 8 ++++++ memory.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ symbols.c | 6 +++++ 3 files changed, 93 insertions(+) diff --git a/defs.h b/defs.h index 89044b18cdbe..bd996ef38707 100644 --- a/defs.h +++ b/defs.h @@ -2291,6 +2291,9 @@ struct offset_table { /* stash of commonly-used offsets */ long hrtimer_clock_base_index; long klp_patch_list; long tk_data_timekeeper; + long page_compound_order; + long folio__folio_order; + long folio__flags_1; }; struct size_table { /* stash of commonly-used sizes */ @@ -2470,6 +2473,9 @@ struct size_table { /* stash of commonly-used sizes */ long cpumask_t; long task_struct_exit_state; long bpf_ringbuf_map; + long page_compound_order; + long folio__folio_order; + long folio__flags_1; }; struct array_table { @@ -5998,6 +6004,8 @@ ulong do_xarray(ulong, int, struct list_pair *); #define XARRAY_TAG_MASK (3UL) #define XARRAY_TAG_INTERNAL (2UL) +int folio_order(ulong folio); + int file_dump(ulong, ulong, ulong, int, int); #define DUMP_FULL_NAME 0x1 #define DUMP_INODE_ONLY 0x2 diff --git a/memory.c b/memory.c index 17423a588464..502f8fdd0ea7 100644 --- a/memory.c +++ b/memory.c @@ -410,6 +410,10 @@ mem_init(void) DISPLAY_DEFAULT = (sizeof(long) == 8) ? DISPLAY_64 : DISPLAY_32; } +#define FOLIO_ORDER_V1 1 +#define FOLIO_ORDER_V2 2 +#define FOLIO_ORDER_V3 3 +static int folio_order_version; /* * Stash a few popular offsets and some basic kernel virtual memory @@ -547,6 +551,37 @@ vm_init(void) MEMBER_OFFSET_INIT(page_freelist, "page", "freelist"); MEMBER_OFFSET_INIT(page_page_type, "page", "page_type"); + /* + * The "folio_batch" was introduced at patch set: + * https://lore.kernel.org/all/20211208042256.1923824-1-willy@infradead.org/ + * Use it as the indicator for folio_order() version 1. + */ + if (STRUCT_EXISTS("folio_batch")) + folio_order_version = FOLIO_ORDER_V1; + + MEMBER_OFFSET_INIT(page_compound_order, "page", "compound_order"); + MEMBER_SIZE_INIT(page_compound_order, "page", "compound_order"); + + /* + * The "_folio_order" was introduced at patch set: + * https://lore.kernel.org/all/20220808193430.3378317-1-willy@infradead.org/ + * Use it as the indicator for folio_order() version 2. + */ + MEMBER_SIZE_INIT(folio__folio_order, "folio", "_folio_order"); + MEMBER_OFFSET_INIT(folio__folio_order, "folio", "_folio_order"); + if (VALID_MEMBER(folio__folio_order)) + folio_order_version = FOLIO_ORDER_V2; + + /* + * The "free_huge_folio()" was introduced at patch set: + * https://lore.kernel.org/linux-mm/20230816151201.3655946-1-willy@infradead.org/ + * Use it as the indicator for folio_order() version 3. + */ + MEMBER_OFFSET_INIT(folio__flags_1, "folio", "_flags_1"); + MEMBER_SIZE_INIT(folio__flags_1, "folio", "_flags_1"); + if (kernel_symbol_exists("free_huge_folio")) + folio_order_version = FOLIO_ORDER_V3; + MEMBER_OFFSET_INIT(mm_struct_pgd, "mm_struct", "pgd"); MEMBER_OFFSET_INIT(swap_info_struct_swap_file, @@ -20426,6 +20461,50 @@ static unsigned int oo_objects(ulong oo) return (oo & ((1 << 16) - 1)); } +int +folio_order(ulong folio) +{ + ulong v = 0; + int PG_head = 16; + + if (folio_order_version == FOLIO_ORDER_V1) { + readmem(folio + OFFSET(page_flags), KVADDR, &v, sizeof(ulong), + "folio.page.flags", FAULT_ON_ERROR); + if (!(v & (1 << PG_head))) + return 0; + + readmem(folio + SIZE(page) + OFFSET(page_compound_order), KVADDR, &v, + SIZE(page_compound_order), "page[1].compound_order", FAULT_ON_ERROR); + + return v; + } else if (folio_order_version == FOLIO_ORDER_V2) { + readmem(folio + OFFSET(page_flags), KVADDR, &v, sizeof(ulong), + "folio.page.flags", FAULT_ON_ERROR); + if (!(v & (1 << PG_head))) + return 0; + + readmem(folio + OFFSET(folio__folio_order), KVADDR, &v, + SIZE(folio__folio_order), "folio->_folio_order", FAULT_ON_ERROR); + + return v; + } else if (folio_order_version == FOLIO_ORDER_V3) { + /* The PG_head changes to bit 6 in this version */ + PG_head = 6; + + readmem(folio + OFFSET(page_flags), KVADDR, &v, sizeof(ulong), + "folio.page.flags", FAULT_ON_ERROR); + if (!(v & (1 << PG_head))) + return 0; + + readmem(folio + OFFSET(folio__flags_1), KVADDR, &v, + SIZE(folio__flags_1), "folio->_flags_1", FAULT_ON_ERROR); + + return v & 0xff; + } else { + return 0; + } +} + #ifdef NOT_USED ulong slab_to_kmem_cache_node(struct meminfo *si, ulong slab_page) diff --git a/symbols.c b/symbols.c index 3c62f54d4a93..c0285058c5cb 100644 --- a/symbols.c +++ b/symbols.c @@ -10462,6 +10462,9 @@ dump_offset_table(char *spec, ulong makestruct) fprintf(fp, " page_private: %ld\n", OFFSET(page_private)); fprintf(fp, " page_page_type: %ld\n", OFFSET(page_page_type)); + fprintf(fp, " page_compound_order: %ld\n", OFFSET(page_compound_order)); + fprintf(fp, " folio__folio_order: %ld\n", OFFSET(folio__folio_order)); + fprintf(fp, " folio__flags_1: %ld\n", OFFSET(folio__flags_1)); fprintf(fp, " trace_print_flags_mask: %ld\n", OFFSET(trace_print_flags_mask)); @@ -11972,6 +11975,9 @@ dump_offset_table(char *spec, ulong makestruct) fprintf(fp, "\n size_table:\n"); fprintf(fp, " page: %ld\n", SIZE(page)); fprintf(fp, " page_flags: %ld\n", SIZE(page_flags)); + fprintf(fp, " page_compound_order: %ld\n", SIZE(page_compound_order)); + fprintf(fp, " folio__folio_order: %ld\n", SIZE(folio__folio_order)); + fprintf(fp, " folio__flags_1: %ld\n", SIZE(folio__flags_1)); fprintf(fp, " trace_print_flags: %ld\n", SIZE(trace_print_flags)); fprintf(fp, " free_area_struct: %ld\n", SIZE(free_area_struct)); -- 2.54.0