e83d5f939a
Release: crash-8.0.5-2 Resolves: RHEL-43414 Signed-off-by: Tao Liu <ltao@redhat.com>
305 lines
9.7 KiB
Diff
305 lines
9.7 KiB
Diff
From 7c2c90d0b06a0dad00819b7f22be204664a698ff Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?HAGIO=20KAZUHITO=28=E8=90=A9=E5=B0=BE=E3=80=80=E4=B8=80?=
|
|
=?UTF-8?q?=E4=BB=81=29?= <k-hagio-ab@nec.com>
|
|
Date: Wed, 5 Jun 2024 07:30:03 +0000
|
|
Subject: [PATCH 6/9] Fix "kmem -v" option on Linux 6.9 and later kernels
|
|
|
|
The following kernel commits removed vmap_area_list and vmap_area_root
|
|
rb-tree, and introduced vmap_nodes.
|
|
|
|
55c49fee57af mm/vmalloc: remove vmap_area_list
|
|
d093602919ad mm: vmalloc: remove global vmap_area_root rb-tree
|
|
|
|
Without the patch, the "kmem -v" option and functions that use
|
|
dump_vmlist() fail with or without an error:
|
|
|
|
crash> kmem -v
|
|
VM_STRUCT ADDRESS RANGE SIZE
|
|
kmem: invalid kernel virtual address: ccccccccccccccd4 type: "vmlist addr"
|
|
|
|
crash> kmem -v
|
|
crash>
|
|
|
|
Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
|
|
---
|
|
defs.h | 4 ++
|
|
memory.c | 135 +++++++++++++++++++++++++++++++++++++++++++++---------
|
|
symbols.c | 3 ++
|
|
3 files changed, 120 insertions(+), 22 deletions(-)
|
|
|
|
diff --git a/defs.h b/defs.h
|
|
index 42d8759..da856c0 100644
|
|
--- a/defs.h
|
|
+++ b/defs.h
|
|
@@ -2240,6 +2240,8 @@ struct offset_table { /* stash of commonly-used offsets */
|
|
long mnt_namespace_nr_mounts;
|
|
long mount_mnt_node;
|
|
long log_caller_id;
|
|
+ long vmap_node_busy;
|
|
+ long rb_list_head;
|
|
};
|
|
|
|
struct size_table { /* stash of commonly-used sizes */
|
|
@@ -2415,6 +2417,7 @@ struct size_table { /* stash of commonly-used sizes */
|
|
long maple_node;
|
|
long module_memory;
|
|
long fred_frame;
|
|
+ long vmap_node;
|
|
};
|
|
|
|
struct array_table {
|
|
@@ -2679,6 +2682,7 @@ struct vm_table { /* kernel VM-related data */
|
|
#define SLAB_OVERLOAD_PAGE (0x8000000)
|
|
#define SLAB_CPU_CACHE (0x10000000)
|
|
#define SLAB_ROOT_CACHES (0x20000000)
|
|
+#define USE_VMAP_NODES (0x40000000)
|
|
|
|
#define IS_FLATMEM() (vt->flags & FLATMEM)
|
|
#define IS_DISCONTIGMEM() (vt->flags & DISCONTIGMEM)
|
|
diff --git a/memory.c b/memory.c
|
|
index 34ed646..acb8507 100644
|
|
--- a/memory.c
|
|
+++ b/memory.c
|
|
@@ -235,6 +235,7 @@ static void dump_slab_objects(struct meminfo *);
|
|
static void dump_slab_objects_percpu(struct meminfo *);
|
|
static void dump_vmlist(struct meminfo *);
|
|
static void dump_vmap_area(struct meminfo *);
|
|
+static int get_vmap_area_list_from_nodes(ulong **);
|
|
static int dump_page_lists(struct meminfo *);
|
|
static void dump_kmeminfo(void);
|
|
static int page_to_phys(ulong, physaddr_t *);
|
|
@@ -433,9 +434,15 @@ vm_init(void)
|
|
if (VALID_MEMBER(vmap_area_va_start) &&
|
|
VALID_MEMBER(vmap_area_va_end) &&
|
|
VALID_MEMBER(vmap_area_list) &&
|
|
- VALID_MEMBER(vmap_area_vm) &&
|
|
- kernel_symbol_exists("vmap_area_list"))
|
|
- vt->flags |= USE_VMAP_AREA;
|
|
+ VALID_MEMBER(vmap_area_vm)) {
|
|
+ if (kernel_symbol_exists("vmap_nodes")) {
|
|
+ STRUCT_SIZE_INIT(vmap_node, "vmap_node");
|
|
+ MEMBER_OFFSET_INIT(vmap_node_busy, "vmap_node", "busy");
|
|
+ MEMBER_OFFSET_INIT(rb_list_head, "rb_list", "head");
|
|
+ vt->flags |= USE_VMAP_NODES;
|
|
+ } else if (kernel_symbol_exists("vmap_area_list"))
|
|
+ vt->flags |= USE_VMAP_AREA;
|
|
+ }
|
|
|
|
if (kernel_symbol_exists("hstates")) {
|
|
STRUCT_SIZE_INIT(hstate, "hstate");
|
|
@@ -8957,7 +8964,7 @@ dump_vmlist(struct meminfo *vi)
|
|
physaddr_t paddr;
|
|
int mod_vmlist;
|
|
|
|
- if (vt->flags & USE_VMAP_AREA) {
|
|
+ if (vt->flags & (USE_VMAP_AREA|USE_VMAP_NODES)) {
|
|
dump_vmap_area(vi);
|
|
return;
|
|
}
|
|
@@ -9067,6 +9074,77 @@ next_entry:
|
|
vi->retval = verified;
|
|
}
|
|
|
|
+static int
|
|
+sort_by_va_start(const void *arg1, const void *arg2)
|
|
+{
|
|
+ ulong va_start1, va_start2;
|
|
+
|
|
+ readmem(*(ulong *)arg1 + OFFSET(vmap_area_va_start), KVADDR, &va_start1,
|
|
+ sizeof(void *), "vmap_area.va_start", FAULT_ON_ERROR);
|
|
+ readmem(*(ulong *)arg2 + OFFSET(vmap_area_va_start), KVADDR, &va_start2,
|
|
+ sizeof(void *), "vmap_area.va_start", FAULT_ON_ERROR);
|
|
+
|
|
+ return va_start1 < va_start2 ? -1 : (va_start1 == va_start2 ? 0 : 1);
|
|
+}
|
|
+
|
|
+/* Linux 6.9 and later kernels use "vmap_nodes". */
|
|
+static int
|
|
+get_vmap_area_list_from_nodes(ulong **list_ptr)
|
|
+{
|
|
+ int i, cnt, c;
|
|
+ struct list_data list_data, *ld = &list_data;
|
|
+ uint nr_vmap_nodes;
|
|
+ ulong vmap_nodes, list_head;
|
|
+ ulong *list, *ptr;
|
|
+
|
|
+ get_symbol_data("nr_vmap_nodes", sizeof(uint), &nr_vmap_nodes);
|
|
+ get_symbol_data("vmap_nodes", sizeof(ulong), &vmap_nodes);
|
|
+
|
|
+ /* count up all vmap_areas. */
|
|
+ cnt = 0;
|
|
+ for (i = 0; i < nr_vmap_nodes; i++) {
|
|
+ BZERO(ld, sizeof(struct list_data));
|
|
+ list_head = vmap_nodes + SIZE(vmap_node) * i +
|
|
+ OFFSET(vmap_node_busy) + OFFSET(rb_list_head);
|
|
+ readmem(list_head, KVADDR, &ld->start, sizeof(void *),
|
|
+ "rb_list.head", FAULT_ON_ERROR);
|
|
+ ld->list_head_offset = OFFSET(vmap_area_list);
|
|
+ ld->end = list_head;
|
|
+ c = do_list(ld);
|
|
+ if (c < 0)
|
|
+ return -1;
|
|
+
|
|
+ cnt += c;
|
|
+ }
|
|
+
|
|
+ list = ptr = (ulong *)GETBUF(sizeof(void *) * cnt);
|
|
+
|
|
+ /* gather all vmap_areas into a list. */
|
|
+ for (i = 0; i < nr_vmap_nodes; i++) {
|
|
+ BZERO(ld, sizeof(struct list_data));
|
|
+ ld->flags = LIST_ALLOCATE;
|
|
+ list_head = vmap_nodes + SIZE(vmap_node) * i +
|
|
+ OFFSET(vmap_node_busy) + OFFSET(rb_list_head);
|
|
+ readmem(list_head, KVADDR, &ld->start, sizeof(void *),
|
|
+ "rb_list.head", FAULT_ON_ERROR);
|
|
+ ld->list_head_offset = OFFSET(vmap_area_list);
|
|
+ ld->end = list_head;
|
|
+ c = do_list(ld);
|
|
+ if (c < 0)
|
|
+ return -1;
|
|
+
|
|
+ memcpy(ptr, ld->list_ptr, sizeof(void *) * c);
|
|
+ ptr += c;
|
|
+
|
|
+ FREEBUF(ld->list_ptr);
|
|
+ }
|
|
+
|
|
+ qsort(list, cnt, sizeof(void *), sort_by_va_start);
|
|
+
|
|
+ *list_ptr = list;
|
|
+ return cnt;
|
|
+}
|
|
+
|
|
static void
|
|
dump_vmap_area(struct meminfo *vi)
|
|
{
|
|
@@ -9080,26 +9158,37 @@ dump_vmap_area(struct meminfo *vi)
|
|
char buf2[BUFSIZE];
|
|
char buf3[BUFSIZE];
|
|
char buf4[BUFSIZE];
|
|
+ ulong *list_ptr;
|
|
|
|
#define VM_VM_AREA 0x4 /* mm/vmalloc.c */
|
|
|
|
- vmap_area_buf = GETBUF(SIZE(vmap_area));
|
|
start = count = verified = size = 0;
|
|
|
|
- ld = &list_data;
|
|
- BZERO(ld, sizeof(struct list_data));
|
|
- ld->flags = LIST_HEAD_FORMAT|LIST_HEAD_POINTER|LIST_ALLOCATE;
|
|
- get_symbol_data("vmap_area_list", sizeof(void *), &ld->start);
|
|
- ld->list_head_offset = OFFSET(vmap_area_list);
|
|
- ld->end = symbol_value("vmap_area_list");
|
|
- cnt = do_list(ld);
|
|
- if (cnt < 0) {
|
|
- FREEBUF(vmap_area_buf);
|
|
- error(WARNING, "invalid/corrupt vmap_area_list\n");
|
|
- vi->retval = 0;
|
|
- return;
|
|
+ if (vt->flags & USE_VMAP_NODES) {
|
|
+ cnt = get_vmap_area_list_from_nodes(&list_ptr);
|
|
+ if (cnt < 0) {
|
|
+ error(WARNING, "invalid/corrupt vmap_nodes.busy list\n");
|
|
+ vi->retval = 0;
|
|
+ return;
|
|
+ }
|
|
+ } else {
|
|
+ ld = &list_data;
|
|
+ BZERO(ld, sizeof(struct list_data));
|
|
+ ld->flags = LIST_HEAD_FORMAT|LIST_HEAD_POINTER|LIST_ALLOCATE;
|
|
+ get_symbol_data("vmap_area_list", sizeof(void *), &ld->start);
|
|
+ ld->list_head_offset = OFFSET(vmap_area_list);
|
|
+ ld->end = symbol_value("vmap_area_list");
|
|
+ cnt = do_list(ld);
|
|
+ if (cnt < 0) {
|
|
+ error(WARNING, "invalid/corrupt vmap_area_list\n");
|
|
+ vi->retval = 0;
|
|
+ return;
|
|
+ }
|
|
+ list_ptr = ld->list_ptr;
|
|
}
|
|
|
|
+ vmap_area_buf = GETBUF(SIZE(vmap_area));
|
|
+
|
|
for (i = 0; i < cnt; i++) {
|
|
if (!(pc->curcmd_flags & HEADER_PRINTED) && (i == 0) &&
|
|
!(vi->flags & (GET_HIGHEST|GET_PHYS_TO_VMALLOC|
|
|
@@ -9116,7 +9205,7 @@ dump_vmap_area(struct meminfo *vi)
|
|
pc->curcmd_flags |= HEADER_PRINTED;
|
|
}
|
|
|
|
- readmem(ld->list_ptr[i], KVADDR, vmap_area_buf,
|
|
+ readmem(list_ptr[i], KVADDR, vmap_area_buf,
|
|
SIZE(vmap_area), "vmap_area struct", FAULT_ON_ERROR);
|
|
|
|
if (VALID_MEMBER(vmap_area_flags) &&
|
|
@@ -9158,7 +9247,7 @@ dump_vmap_area(struct meminfo *vi)
|
|
}
|
|
fprintf(fp, "%s%s %s%s %s - %s %7ld\n",
|
|
mkstring(buf1,VADDR_PRLEN, LONG_HEX|CENTER|LJUST,
|
|
- MKSTR(ld->list_ptr[i])), space(MINSPACE-1),
|
|
+ MKSTR(list_ptr[i])), space(MINSPACE-1),
|
|
mkstring(buf2,VADDR_PRLEN, LONG_HEX|CENTER|LJUST,
|
|
MKSTR(vm_struct)), space(MINSPACE-1),
|
|
mkstring(buf3, VADDR_PRLEN, LONG_HEX|RJUST,
|
|
@@ -9179,14 +9268,14 @@ dump_vmap_area(struct meminfo *vi)
|
|
if (vi->flags & GET_PHYS_TO_VMALLOC) {
|
|
vi->retval = pcheck +
|
|
PAGEOFFSET(vi->spec_addr);
|
|
- FREEBUF(ld->list_ptr);
|
|
+ FREEBUF(list_ptr);
|
|
return;
|
|
} else
|
|
fprintf(fp,
|
|
"%s%s %s%s %s - %s %7ld\n",
|
|
mkstring(buf1,VADDR_PRLEN,
|
|
LONG_HEX|CENTER|LJUST,
|
|
- MKSTR(ld->list_ptr[i])),
|
|
+ MKSTR(list_ptr[i])),
|
|
space(MINSPACE-1),
|
|
mkstring(buf2, VADDR_PRLEN,
|
|
LONG_HEX|CENTER|LJUST,
|
|
@@ -9204,7 +9293,7 @@ dump_vmap_area(struct meminfo *vi)
|
|
}
|
|
|
|
FREEBUF(vmap_area_buf);
|
|
- FREEBUF(ld->list_ptr);
|
|
+ FREEBUF(list_ptr);
|
|
|
|
if (vi->flags & GET_HIGHEST)
|
|
vi->retval = start+size;
|
|
@@ -14001,6 +14090,8 @@ dump_vm_table(int verbose)
|
|
fprintf(fp, "%sSLAB_ROOT_CACHES", others++ ? "|" : "");\
|
|
if (vt->flags & USE_VMAP_AREA)
|
|
fprintf(fp, "%sUSE_VMAP_AREA", others++ ? "|" : "");\
|
|
+ if (vt->flags & USE_VMAP_NODES)
|
|
+ fprintf(fp, "%sUSE_VMAP_NODES", others++ ? "|" : "");\
|
|
if (vt->flags & CONFIG_NUMA)
|
|
fprintf(fp, "%sCONFIG_NUMA", others++ ? "|" : "");\
|
|
if (vt->flags & VM_EVENT)
|
|
diff --git a/symbols.c b/symbols.c
|
|
index 301ce35..107920f 100644
|
|
--- a/symbols.c
|
|
+++ b/symbols.c
|
|
@@ -10167,6 +10167,8 @@ dump_offset_table(char *spec, ulong makestruct)
|
|
fprintf(fp, " vmap_area_flags: %ld\n",
|
|
OFFSET(vmap_area_flags));
|
|
fprintf(fp, " vmap_area_purge_list: %ld\n", OFFSET(vmap_area_purge_list));
|
|
+ fprintf(fp, " vmap_node_busy: %ld\n", OFFSET(vmap_node_busy));
|
|
+ fprintf(fp, " rb_list_head: %ld\n", OFFSET(rb_list_head));
|
|
|
|
fprintf(fp, " module_size_of_struct: %ld\n",
|
|
OFFSET(module_size_of_struct));
|
|
@@ -12041,6 +12043,7 @@ dump_offset_table(char *spec, ulong makestruct)
|
|
SIZE(task_group));
|
|
fprintf(fp, " vmap_area: %ld\n",
|
|
SIZE(vmap_area));
|
|
+ fprintf(fp, " vmap_node: %ld\n", SIZE(vmap_node));
|
|
fprintf(fp, " hrtimer_clock_base: %ld\n",
|
|
SIZE(hrtimer_clock_base));
|
|
fprintf(fp, " hrtimer_base: %ld\n",
|
|
--
|
|
2.40.1
|
|
|