Re: [PATCH] Reapply "vmcoreinfo: read vmcoreinfo using 'vmcoreinfo_data' when unavailable in elf note"
by Misbah Anjum N
> Commit 7636c13 ("vmcoreinfo: read vmcoreinfo using 'vmcoreinfo_data'
> when unavailable in elf note") moved the vmcoreinfo reading to always
> read from memory instead of relying on diskdump/netdump's local
> handlers. This was later reverted to fix regression in X86_64 kslar
> images.
>
> Reintroduce the `vmcoreinfo_read_from_memory` as fallback to
> diskdump/netdump vmcores.
>
> This reverts commit 72e2776caf1ca41dffcc8aba11c55c636565725b.
>
> Cc: Aditya Gupta <adityag(a)linux.ibm.com>
> Cc: Tao Liu <ltao(a)redhat.com>
> Signed-off-by: Shivang Upadhyay <shivangu(a)linux.ibm.com>
Tested-by: Misbah Anjum N <misanjum(a)linux.ibm.com>
Hi,
I have tested this patch successfully on the following platform:
Platform: IBM PowerPC 64LE (PPC64LE)
Architecture: ppc64le
Host Kernel: 6.18.0-8-generic
Guest Kernel: 6.18.0-8-generic
OS: Ubuntu 26.04 (Resolute Raccoon)
Crash version: 9.0.1 (patched)
Compiler: gcc 15.2.0
GDB version: 16.2 (embedded)
Test cases verified:
--------------------
1. virsh dump --memory-only (elf, kdump-zlib compression)
2. virsh dump --memory-only --bypass-cache (elf, kdump-zlib compression)
Test results:
------------
- Patch applied cleanly to crash-9.0.1 (with offsets)
- Build completed successfully with all dependencies
- vmcoreinfo_read_from_memory fallback is active in diskdump.c and netdump.c
- Successfully reads vmcoreinfo from memory when ELF note method is unavailable
- Resolves the X86_64 kslar image regression
- No regressions detected
Test logs (trimmed):
-------------------
# virsh dump ubuntu2604 vmcore-mem --memory-only
Domain 'ubuntu2604' dumped to vmcore-mem
# crash /usr/lib/debug/boot/vmlinux-6.18.0-8-generic vmcore-mem
crash 9.0.1
...
KERNEL: /usr/lib/debug/boot/vmlinux-6.18.0-8-generic
DUMPFILE: vmcore-mem
...
crash> bt
PID: 0 TASK: c0000000038b1580 CPU: 0 COMMAND: "swapper/0"
[NIP : plpar_hcall_norets_notrace+24]
[LR : check_and_cede_processor+72]
...
The patch works as intended and fixes the vmcoreinfo reading issue.
Thanks,
Misbah Anjum N
1 month
[PATCH RFC] sys: Display livepatch transition status in KERNEL line
by Motomasa Suzuki
This commit enhances the 'sys' command to show if a kernel livepatch is
currently in a transition phase, directly within the KERNEL output line.
Currently, diagnosing system state during or immediately after livepatch
operations can be ambiguous. While 'livepatch' is indicated by
'[LIVEPATCH]', there's no direct indicator within 'crash' itself to show
if a livepatch is actively applying, reverting, or in some other
transient state. This lack of immediate visibility can complicate crash
analysis, as the system might be in an inconsistent state due to an
ongoing patch application/reversion.
This change introduces a new '[TRANSITION]' flag which appears next to
'[LIVEPATCH]' and '[TAINTED]' in the 'sys' command output. This flag is
set if the livepatch subsystem indicates an in-progress transition
(e.g., as exposed via '/sys/kernel/livepatch/<patch_name>/transition').
Example 'sys' output with this change:
KERNEL: /usr/lib/debug/lib/modules/<version_name>/vmlinux [LIVEPATCH]
[TRANSITION] [TAINTED]
This enhancement provides critical, at-a-glance information for
developers and administrators, allowing them to quickly ascertain if
ongoing livepatch activity might be influencing a system's behavior
during crash investigations. It directly leverages existing kernel
livepatch status infrastructure to enrich the crash utility's diagnostic
capabilities.
Signed-off-by: Motomasa Suzuki <suzuki.motomasa(a)fujitsu.com>
---
defs.h | 1 +
kernel.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/defs.h b/defs.h
index ab4aee8..b459d4d 100644
--- a/defs.h
+++ b/defs.h
@@ -2280,6 +2280,7 @@ struct offset_table { /* stash of commonly-used offsets */
long bpf_ringbuf_map_rb;
long bpf_ringbuf_consumer_pos;
long bpf_ringbuf_nr_pages;
+ long klp_patch_list;
};
struct size_table { /* stash of commonly-used sizes */
diff --git a/kernel.c b/kernel.c
index 13f3374..1ca18e4 100644
--- a/kernel.c
+++ b/kernel.c
@@ -461,7 +461,10 @@ kernel_init()
error(WARNING,
"list_head.next offset: %ld: list command may fail\n",
OFFSET(list_head_next));
-
+ if (STRUCT_EXISTS("klp_patch")) {
+ if (MEMBER_EXISTS("klp_patch", "list"))
+ MEMBER_OFFSET_INIT(klp_patch_list, "klp_patch", "list");
+ }
MEMBER_OFFSET_INIT(hlist_node_next, "hlist_node", "next");
MEMBER_OFFSET_INIT(hlist_node_pprev, "hlist_node", "pprev");
STRUCT_SIZE_INIT(hlist_head, "hlist_head");
@@ -5681,6 +5684,48 @@ is_livepatch(void)
return FALSE;
}
+#define KLP_PATCH_ITER_LIMIT 1024
+
+static int
+is_livepatch_transition(void)
+{
+ struct kernel_list_head head;
+ struct kernel_list_head node;
+ ulong transition_patch;
+ ulong list_addr;
+ ulong current;
+ ulong patch_addr;
+ int loops;
+
+ if (!try_get_symbol_data("klp_transition_patch", sizeof(ulong),
+ &transition_patch) || !transition_patch)
+ return FALSE;
+
+ if (!kernel_symbol_exists("klp_patches") || !VALID_MEMBER(klp_patch_list))
+ return FALSE;
+
+ list_addr = symbol_value("klp_patches");
+ if (!readmem(list_addr, KVADDR, &head, sizeof(head), "klp_patches",
+ RETURN_ON_ERROR | QUIET))
+ return FALSE;
+
+ for (current = (ulong)head.next, loops = 0;
+ current && current != list_addr && loops < KLP_PATCH_ITER_LIMIT;
+ current = (ulong)node.next, loops++) {
+
+ if (!readmem(list_addr, KVADDR, &head, sizeof(head),
+ "klp_patch list entry", RETURN_ON_ERROR | QUIET))
+ return FALSE;
+
+ patch_addr = current - (ulong)OFFSET(klp_patch_list);
+
+ if (patch_addr == transition_patch)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/*
* Display system stats at init-time or for the sys command.
*/
@@ -5724,17 +5769,19 @@ display_sys_stats(void)
}
} else {
if (pc->system_map) {
- fprintf(fp, " SYSTEM MAP: %s%s%s\n", pc->system_map,
+ fprintf(fp, " SYSTEM MAP: %s%s%s%s\n", pc->system_map,
is_livepatch() ? " [LIVEPATCH]" : "",
+ is_livepatch_transition() ? " [TRANSITION]" : "",
is_kernel_tainted() ? " [TAINTED]" : "");
fprintf(fp, "DEBUG KERNEL: %s %s\n",
pc->namelist_orig ?
pc->namelist_orig : pc->namelist,
debug_kernel_version(pc->namelist));
} else
- fprintf(fp, " KERNEL: %s%s%s\n", pc->namelist_orig ?
+ fprintf(fp, " KERNEL: %s%s%s%s\n", pc->namelist_orig ?
pc->namelist_orig : pc->namelist,
is_livepatch() ? " [LIVEPATCH]" : "",
+ is_livepatch_transition() ? " [TRANSITION]" : "",
is_kernel_tainted() ? " [TAINTED]" : "");
}
--
2.47.3
1 month
[PATCH v4] add "files -n" command for an inode
by Huang Shijie
In the NUMA machine, it is useful to know the memory distribution of
an inode page cache:
How many pages in the node 0?
How many pages in the node 1?
Add "files -n" command to get the memory distribution information:
1.) Add new argument for dump_inode_page_cache_info()
2.) make page_to_nid() a global function.
3.) Add summary_inode_page() to check each page's node
information.
4.) Use print_inode_summary_info() to print the
memory distribution information of an inode.
Signed-off-by: Huang Shijie <huangsj(a)hygon.cn>
---
v3 -- > v4:
Rebase the old patch on the latest Crash code.
Tested with Hygon machine.
Changes some help message.
v3: https://www.spinics.net/linux/fedora/redhat-crash-utility/msg11238.html
---
defs.h | 1 +
filesys.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
help.c | 24 +++++++++++++++++++++-
memory.c | 4 ++--
4 files changed, 81 insertions(+), 8 deletions(-)
diff --git a/defs.h b/defs.h
index ceed3a9..fc30aa5 100644
--- a/defs.h
+++ b/defs.h
@@ -5945,6 +5945,7 @@ int dump_inode_page(ulong);
ulong valid_section_nr(ulong);
void display_memory_from_file_offset(ulonglong, long, void *);
void swap_info_init(void);
+int page_to_nid(ulong);
/*
* filesys.c
diff --git a/filesys.c b/filesys.c
index 34944e2..0405a60 100644
--- a/filesys.c
+++ b/filesys.c
@@ -49,7 +49,7 @@ static int match_file_string(char *, char *, char *);
static ulong get_root_vfsmount(char *);
static void check_live_arch_mismatch(void);
static long get_inode_nrpages(ulong);
-static void dump_inode_page_cache_info(ulong);
+static void dump_inode_page_cache_info(ulong, void *callback);
#define DENTRY_CACHE (20)
#define INODE_CACHE (20)
@@ -2240,8 +2240,38 @@ get_inode_nrpages(ulong i_mapping)
return nrpages;
}
+/* Used to collect the numa information for an inode */
+static ulong *numa_node;
+
static void
-dump_inode_page_cache_info(ulong inode)
+print_inode_summary_info(void)
+{
+ int i;
+
+ fprintf(fp, " NODE PAGES\n");
+ for (i = 0; i < vt->numnodes; i++)
+ fprintf(fp, " %2d %8ld\n", i, numa_node[i]);
+}
+
+static int
+summary_inode_page(ulong page)
+{
+ int node;
+
+ if (!is_page_ptr(page, NULL))
+ error(FATAL, "Invalid inode page(0x%lx)\n", page);
+
+ node = page_to_nid(page);
+ if (node < 0 || node >= vt->numnodes)
+ error(FATAL, "Invalid node(%d) for page(0x%lx)\n", node, page);
+
+ numa_node[node]++;
+
+ return 1;
+}
+
+static void
+dump_inode_page_cache_info(ulong inode, void *callback)
{
char *inode_buf;
ulong i_mapping, nrpages, root_rnode, xarray, count;
@@ -2284,7 +2314,7 @@ dump_inode_page_cache_info(ulong inode)
root_rnode = i_mapping + OFFSET(address_space_page_tree);
lp.index = 0;
- lp.value = (void *)&dump_inode_page;
+ lp.value = callback;
if (root_rnode)
count = do_radix_tree(root_rnode, RADIX_TREE_DUMP_CB, &lp);
@@ -2324,7 +2354,7 @@ cmd_files(void)
ref = NULL;
refarg = NULL;
- while ((c = getopt(argcnt, args, "d:R:p:c")) != EOF) {
+ while ((c = getopt(argcnt, args, "d:n:R:p:c")) != EOF) {
switch(c)
{
case 'R':
@@ -2343,11 +2373,31 @@ cmd_files(void)
display_dentry_info(value);
return;
+ case 'n':
+ if (VALID_MEMBER(address_space_page_tree) &&
+ VALID_MEMBER(inode_i_mapping)) {
+ value = htol(optarg, FAULT_ON_ERROR, NULL);
+
+ /* Allocate the array for this inode */
+ numa_node = malloc(sizeof(ulong) * vt->numnodes);
+ BZERO(numa_node, sizeof(ulong) * vt->numnodes);
+
+ dump_inode_page_cache_info(value, (void *)&summary_inode_page);
+
+ /* Print out the NUMA node information for this inode */
+ print_inode_summary_info();
+
+ free(numa_node);
+ numa_node = NULL;
+ } else
+ option_not_supported('n');
+ return;
+
case 'p':
if (VALID_MEMBER(address_space_page_tree) &&
VALID_MEMBER(inode_i_mapping)) {
value = htol(optarg, FAULT_ON_ERROR, NULL);
- dump_inode_page_cache_info(value);
+ dump_inode_page_cache_info(value, (void *)&dump_inode_page);
} else
option_not_supported('p');
return;
diff --git a/help.c b/help.c
index 91d1550..6f97289 100644
--- a/help.c
+++ b/help.c
@@ -7900,7 +7900,7 @@ NULL
char *help_files[] = {
"files",
"open files",
-"[-d dentry] | [-p inode] | [-c] [-R reference] [pid | taskp] ... ",
+"[-d dentry] | [-p inode] | [-n inode]|[-c] [-R reference] [pid | taskp] ... ",
" This command displays information about open files of a context.",
" It prints the context's current root directory and current working",
" directory, and then for each open file descriptor it prints a pointer",
@@ -7915,6 +7915,8 @@ char *help_files[] = {
" super block, file type, and full pathname.",
" -p inode given a hexadecimal inode address, dump all of its pages",
" that are in the page cache.",
+" -n inode given a hexadecimal inode address, check all the pages",
+" in the page cache, and display a NUMA node distribution.",
" -c for each open file descriptor, prints a pointer to its",
" inode, a pointer to the inode's i_mapping address_space",
" structure, the number of pages of the inode that are in",
@@ -8024,6 +8026,26 @@ char *help_files[] = {
" ca1ddde0 2eeef000 f59b91ac 3 2 82c referenced,uptodate,lru,private",
" ca36b300 3b598000 f59b91ac 4 2 82c referenced,uptodate,lru,private",
" ca202680 30134000 f59b91ac 5 2 82c referenced,uptodate,lru,private",
+" ",
+" For the inode at address ffff8898857c55a8, display the NUMA node",
+" distribution of its pages that are in the page cache:",
+" %s> files -n ffff8898857c55a8",
+" INODE NRPAGES",
+" ffff8898857c55a8 51748",
+" ",
+" NODE PAGES",
+" 0 51536",
+" 1 0",
+" 2 0",
+" 3 0",
+" 4 0",
+" 5 212",
+" 6 0",
+" 7 0",
+" 8 0",
+" 9 0",
+" 10 0",
+" 11 0",
" ",
NULL
};
diff --git a/memory.c b/memory.c
index cbc8d2f..9ba262a 100644
--- a/memory.c
+++ b/memory.c
@@ -301,7 +301,7 @@ static int dump_vm_event_state(void);
static int dump_page_states(void);
static int generic_read_dumpfile(ulonglong, void *, long, char *, ulong);
static int generic_write_dumpfile(ulonglong, void *, long, char *, ulong);
-static int page_to_nid(ulong);
+int page_to_nid(ulong);
static int get_kmem_cache_list(ulong **);
static int get_kmem_cache_root_list(ulong **);
static int get_kmem_cache_child_list(ulong **, ulong);
@@ -20054,7 +20054,7 @@ is_kmem_cache_addr_common(ulong vaddr, char *kbuf)
/*
* Kernel-config-neutral page-to-node evaluator.
*/
-static int
+int
page_to_nid(ulong page)
{
int i;
--
2.43.0
1 month, 1 week