150 lines
5.3 KiB
Diff
150 lines
5.3 KiB
Diff
|
From 47d375ac822d413999c92520402c4868ce2275cc Mon Sep 17 00:00:00 2001
|
||
|
From: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||
|
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 <k-hagio-ab@nec.com>
|
||
|
Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
|
||
|
---
|
||
|
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
|
||
|
|