[PATCH] Fix for an abort in vm_stat_init() without CONFIG_NUMA
by Kazuhito Hagio
With recent kernels without CONFIG_NUMA (including Fedora 32-bit),
the vm_stat_init() function aborts when getting numa_stat_item
enum items, (probably) because it is not defined.
crash> kmem -V
double free or corruption (!prev)
Aborted (core dumped)
We can avoid the abort by checking whether the length of the
vm_numa_stat array is also not zero.
This patch tested OK with the following kernels:
4.17.0-0.rc5.git3.1.fc29.i686
4.18.0-0.rc5.git4.1.fc29.x86_64
3.10.0-862.el7.x86_64
Signed-off-by: Kazuhito Hagio <k-hagio(a)ab.jp.nec.com>
---
defs.h | 1 +
memory.c | 10 ++++++----
symbols.c | 4 ++++
3 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/defs.h b/defs.h
index f569a62..6fdb478 100644
--- a/defs.h
+++ b/defs.h
@@ -2220,6 +2220,7 @@ struct array_table {
int height_to_maxnodes;
int task_struct_rlim;
int signal_struct_rlim;
+ int vm_numa_stat;
};
/*
diff --git a/memory.c b/memory.c
index 7c0cb5f..e02ba68 100644
--- a/memory.c
+++ b/memory.c
@@ -17454,11 +17454,12 @@ vm_stat_init(void)
} else if (symbol_exists("vm_zone_stat") &&
get_symbol_type("vm_zone_stat",
NULL, NULL) == TYPE_CODE_ARRAY) {
- if (symbol_exists("vm_numa_stat")) {
+ if (symbol_exists("vm_numa_stat") &&
+ get_array_length("vm_numa_stat", NULL, 0)) {
vt->nr_vm_stat_items =
get_array_length("vm_zone_stat", NULL, 0)
+ get_array_length("vm_node_stat", NULL, 0)
- + get_array_length("vm_numa_stat", NULL, 0);
+ + ARRAY_LENGTH(vm_numa_stat);
split_vmstat = 2;
enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zone_cnt);
enumerator_value("NR_VM_NODE_STAT_ITEMS", &node_cnt);
@@ -17599,7 +17600,7 @@ dump_vm_stat(char *item, long *retval, ulong zone)
buf = GETBUF(sizeof(ulong) * vt->nr_vm_stat_items);
if (symbol_exists("vm_node_stat") && symbol_exists("vm_zone_stat") &&
- symbol_exists("vm_numa_stat"))
+ symbol_exists("vm_numa_stat") && ARRAY_LENGTH(vm_numa_stat))
split_vmstat = 2;
else if (symbol_exists("vm_node_stat") && symbol_exists("vm_zone_stat"))
split_vmstat = 1;
@@ -17666,7 +17667,8 @@ dump_vm_stat(char *item, long *retval, ulong zone)
if (!zone) {
if ((i == node_start) && symbol_exists("vm_node_stat"))
fprintf(fp, "\n VM_NODE_STAT:\n");
- if ((i == numa_start) && symbol_exists("vm_numa_stat"))
+ if ((i == numa_start) && symbol_exists("vm_numa_stat")
+ && ARRAY_LENGTH(vm_numa_stat))
fprintf(fp, "\n VM_NUMA_STAT:\n");
}
fprintf(fp, "%s%s: %ld\n",
diff --git a/symbols.c b/symbols.c
index df84ee2..bee60ba 100644
--- a/symbols.c
+++ b/symbols.c
@@ -8457,6 +8457,8 @@ builtin_array_length(char *s, int len, int *two_dim)
lenptr = &array_table.task_struct_rlim;
else if (STREQ(s, "signal_struct.rlim"))
lenptr = &array_table.signal_struct_rlim;
+ else if (STREQ(s, "vm_numa_stat"))
+ lenptr = &array_table.vm_numa_stat;
if (!lenptr) /* not stored */
return(len);
@@ -10594,6 +10596,8 @@ dump_offset_table(char *spec, ulong makestruct)
ARRAY_LENGTH(task_struct_rlim));
fprintf(fp, " signal_struct_rlim: %d\n",
ARRAY_LENGTH(signal_struct_rlim));
+ fprintf(fp, " vm_numa_stat: %d\n",
+ ARRAY_LENGTH(vm_numa_stat));
if (spec) {
int in_size_table, in_array_table, arrays, offsets, sizes;
--
1.8.3.1
6 years, 3 months
[PATCH] Fix the extension trace.so for RHEL7.6
by Xu Huan
Fix the extension trace.so for RHEL7.6 ,which moved
ftrace_event_call.data into an anonymous union,and the
previous offset has changed, so the trace.so extension
module fails to load ,indicating "no commands registered:
shared object unloaded".
---
extensions/trace.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/extensions/trace.c b/extensions/trace.c
index 7d76699..ad71951 100644
--- a/extensions/trace.c
+++ b/extensions/trace.c
@@ -853,8 +853,18 @@ static int syscall_get_enter_fields(ulong call, ulong *fields)
inited = 1;
data_offset = MAX(MEMBER_OFFSET("ftrace_event_call", "data"),
MEMBER_OFFSET("trace_event_call", "data"));
- if (data_offset < 0)
- return -1;
+ if (data_offset < 0) {
+ /*
+ * rhel-7.6 moved the .data member into an anonymous union.
+ */
+ if (MEMBER_EXISTS("ftrace_event_call", "rh_data") &&
+ MEMBER_EXISTS("ftrace_event_data", "data")) {
+ data_offset = MEMBER_OFFSET("ftrace_event_call", "rh_data") +
+ MEMBER_OFFSET("ftrace_event_data", "data");
+ inited = 2;
+ } else
+ return -1;
+ }
enter_fields_offset = MEMBER_OFFSET("syscall_metadata", "enter_fields");
if (enter_fields_offset < 0)
@@ -868,6 +878,12 @@ work:
"read ftrace_event_call data", RETURN_ON_ERROR))
return -1;
+ if (inited == 2) {
+ if (!readmem(metadata, KVADDR, &metadata, sizeof(metadata),
+ "read ftrace_event_call data (indirect rh_data)", RETURN_ON_ERROR))
+ return -1;
+ }
+
*fields = metadata + enter_fields_offset;
return 0;
}
--
2.17.1
6 years, 3 months
Maintenance of trace.c extension module
by xuhuan
Hello Dave,
I'm Fei Jie's colleague at FNST. Since Fei now is busy with other work
and doesn't have time to maintain trace.c, I'd like to be the maintainer
of this module from now on. And I'm working on the code of trace.c .
Thanks,
Xu.
6 years, 3 months
[PATCH 0/2] Move NAME column in "kmem -s" output to the last of line
by Kazuhito Hagio
Nowadays, "kmem -s" output can have long lines due to cache name with
memcg name, and I don't think that it's human-readable as it is.
crash> kmem -s
CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE
ffff8a1522c15380 kmalloc-128(12536:session-11.scope) 128 111 128 4 4k
ffff8a1522c15200 radix_tree_node(12536:session-11.scope) 576 340 434 31 8k
ffff8a1523d15380 xfs_inode(12536:session-11.scope) 904 1567 1581 93 16k
ffff8a1522c15080 nfs_inode_cache(12536:session-11.scope) 1072 140 165 11 16k
ffff8a1523d14c00 shmem_inode_cache(12536:session-11.scope) 696 0 46 2 16k
So, can we move the 'NAME' column to the last of line like this?
crash> kmem -s
CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME
ffff8a1522c15380 128 111 128 4 4k kmalloc-128(12536:session-11.scope)
ffff8a1522c15200 576 340 434 31 8k radix_tree_node(12536:session-11.scope)
ffff8a1523d15380 904 1567 1581 93 16k xfs_inode(12536:session-11.scope)
ffff8a1522c15080 1072 140 165 11 16k nfs_inode_cache(12536:session-11.scope)
ffff8a1523d14c00 696 0 46 2 16k shmem_inode_cache(12536:session-11.scope)
If we can, crash has the three functions to print them for each slab/slub
version and I think that it would be good to change all of them together.
Fortunately, the header is same among them, and it looks like we can unify
them into one function. [Patch 1]
And then, move it to the last of line. [Patch 2]
I tested this with some vmcores having PERCPU_KMALLOC_V2 or KMALLOC_SLUB
and found no problem, but I don't have any vmcores having PERCPU_KMALLOC_V1
or no flag.
Kazuhito Hagio (2):
Unify the three functions printing "kmem -s" line into one function
Move NAME column in "kmem -s" output to the last of line
help.c | 136 +++++++++++++++++++++++++++++++--------------------------------
memory.c | 132 +++++++++++++++----------------------------------------------
2 files changed, 99 insertions(+), 169 deletions(-)
--
1.8.3.1
6 years, 3 months
[PATCH] fix open fds display when process using large amount of file descriptors
by Tan Hu
Usually, structure fd_set only has 1024 bits size, when a process
using large amount of file descriptors that exceed the size of fd_set,
then the display of files and net sockets would mistake caused by the
out of bounds reading in loop.
Signed-off-by: Tan Hu <tan.hu(a)zte.com.cn>
---
filesys.c | 24 ++++++++++++++++++------
net.c | 17 +++++++++++++----
2 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/filesys.c b/filesys.c
index 0ace8f4..47f5a24 100755
--- a/filesys.c
+++ b/filesys.c
@@ -2380,7 +2380,8 @@ open_files_dump(ulong task, int flags, struct reference *ref)
int max_fdset = 0;
int max_fds = 0;
ulong open_fds_addr;
- fd_set open_fds;
+ int open_fds_size;
+ ulong *open_fds;
ulong fd;
ulong file;
ulong value;
@@ -2583,16 +2584,25 @@ open_files_dump(ulong task, int flags, struct reference *ref)
open_fds_addr = ULONG(files_struct_buf +
OFFSET(files_struct_open_fds));
+ open_fds_size = MAX(max_fdset, max_fds) / BITS_PER_BYTE;
+ open_fds = (ulong *)GETBUF(open_fds_size);
+ if (!open_fds) {
+ if (fdtable_buf)
+ FREEBUF(fdtable_buf);
+ FREEBUF(files_struct_buf);
+ return;
+ }
+
if (open_fds_addr) {
if (VALID_MEMBER(files_struct_open_fds_init) &&
(open_fds_addr == (files_struct_addr +
OFFSET(files_struct_open_fds_init))))
BCOPY(files_struct_buf +
OFFSET(files_struct_open_fds_init),
- &open_fds, sizeof(fd_set));
+ open_fds, open_fds_size);
else
- readmem(open_fds_addr, KVADDR, &open_fds,
- sizeof(fd_set), "fdtable open_fds",
+ readmem(open_fds_addr, KVADDR, open_fds,
+ open_fds_size, "fdtable open_fds",
FAULT_ON_ERROR);
}
@@ -2607,6 +2617,7 @@ open_files_dump(ulong task, int flags, struct reference *ref)
if (fdtable_buf)
FREEBUF(fdtable_buf);
FREEBUF(files_struct_buf);
+ FREEBUF(open_fds);
return;
}
@@ -2617,11 +2628,11 @@ open_files_dump(ulong task, int flags, struct reference *ref)
j = 0;
for (;;) {
unsigned long set;
- i = j * __NFDBITS;
+ i = j * BITS_PER_LONG;
if (((max_fdset >= 0) && (i >= max_fdset)) ||
(i >= max_fds))
break;
- set = open_fds.__fds_bits[j++];
+ set = open_fds[j++];
while (set) {
if (set & 1) {
readmem(fd + i*sizeof(struct file *), KVADDR,
@@ -2665,6 +2676,7 @@ open_files_dump(ulong task, int flags, struct reference *ref)
if (fdtable_buf)
FREEBUF(fdtable_buf);
FREEBUF(files_struct_buf);
+ FREEBUF(open_fds);
}
/*
diff --git a/net.c b/net.c
index 4199091..f08f22a 100755
--- a/net.c
+++ b/net.c
@@ -1373,7 +1373,8 @@ dump_sockets_workhorse(ulong task, ulong flag, struct reference *ref)
int max_fdset = 0;
int max_fds = 0;
ulong open_fds_addr = 0;
- fd_set open_fds;
+ ulong *open_fds;
+ int open_fds_size;
ulong fd;
ulong file;
int i, j;
@@ -1446,12 +1447,18 @@ dump_sockets_workhorse(ulong task, ulong flag, struct reference *ref)
sizeof(void *), "files_struct fd addr", FAULT_ON_ERROR);
}
+ open_fds_size = MAX(max_fdset, max_fds) / BITS_PER_BYTE;
+ open_fds = (ulong *)GETBUF(open_fds_size);
+ if (!open_fds)
+ return;
+
if (open_fds_addr)
- readmem(open_fds_addr, KVADDR, &open_fds, sizeof(fd_set),
+ readmem(open_fds_addr, KVADDR, open_fds, open_fds_size,
"files_struct open_fds", FAULT_ON_ERROR);
if (!open_fds_addr || !fd) {
if (!NET_REFERENCE_CHECK(ref))
fprintf(fp, "No open sockets.\n");
+ FREEBUF(open_fds);
return;
}
@@ -1479,10 +1486,10 @@ dump_sockets_workhorse(ulong task, ulong flag, struct reference *ref)
j = 0;
for (;;) {
unsigned long set;
- i = j * __NFDBITS;
+ i = j * BITS_PER_LONG;
if (((max_fdset >= 0) && (i >= max_fdset)) || (i >= max_fds))
break;
- set = open_fds.__fds_bits[j++];
+ set = open_fds[j++];
while (set) {
if (set & 1) {
readmem(fd + i*sizeof(struct file *), KVADDR,
@@ -1505,6 +1512,8 @@ dump_sockets_workhorse(ulong task, ulong flag, struct reference *ref)
if (NET_REFERENCE_FOUND(ref))
fprintf(fp, "\n");
+
+ FREEBUF(open_fds);
}
--
1.8.3.1
6 years, 3 months