The folio_order() was introduced to kernel at v5.16, but the first
large folio support patch is in v5.17:
6795801366da "xfs: Support large folios"
The folio_order() keeps the same logic as kernel code
in different versions:
1.) In kernel v5.17, folio_order() uses page[1].compound_order to
get the folio order.
2.) In kernel v6.1, the following patch introduces _folio_order:
c3a15bff46cb5149 "mm: reimplement folio_order() and folio_nr_pages()"
folio_order() uses _folio_order to get the folio order.
3.) In kernel v6.6, 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.
This patch will be used in later patches.
Signed-off-by: Huang Shijie <huangsj(a)hygon.cn>
---
defs.h | 8 +++++++
memory.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
symbols.c | 6 +++++
3 files changed, 84 insertions(+)
diff --git a/defs.h b/defs.h
index 8f6784e..e832ea6 100644
--- a/defs.h
+++ b/defs.h
@@ -2290,6 +2290,9 @@ struct offset_table { /* stash of commonly-used
offsets */
long bpf_ringbuf_nr_pages;
long hrtimer_clock_base_index;
long klp_patch_list;
+ long page_compound_order;
+ long folio__folio_order;
+ long folio__flags_1;
};
struct size_table { /* stash of commonly-used sizes */
@@ -2469,6 +2472,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 {
@@ -6008,6 +6014,8 @@ ulong do_xarray(ulong, int, struct list_pair *, int);
#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 17423a5..3b272ad 100644
--- a/memory.c
+++ b/memory.c
@@ -547,6 +547,13 @@ vm_init(void)
MEMBER_OFFSET_INIT(page_freelist, "page", "freelist");
MEMBER_OFFSET_INIT(page_page_type, "page", "page_type");
+ MEMBER_OFFSET_INIT(page_compound_order, "page", "compound_order");
+ MEMBER_SIZE_INIT(page_compound_order, "page", "compound_order");
+ MEMBER_OFFSET_INIT(folio__folio_order, "folio", "_folio_order");
+ MEMBER_SIZE_INIT(folio__folio_order, "folio", "_folio_order");
+ MEMBER_OFFSET_INIT(folio__flags_1, "folio", "_flags_1");
+ MEMBER_SIZE_INIT(folio__flags_1, "folio", "_flags_1");
+
MEMBER_OFFSET_INIT(mm_struct_pgd, "mm_struct", "pgd");
MEMBER_OFFSET_INIT(swap_info_struct_swap_file,
@@ -20426,6 +20433,69 @@ static unsigned int oo_objects(ulong oo)
return (oo & ((1 << 16) - 1));
}
+/*
+ * The folio_order() was introduced to kernel at v5.16, but the first
+ * large folio support patch is in v5.17:
+ * 6795801366da "xfs: Support large folios"
+ *
+ * 1.) In kernel v5.17, folio_order() uses page[1].compound_order to
+ * get the folio order.
+ *
+ * 2.) In kernel v6.1, the following patch introduces _folio_order:
+ * c3a15bff46cb5149 "mm: reimplement folio_order() and folio_nr_pages()"
+ *
+ * folio_order() uses _folio_order to get the folio order.
+ *
+ * 3.) In kernel v6.6, 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.
+ */
+int
+folio_order(ulong folio)
+{
+ ulong v = 0;
+ int PG_head = 16;
+
+ if (THIS_KERNEL_VERSION < LINUX(5,17,0))
+ return 0;
+
+ if (THIS_KERNEL_VERSION < LINUX(6,1,0)) {
+ 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 (THIS_KERNEL_VERSION < LINUX(6,6,0)) {
+ 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 {
+ /* The PG_head changes to bit 6 at kernel v6.6 */
+ 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;
+ }
+}
+
#ifdef NOT_USED
ulong
slab_to_kmem_cache_node(struct meminfo *si, ulong slab_page)
diff --git a/symbols.c b/symbols.c
index e6865ca..08c07e9 100644
--- a/symbols.c
+++ b/symbols.c
@@ -10451,6 +10451,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));
@@ -11961,6 +11964,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.43.0