From 47d375ac822d413999c92520402c4868ce2275cc Mon Sep 17 00:00:00 2001 From: Kazuhito Hagio Date: Fri, 16 Dec 2022 14:03:46 +0900 Subject: [PATCH 60/89] SLUB: Fix for offset change of struct slab members on Linux 6.2-rc1 The following kernel commits split slab info from struct page into struct slab in Linux 5.17. d122019bf061 ("mm: Split slab into its own type") 07f910f9b729 ("mm: Remove slab from struct page") Crash commit 5f390ed811b0 followed the change for SLUB, but crash still uses the offset of page.lru inappropriately. Luckily, it could work because it was the same value as the offset of slab.slab_list until Linux 6.1. However, kernel commit 130d4df57390 ("mm/sl[au]b: rearrange struct slab fields to allow larger rcu_head") in Linux 6.2-rc1 changed the offset of slab.slab_list. As a result, without the patch, "kmem -s|-S" options print the following errors and fail to print values correctly for kernels configured with CONFIG_SLUB. crash> kmem -S filp CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME kmem: filp: partial list slab: ffffcc650405ab88 invalid page.inuse: -1 ffff8fa0401eca00 232 1267 1792 56 8k filp ... KMEM_CACHE_NODE NODE SLABS PARTIAL PER-CPU ffff8fa0401cb8c0 0 56 24 8 NODE 0 PARTIAL: SLAB MEMORY NODE TOTAL ALLOCATED FREE kmem: filp: invalid partial list slab pointer: ffffcc650405ab88 Signed-off-by: Kazuhito Hagio Signed-off-by: Lianbo Jiang --- defs.h | 1 + memory.c | 16 ++++++++++------ symbols.c | 1 + 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/defs.h b/defs.h index 9c91f38328d0..31702e707bee 100644 --- a/defs.h +++ b/defs.h @@ -2188,6 +2188,7 @@ struct offset_table { /* stash of commonly-used offsets */ long blk_mq_tags_rqs; long request_queue_hctx_table; long percpu_counter_counters; + long slab_slab_list; }; struct size_table { /* stash of commonly-used sizes */ diff --git a/memory.c b/memory.c index 9d003713534b..d05737cc1429 100644 --- a/memory.c +++ b/memory.c @@ -781,6 +781,8 @@ vm_init(void) if (INVALID_MEMBER(page_slab)) MEMBER_OFFSET_INIT(page_slab, "slab", "slab_cache"); + MEMBER_OFFSET_INIT(slab_slab_list, "slab", "slab_list"); + MEMBER_OFFSET_INIT(page_slab_page, "page", "slab_page"); if (INVALID_MEMBER(page_slab_page)) ANON_MEMBER_OFFSET_INIT(page_slab_page, "page", "slab_page"); @@ -19474,6 +19476,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node) { ulong next, last, list_head, flags; int first; + long list_off = VALID_MEMBER(slab_slab_list) ? OFFSET(slab_slab_list) : OFFSET(page_lru); if (!node_ptr) return; @@ -19487,7 +19490,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node) next == list_head ? " (empty)\n" : ""); first = 0; while (next != list_head) { - si->slab = last = next - OFFSET(page_lru); + si->slab = last = next - list_off; if (first++ == 0) fprintf(fp, " %s", slab_hdr); @@ -19510,7 +19513,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node) if (!IS_KVADDR(next) || ((next != list_head) && - !is_page_ptr(next - OFFSET(page_lru), NULL))) { + !is_page_ptr(next - list_off, NULL))) { error(INFO, "%s: partial list slab: %lx invalid page.lru.next: %lx\n", si->curname, last, next); @@ -19537,7 +19540,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node) next == list_head ? " (empty)\n" : ""); first = 0; while (next != list_head) { - si->slab = next - OFFSET(page_lru); + si->slab = next - list_off; if (first++ == 0) fprintf(fp, " %s", slab_hdr); @@ -19754,6 +19757,7 @@ count_partial(ulong node, struct meminfo *si, ulong *free) short inuse, objects; ulong total_inuse; ulong count = 0; + long list_off = VALID_MEMBER(slab_slab_list) ? OFFSET(slab_slab_list) : OFFSET(page_lru); count = 0; total_inuse = 0; @@ -19765,12 +19769,12 @@ count_partial(ulong node, struct meminfo *si, ulong *free) hq_open(); while (next != list_head) { - if (!readmem(next - OFFSET(page_lru) + OFFSET(page_inuse), + if (!readmem(next - list_off + OFFSET(page_inuse), KVADDR, &inuse, sizeof(ushort), "page.inuse", RETURN_ON_ERROR)) { hq_close(); return -1; } - last = next - OFFSET(page_lru); + last = next - list_off; if (inuse == -1) { error(INFO, @@ -19796,7 +19800,7 @@ count_partial(ulong node, struct meminfo *si, ulong *free) } if (!IS_KVADDR(next) || ((next != list_head) && - !is_page_ptr(next - OFFSET(page_lru), NULL))) { + !is_page_ptr(next - list_off, NULL))) { error(INFO, "%s: partial list slab: %lx invalid page.lru.next: %lx\n", si->curname, last, next); break; diff --git a/symbols.c b/symbols.c index d1b35a56aa71..9e6fca73eaf9 100644 --- a/symbols.c +++ b/symbols.c @@ -9722,6 +9722,7 @@ dump_offset_table(char *spec, ulong makestruct) OFFSET(slab_inuse)); fprintf(fp, " slab_free: %ld\n", OFFSET(slab_free)); + fprintf(fp, " slab_slab_list: %ld\n", OFFSET(slab_slab_list)); fprintf(fp, " kmem_cache_size: %ld\n", OFFSET(kmem_cache_size)); -- 2.37.1