|
|
608733 |
|
|
|
608733 |
commit 9b494b7006bcc7f3f0bf3be9e3c6d3a5e703a728
|
|
|
608733 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
608733 |
Date: Tue Jun 26 16:00:28 2018 -0400
|
|
|
608733 |
|
|
|
608733 |
Update for the "kmem -V" option to also dump the global entries that
|
|
|
608733 |
are contained in the "vm_numa_stat" array that was introduced in
|
|
|
608733 |
Linux 4.14. Also, the command output separates the "vm_zone_stat",
|
|
|
608733 |
"vm_node_stat" and "vm_numa_stat" entries into separate sections with
|
|
|
608733 |
"VM_ZONE_STAT", "VM_NODE_STAT" and "VM_NUMA_STAT" headers. Without
|
|
|
608733 |
the patch, the "vm_zone_stat" and "vm_node_stat" entries are listed
|
|
|
608733 |
together under a "VM_STAT" header.
|
|
|
608733 |
(anderson@redhat.com)
|
|
|
608733 |
|
|
|
608733 |
diff --git a/help.c b/help.c
|
|
|
608733 |
index 5a52650..638c6ec 100644
|
|
|
608733 |
--- a/help.c
|
|
|
608733 |
+++ b/help.c
|
|
|
608733 |
@@ -6451,9 +6451,10 @@ char *help_kmem[] = {
|
|
|
608733 |
" -C same as -c, but also dumps all pages in the page_hash_table.",
|
|
|
608733 |
" -i displays general memory usage information",
|
|
|
608733 |
" -v displays the mapped virtual memory regions allocated by vmalloc().",
|
|
|
608733 |
-" -V displays the kernel vm_stat table if it exists, the cumulative",
|
|
|
608733 |
-" page_states counter values if they exist, and/or the cumulative",
|
|
|
608733 |
-" vm_event_states counter values if they exist.",
|
|
|
608733 |
+" -V displays the kernel vm_stat table if it exists, or in more recent",
|
|
|
608733 |
+" kernels, the vm_zone_stat, vm_node_stat and vm_numa_stat tables,",
|
|
|
608733 |
+" the cumulative page_states counter values if they exist, and/or ",
|
|
|
608733 |
+" the cumulative, vm_event_states counter values if they exist.",
|
|
|
608733 |
" -n display memory node data (if supported).",
|
|
|
608733 |
" -z displays per-zone memory statistics.",
|
|
|
608733 |
" -o displays each cpu's offset value that is added to per-cpu symbol",
|
|
|
608733 |
@@ -6761,24 +6762,69 @@ char *help_kmem[] = {
|
|
|
608733 |
" f63d5cc0 f6287b80 f83c2000 - f84c3000 1052672",
|
|
|
608733 |
" ...",
|
|
|
608733 |
" ",
|
|
|
608733 |
-" Dump the vm_table contents:\n",
|
|
|
608733 |
+" Dump the virtual memory statistics:\n",
|
|
|
608733 |
" %s> kmem -V",
|
|
|
608733 |
-" NR_ANON_PAGES: 38989",
|
|
|
608733 |
-" NR_FILE_MAPPED: 3106",
|
|
|
608733 |
-" NR_FILE_PAGES: 169570",
|
|
|
608733 |
-" NR_SLAB: 32439",
|
|
|
608733 |
-" NR_PAGETABLE: 1181",
|
|
|
608733 |
-" NR_FILE_DIRTY: 4633",
|
|
|
608733 |
-" NR_WRITEBACK: 0",
|
|
|
608733 |
-" NR_UNSTABLE_NFS: 0",
|
|
|
608733 |
-" NR_BOUNCE: 0",
|
|
|
608733 |
-" NUMA_HIT: 63545992",
|
|
|
608733 |
-" NUMA_MISS: 0",
|
|
|
608733 |
-" NUMA_FOREIGN: 0",
|
|
|
608733 |
-" NUMA_INTERLEAVE_HIT: 24002",
|
|
|
608733 |
-" NUMA_LOCAL: 63545992",
|
|
|
608733 |
-" NUMA_OTHER: 0",
|
|
|
608733 |
-" ",
|
|
|
608733 |
+" VM_ZONE_STAT:",
|
|
|
608733 |
+" NR_FREE_PAGES: 30085",
|
|
|
608733 |
+" NR_ZONE_INACTIVE_ANON: 1985",
|
|
|
608733 |
+" NR_ZONE_ACTIVE_ANON: 338275",
|
|
|
608733 |
+" NR_ZONE_INACTIVE_FILE: 19760",
|
|
|
608733 |
+" NR_ZONE_ACTIVE_FILE: 12018",
|
|
|
608733 |
+" NR_ZONE_UNEVICTABLE: 0",
|
|
|
608733 |
+" NR_ZONE_WRITE_PENDING: 4",
|
|
|
608733 |
+" NR_MLOCK: 0",
|
|
|
608733 |
+" NR_PAGETABLE: 1562",
|
|
|
608733 |
+" NR_KERNEL_STACK_KB: 1728",
|
|
|
608733 |
+" NR_BOUNCE: 0",
|
|
|
608733 |
+" NR_FREE_CMA_PAGES: 0",
|
|
|
608733 |
+" ",
|
|
|
608733 |
+" VM_NODE_STAT:",
|
|
|
608733 |
+" NR_INACTIVE_ANON: 1985",
|
|
|
608733 |
+" NR_ACTIVE_ANON: 338275",
|
|
|
608733 |
+" NR_INACTIVE_FILE: 19760",
|
|
|
608733 |
+" NR_ACTIVE_FILE: 12018",
|
|
|
608733 |
+" NR_UNEVICTABLE: 0",
|
|
|
608733 |
+" NR_SLAB_RECLAIMABLE: 3111",
|
|
|
608733 |
+" NR_SLAB_UNRECLAIMABLE: 3039",
|
|
|
608733 |
+" NR_ISOLATED_ANON: 0",
|
|
|
608733 |
+" NR_ISOLATED_FILE: 0",
|
|
|
608733 |
+" WORKINGSET_REFAULT: 0",
|
|
|
608733 |
+" WORKINGSET_ACTIVATE: 0",
|
|
|
608733 |
+" WORKINGSET_NODERECLAIM: 0",
|
|
|
608733 |
+" NR_ANON_MAPPED: 338089",
|
|
|
608733 |
+" NR_FILE_MAPPED: 8102",
|
|
|
608733 |
+" NR_FILE_PAGES: 33949",
|
|
|
608733 |
+" NR_FILE_DIRTY: 4",
|
|
|
608733 |
+" NR_WRITEBACK: 0",
|
|
|
608733 |
+" NR_WRITEBACK_TEMP: 0",
|
|
|
608733 |
+" NR_SHMEM: 2171",
|
|
|
608733 |
+" NR_SHMEM_THPS: 0",
|
|
|
608733 |
+" NR_SHMEM_PMDMAPPED: 0",
|
|
|
608733 |
+" NR_ANON_THPS: 86",
|
|
|
608733 |
+" NR_UNSTABLE_NFS: 0",
|
|
|
608733 |
+" NR_VMSCAN_WRITE: 0",
|
|
|
608733 |
+" NR_VMSCAN_IMMEDIATE: 0",
|
|
|
608733 |
+" NR_DIRTIED: 155",
|
|
|
608733 |
+" NR_WRITTEN: 75",
|
|
|
608733 |
+" ",
|
|
|
608733 |
+" VM_NUMA_STAT:",
|
|
|
608733 |
+" NUMA_HIT: 575409",
|
|
|
608733 |
+" NUMA_MISS: 0",
|
|
|
608733 |
+" NUMA_FOREIGN: 0",
|
|
|
608733 |
+" NUMA_INTERLEAVE_HIT: 12930",
|
|
|
608733 |
+" NUMA_LOCAL: 575409",
|
|
|
608733 |
+" NUMA_OTHER: 0",
|
|
|
608733 |
+" ",
|
|
|
608733 |
+" VM_EVENT_STATES:",
|
|
|
608733 |
+" PGPGIN: 282492",
|
|
|
608733 |
+" PGPGOUT: 6773",
|
|
|
608733 |
+" PSWPIN: 0",
|
|
|
608733 |
+" PSWPOUT: 0",
|
|
|
608733 |
+" PGALLOC_DMA: 0",
|
|
|
608733 |
+" PGALLOC_DMA32: 693092",
|
|
|
608733 |
+" PGALLOC_NORMAL: 0",
|
|
|
608733 |
+" ...",
|
|
|
608733 |
+" ",
|
|
|
608733 |
" Display hugepage hstate information: \n",
|
|
|
608733 |
" %s> kmem -h",
|
|
|
608733 |
" HSTATE SIZE FREE TOTAL NAME",
|
|
|
608733 |
diff --git a/memory.c b/memory.c
|
|
|
608733 |
index 5c0a853..81ed689 100644
|
|
|
608733 |
--- a/memory.c
|
|
|
608733 |
+++ b/memory.c
|
|
|
608733 |
@@ -17422,7 +17422,7 @@ vm_stat_init(void)
|
|
|
608733 |
int c ATTRIBUTE_UNUSED;
|
|
|
608733 |
struct gnu_request *req;
|
|
|
608733 |
char *start;
|
|
|
608733 |
- long enum_value, zc = -1;
|
|
|
608733 |
+ long enum_value, zone_cnt = -1, node_cnt = -1;
|
|
|
608733 |
int split_vmstat = 0, ni = 0;
|
|
|
608733 |
|
|
|
608733 |
if (vt->flags & VM_STAT)
|
|
|
608733 |
@@ -17451,11 +17451,21 @@ vm_stat_init(void)
|
|
|
608733 |
} else if (symbol_exists("vm_zone_stat") &&
|
|
|
608733 |
get_symbol_type("vm_zone_stat",
|
|
|
608733 |
NULL, NULL) == TYPE_CODE_ARRAY) {
|
|
|
608733 |
- vt->nr_vm_stat_items =
|
|
|
608733 |
- get_array_length("vm_zone_stat", NULL, 0)
|
|
|
608733 |
- + get_array_length("vm_node_stat", NULL, 0);
|
|
|
608733 |
- split_vmstat = 1;
|
|
|
608733 |
- enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zc);
|
|
|
608733 |
+ if (symbol_exists("vm_numa_stat")) {
|
|
|
608733 |
+ vt->nr_vm_stat_items =
|
|
|
608733 |
+ get_array_length("vm_zone_stat", NULL, 0)
|
|
|
608733 |
+ + get_array_length("vm_node_stat", NULL, 0)
|
|
|
608733 |
+ + get_array_length("vm_numa_stat", NULL, 0);
|
|
|
608733 |
+ split_vmstat = 2;
|
|
|
608733 |
+ enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zone_cnt);
|
|
|
608733 |
+ enumerator_value("NR_VM_NODE_STAT_ITEMS", &node_cnt);
|
|
|
608733 |
+ } else {
|
|
|
608733 |
+ vt->nr_vm_stat_items =
|
|
|
608733 |
+ get_array_length("vm_zone_stat", NULL, 0)
|
|
|
608733 |
+ + get_array_length("vm_node_stat", NULL, 0);
|
|
|
608733 |
+ split_vmstat = 1;
|
|
|
608733 |
+ enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zone_cnt);
|
|
|
608733 |
+ }
|
|
|
608733 |
} else {
|
|
|
608733 |
goto bailout;
|
|
|
608733 |
}
|
|
|
608733 |
@@ -17468,13 +17478,20 @@ vm_stat_init(void)
|
|
|
608733 |
req->flags = GNU_PRINT_ENUMERATORS;
|
|
|
608733 |
gdb_interface(req);
|
|
|
608733 |
|
|
|
608733 |
- if (split_vmstat) {
|
|
|
608733 |
+ if (split_vmstat >= 1) {
|
|
|
608733 |
req->command = GNU_GET_DATATYPE;
|
|
|
608733 |
req->name = "node_stat_item";
|
|
|
608733 |
req->flags = GNU_PRINT_ENUMERATORS;
|
|
|
608733 |
gdb_interface(req);
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
+ if (split_vmstat == 2) {
|
|
|
608733 |
+ req->command = GNU_GET_DATATYPE;
|
|
|
608733 |
+ req->name = "numa_stat_item";
|
|
|
608733 |
+ req->flags = GNU_PRINT_ENUMERATORS;
|
|
|
608733 |
+ gdb_interface(req);
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
FREEBUF(req);
|
|
|
608733 |
|
|
|
608733 |
stringlen = 1;
|
|
|
608733 |
@@ -17488,15 +17505,20 @@ vm_stat_init(void)
|
|
|
608733 |
c = parse_line(buf, arglist);
|
|
|
608733 |
if ((!split_vmstat &&
|
|
|
608733 |
STREQ(arglist[0], "NR_VM_ZONE_STAT_ITEMS")) ||
|
|
|
608733 |
- (split_vmstat &&
|
|
|
608733 |
- STREQ(arglist[0], "NR_VM_NODE_STAT_ITEMS"))) {
|
|
|
608733 |
+ ((split_vmstat == 1) &&
|
|
|
608733 |
+ STREQ(arglist[0], "NR_VM_NODE_STAT_ITEMS")) ||
|
|
|
608733 |
+ ((split_vmstat == 2) &&
|
|
|
608733 |
+ STREQ(arglist[0], "NR_VM_NUMA_STAT_ITEMS"))) {
|
|
|
608733 |
if (LKCD_KERNTYPES())
|
|
|
608733 |
vt->nr_vm_stat_items =
|
|
|
608733 |
MAX(atoi(arglist[2]), count);
|
|
|
608733 |
break;
|
|
|
608733 |
- } else if (split_vmstat &&
|
|
|
608733 |
+ } else if ((split_vmstat == 1) &&
|
|
|
608733 |
STREQ(arglist[0], "NR_VM_ZONE_STAT_ITEMS")) {
|
|
|
608733 |
continue;
|
|
|
608733 |
+ } else if ((split_vmstat == 2) &&
|
|
|
608733 |
+ STREQ(arglist[0], "NR_VM_NODE_STAT_ITEMS")) {
|
|
|
608733 |
+ continue;
|
|
|
608733 |
} else {
|
|
|
608733 |
stringlen += strlen(arglist[0]) + 1;
|
|
|
608733 |
count++;
|
|
|
608733 |
@@ -17523,8 +17545,11 @@ vm_stat_init(void)
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
i = ni + enum_value;
|
|
|
608733 |
- if (!ni && (enum_value == zc)) {
|
|
|
608733 |
- ni = zc;
|
|
|
608733 |
+ if (!ni && (enum_value == zone_cnt)) {
|
|
|
608733 |
+ ni = zone_cnt;
|
|
|
608733 |
+ continue;
|
|
|
608733 |
+ } else if ((ni == zone_cnt) && (enum_value == node_cnt)) {
|
|
|
608733 |
+ ni += node_cnt;
|
|
|
608733 |
continue;
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
@@ -17556,8 +17581,8 @@ dump_vm_stat(char *item, long *retval, ulong zone)
|
|
|
608733 |
char *buf;
|
|
|
608733 |
ulong *vp;
|
|
|
608733 |
ulong location;
|
|
|
608733 |
- int i, maxlen, len;
|
|
|
608733 |
- long tc, zc = 0, nc = 0;
|
|
|
608733 |
+ int i, maxlen, len, node_start = -1, numa_start = 1;
|
|
|
608733 |
+ long total_cnt, zone_cnt = 0, node_cnt = 0, numa_cnt = 0;
|
|
|
608733 |
int split_vmstat = 0;
|
|
|
608733 |
|
|
|
608733 |
if (!vm_stat_init()) {
|
|
|
608733 |
@@ -17570,48 +17595,86 @@ dump_vm_stat(char *item, long *retval, ulong zone)
|
|
|
608733 |
|
|
|
608733 |
buf = GETBUF(sizeof(ulong) * vt->nr_vm_stat_items);
|
|
|
608733 |
|
|
|
608733 |
- if (symbol_exists("vm_node_stat") && symbol_exists("vm_zone_stat"))
|
|
|
608733 |
+ if (symbol_exists("vm_node_stat") && symbol_exists("vm_zone_stat") &&
|
|
|
608733 |
+ symbol_exists("vm_numa_stat"))
|
|
|
608733 |
+ split_vmstat = 2;
|
|
|
608733 |
+ else if (symbol_exists("vm_node_stat") && symbol_exists("vm_zone_stat"))
|
|
|
608733 |
split_vmstat = 1;
|
|
|
608733 |
else
|
|
|
608733 |
location = zone ? zone : symbol_value("vm_stat");
|
|
|
608733 |
|
|
|
608733 |
- if (split_vmstat) {
|
|
|
608733 |
- enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zc);
|
|
|
608733 |
+ if (split_vmstat == 1) {
|
|
|
608733 |
+ enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zone_cnt);
|
|
|
608733 |
location = zone ? zone : symbol_value("vm_zone_stat");
|
|
|
608733 |
readmem(location, KVADDR, buf,
|
|
|
608733 |
- sizeof(ulong) * zc,
|
|
|
608733 |
+ sizeof(ulong) * zone_cnt,
|
|
|
608733 |
"vm_zone_stat", FAULT_ON_ERROR);
|
|
|
608733 |
if (!zone) {
|
|
|
608733 |
location = symbol_value("vm_node_stat");
|
|
|
608733 |
- enumerator_value("NR_VM_NODE_STAT_ITEMS", &nc);
|
|
|
608733 |
- readmem(location, KVADDR, buf + (sizeof(ulong) * zc),
|
|
|
608733 |
- sizeof(ulong) * nc,
|
|
|
608733 |
+ enumerator_value("NR_VM_NODE_STAT_ITEMS", &node_cnt);
|
|
|
608733 |
+ readmem(location, KVADDR, buf + (sizeof(ulong) * zone_cnt),
|
|
|
608733 |
+ sizeof(ulong) * node_cnt,
|
|
|
608733 |
"vm_node_stat", FAULT_ON_ERROR);
|
|
|
608733 |
}
|
|
|
608733 |
- tc = zc + nc;
|
|
|
608733 |
+ node_start = zone_cnt;
|
|
|
608733 |
+ total_cnt = zone_cnt + node_cnt;
|
|
|
608733 |
+ } else if (split_vmstat == 2) {
|
|
|
608733 |
+ enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zone_cnt);
|
|
|
608733 |
+ location = zone ? zone : symbol_value("vm_zone_stat");
|
|
|
608733 |
+ readmem(location, KVADDR, buf,
|
|
|
608733 |
+ sizeof(ulong) * zone_cnt,
|
|
|
608733 |
+ "vm_zone_stat", FAULT_ON_ERROR);
|
|
|
608733 |
+ if (!zone) {
|
|
|
608733 |
+ location = symbol_value("vm_node_stat");
|
|
|
608733 |
+ enumerator_value("NR_VM_NODE_STAT_ITEMS", &node_cnt);
|
|
|
608733 |
+ readmem(location, KVADDR, buf + (sizeof(ulong) * zone_cnt),
|
|
|
608733 |
+ sizeof(ulong) * node_cnt,
|
|
|
608733 |
+ "vm_node_stat", FAULT_ON_ERROR);
|
|
|
608733 |
+ }
|
|
|
608733 |
+ node_start = zone_cnt;
|
|
|
608733 |
+ if (!zone) {
|
|
|
608733 |
+ location = symbol_value("vm_numa_stat");
|
|
|
608733 |
+ enumerator_value("NR_VM_NUMA_STAT_ITEMS", &numa_cnt);
|
|
|
608733 |
+ readmem(location, KVADDR, buf + (sizeof(ulong) * (zone_cnt+node_cnt)),
|
|
|
608733 |
+ sizeof(ulong) * numa_cnt,
|
|
|
608733 |
+ "vm_numa_stat", FAULT_ON_ERROR);
|
|
|
608733 |
+ }
|
|
|
608733 |
+ numa_start = zone_cnt+node_cnt;
|
|
|
608733 |
+ total_cnt = zone_cnt + node_cnt + numa_cnt;
|
|
|
608733 |
} else {
|
|
|
608733 |
readmem(location, KVADDR, buf,
|
|
|
608733 |
sizeof(ulong) * vt->nr_vm_stat_items,
|
|
|
608733 |
"vm_stat", FAULT_ON_ERROR);
|
|
|
608733 |
- tc = vt->nr_vm_stat_items;
|
|
|
608733 |
+ total_cnt = vt->nr_vm_stat_items;
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
if (!item) {
|
|
|
608733 |
- if (!zone)
|
|
|
608733 |
- fprintf(fp, " VM_STAT:\n");
|
|
|
608733 |
- for (i = maxlen = 0; i < tc; i++)
|
|
|
608733 |
+ if (!zone) {
|
|
|
608733 |
+ if (symbol_exists("vm_zone_stat"))
|
|
|
608733 |
+ fprintf(fp, " VM_ZONE_STAT:\n");
|
|
|
608733 |
+ else
|
|
|
608733 |
+ fprintf(fp, " VM_STAT:\n");
|
|
|
608733 |
+ }
|
|
|
608733 |
+ for (i = maxlen = 0; i < total_cnt; i++)
|
|
|
608733 |
if ((len = strlen(vt->vm_stat_items[i])) > maxlen)
|
|
|
608733 |
maxlen = len;
|
|
|
608733 |
vp = (ulong *)buf;
|
|
|
608733 |
- for (i = 0; i < tc; i++)
|
|
|
608733 |
+ for (i = 0; i < total_cnt; i++) {
|
|
|
608733 |
+ if (!zone) {
|
|
|
608733 |
+ if ((i == node_start) && symbol_exists("vm_node_stat"))
|
|
|
608733 |
+ fprintf(fp, "\n VM_NODE_STAT:\n");
|
|
|
608733 |
+ if ((i == numa_start) && symbol_exists("vm_numa_stat"))
|
|
|
608733 |
+ fprintf(fp, "\n VM_NUMA_STAT:\n");
|
|
|
608733 |
+ }
|
|
|
608733 |
fprintf(fp, "%s%s: %ld\n",
|
|
|
608733 |
space(maxlen - strlen(vt->vm_stat_items[i])),
|
|
|
608733 |
vt->vm_stat_items[i], vp[i]);
|
|
|
608733 |
+ }
|
|
|
608733 |
return TRUE;
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
vp = (ulong *)buf;
|
|
|
608733 |
- for (i = 0; i < tc; i++) {
|
|
|
608733 |
+ for (i = 0; i < total_cnt; i++) {
|
|
|
608733 |
if (STREQ(vt->vm_stat_items[i], item)) {
|
|
|
608733 |
*retval = vp[i];
|
|
|
608733 |
return TRUE;
|
|
|
608733 |
|
|
|
608733 |
commit f294197b5511537e6b14d5e1db324f4fc4fdd3f8
|
|
|
608733 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
608733 |
Date: Fri Jul 6 10:57:50 2018 -0400
|
|
|
608733 |
|
|
|
608733 |
Support for the "bpf" command on RHEL 3.10.0-913.el7 and later
|
|
|
608733 |
3.10-based RHEL7 kernels, which contain a backport of the upstream
|
|
|
608733 |
eBPF code, but still use the older, pre-4.11, IDR facility that does
|
|
|
608733 |
not use radix trees for linking the active bpf_prog and bpf_map
|
|
|
608733 |
structures. Without the patch, the command indicates "bpf: command
|
|
|
608733 |
not supported or applicable on this architecture or kernel".
|
|
|
608733 |
(anderson@redhat.com)
|
|
|
608733 |
|
|
|
608733 |
diff --git a/bpf.c b/bpf.c
|
|
|
608733 |
index 427263d..8871b76 100644
|
|
|
608733 |
--- a/bpf.c
|
|
|
608733 |
+++ b/bpf.c
|
|
|
608733 |
@@ -45,6 +45,10 @@ static void bpf_prog_gpl_compatible(char *, ulong);
|
|
|
608733 |
static void dump_xlated_plain(void *, unsigned int, int);
|
|
|
608733 |
static void print_boot_time(unsigned long long, char *, unsigned int);
|
|
|
608733 |
|
|
|
608733 |
+static int do_old_idr(int, ulong, struct radix_tree_pair *);
|
|
|
608733 |
+#define OLD_IDR_INIT (1)
|
|
|
608733 |
+#define OLD_IDR_COUNT (2)
|
|
|
608733 |
+#define OLD_IDR_GATHER (3)
|
|
|
608733 |
|
|
|
608733 |
#define PROG_ID (0x1)
|
|
|
608733 |
#define MAP_ID (0x2)
|
|
|
608733 |
@@ -167,7 +171,6 @@ bpf_init(struct bpf_info *bpf)
|
|
|
608733 |
!VALID_STRUCT(bpf_map) ||
|
|
|
608733 |
!VALID_STRUCT(bpf_insn) ||
|
|
|
608733 |
INVALID_MEMBER(bpf_prog_aux) ||
|
|
|
608733 |
- INVALID_MEMBER(idr_idr_rt) ||
|
|
|
608733 |
INVALID_MEMBER(bpf_prog_type) ||
|
|
|
608733 |
INVALID_MEMBER(bpf_prog_tag) ||
|
|
|
608733 |
INVALID_MEMBER(bpf_prog_jited_len) ||
|
|
|
608733 |
@@ -210,6 +213,9 @@ bpf_init(struct bpf_info *bpf)
|
|
|
608733 |
mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "BPF_MAP"),
|
|
|
608733 |
mkstring(buf3, bpf->bpf_map_map_type_size, CENTER|LJUST, "BPF_MAP_TYPE"));
|
|
|
608733 |
|
|
|
608733 |
+ if (INVALID_MEMBER(idr_idr_rt))
|
|
|
608733 |
+ do_old_idr(OLD_IDR_INIT, 0, NULL);
|
|
|
608733 |
+
|
|
|
608733 |
bpf->status = TRUE;
|
|
|
608733 |
break;
|
|
|
608733 |
|
|
|
608733 |
@@ -220,24 +226,38 @@ bpf_init(struct bpf_info *bpf)
|
|
|
608733 |
command_not_supported();
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
- bpf->progs = do_radix_tree(symbol_value("prog_idr") + OFFSET(idr_idr_rt),
|
|
|
608733 |
- RADIX_TREE_COUNT, NULL);
|
|
|
608733 |
+ if (VALID_MEMBER(idr_idr_rt))
|
|
|
608733 |
+ bpf->progs = do_radix_tree(symbol_value("prog_idr") + OFFSET(idr_idr_rt),
|
|
|
608733 |
+ RADIX_TREE_COUNT, NULL);
|
|
|
608733 |
+ else
|
|
|
608733 |
+ bpf->progs = do_old_idr(OLD_IDR_COUNT, symbol_value("prog_idr"), NULL);
|
|
|
608733 |
+
|
|
|
608733 |
if (bpf->progs) {
|
|
|
608733 |
len = sizeof(struct radix_tree_pair) * (bpf->progs+1);
|
|
|
608733 |
bpf->proglist = (struct radix_tree_pair *)GETBUF(len);
|
|
|
608733 |
bpf->proglist[0].index = bpf->progs;
|
|
|
608733 |
- bpf->progs = do_radix_tree(symbol_value("prog_idr") + OFFSET(idr_idr_rt),
|
|
|
608733 |
- RADIX_TREE_GATHER, bpf->proglist);
|
|
|
608733 |
+ if (VALID_MEMBER(idr_idr_rt))
|
|
|
608733 |
+ bpf->progs = do_radix_tree(symbol_value("prog_idr") + OFFSET(idr_idr_rt),
|
|
|
608733 |
+ RADIX_TREE_GATHER, bpf->proglist);
|
|
|
608733 |
+ else
|
|
|
608733 |
+ bpf->progs = do_old_idr(OLD_IDR_GATHER, symbol_value("prog_idr"), bpf->proglist);
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
- bpf->maps = do_radix_tree(symbol_value("map_idr") + OFFSET(idr_idr_rt),
|
|
|
608733 |
- RADIX_TREE_COUNT, NULL);
|
|
|
608733 |
+ if (VALID_MEMBER(idr_idr_rt))
|
|
|
608733 |
+ bpf->maps = do_radix_tree(symbol_value("map_idr") + OFFSET(idr_idr_rt),
|
|
|
608733 |
+ RADIX_TREE_COUNT, NULL);
|
|
|
608733 |
+ else
|
|
|
608733 |
+ bpf->maps = do_old_idr(OLD_IDR_COUNT, symbol_value("map_idr"), NULL);
|
|
|
608733 |
+
|
|
|
608733 |
if (bpf->maps) {
|
|
|
608733 |
len = sizeof(struct radix_tree_pair) * (bpf->maps+1);
|
|
|
608733 |
bpf->maplist = (struct radix_tree_pair *)GETBUF(len);
|
|
|
608733 |
bpf->maplist[0].index = bpf->maps;
|
|
|
608733 |
- bpf->maps = do_radix_tree(symbol_value("map_idr") + OFFSET(idr_idr_rt),
|
|
|
608733 |
- RADIX_TREE_GATHER, bpf->maplist);
|
|
|
608733 |
+ if (VALID_MEMBER(idr_idr_rt))
|
|
|
608733 |
+ bpf->maps = do_radix_tree(symbol_value("map_idr") + OFFSET(idr_idr_rt),
|
|
|
608733 |
+ RADIX_TREE_GATHER, bpf->maplist);
|
|
|
608733 |
+ else
|
|
|
608733 |
+ bpf->maps = do_old_idr(OLD_IDR_GATHER, symbol_value("map_idr"), bpf->maplist);
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
bpf->bpf_prog_buf = GETBUF(SIZE(bpf_prog));
|
|
|
608733 |
@@ -538,8 +558,10 @@ do_map_only:
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
bailout:
|
|
|
608733 |
- FREEBUF(bpf->proglist);
|
|
|
608733 |
- FREEBUF(bpf->maplist);
|
|
|
608733 |
+ if (bpf->proglist)
|
|
|
608733 |
+ FREEBUF(bpf->proglist);
|
|
|
608733 |
+ if (bpf->maplist)
|
|
|
608733 |
+ FREEBUF(bpf->maplist);
|
|
|
608733 |
FREEBUF(bpf->bpf_prog_buf);
|
|
|
608733 |
FREEBUF(bpf->bpf_prog_aux_buf);
|
|
|
608733 |
FREEBUF(bpf->bpf_map_buf);
|
|
|
608733 |
@@ -1255,3 +1277,50 @@ print_boot_time(unsigned long long nsecs, char *buf, unsigned int size)
|
|
|
608733 |
sprintf(buf, "(unknown)");
|
|
|
608733 |
#endif
|
|
|
608733 |
}
|
|
|
608733 |
+
|
|
|
608733 |
+/*
|
|
|
608733 |
+ * Borrow the old (pre-radix_tree) IDR facility code used by
|
|
|
608733 |
+ * the ipcs command.
|
|
|
608733 |
+ */
|
|
|
608733 |
+static int
|
|
|
608733 |
+do_old_idr(int cmd, ulong idr, struct radix_tree_pair *rtp)
|
|
|
608733 |
+{
|
|
|
608733 |
+ int i, max, cur, next_id, total = 0;
|
|
|
608733 |
+ ulong entry;
|
|
|
608733 |
+
|
|
|
608733 |
+ switch (cmd)
|
|
|
608733 |
+ {
|
|
|
608733 |
+ case OLD_IDR_INIT:
|
|
|
608733 |
+ ipcs_init();
|
|
|
608733 |
+ break;
|
|
|
608733 |
+
|
|
|
608733 |
+ case OLD_IDR_COUNT:
|
|
|
608733 |
+ readmem(idr + OFFSET(idr_cur), KVADDR, &cur,
|
|
|
608733 |
+ sizeof(int), "idr.cur", FAULT_ON_ERROR);
|
|
|
608733 |
+ for (total = next_id = 0; next_id < cur; next_id++) {
|
|
|
608733 |
+ entry = idr_find(idr, next_id);
|
|
|
608733 |
+ if (entry == 0)
|
|
|
608733 |
+ continue;
|
|
|
608733 |
+ total++;
|
|
|
608733 |
+ }
|
|
|
608733 |
+ break;
|
|
|
608733 |
+
|
|
|
608733 |
+ case OLD_IDR_GATHER:
|
|
|
608733 |
+ max = rtp[0].index;
|
|
|
608733 |
+ readmem(idr + OFFSET(idr_cur), KVADDR, &cur,
|
|
|
608733 |
+ sizeof(int), "idr.cur", FAULT_ON_ERROR);
|
|
|
608733 |
+ for (i = total = next_id = 0; next_id < cur; next_id++) {
|
|
|
608733 |
+ entry = idr_find(idr, next_id);
|
|
|
608733 |
+ if (entry == 0)
|
|
|
608733 |
+ continue;
|
|
|
608733 |
+ total++;
|
|
|
608733 |
+ rtp[i].index = next_id;
|
|
|
608733 |
+ rtp[i].value = (void *)entry;
|
|
|
608733 |
+ if (++i == max)
|
|
|
608733 |
+ break;
|
|
|
608733 |
+ }
|
|
|
608733 |
+ break;
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
+ return total;
|
|
|
608733 |
+}
|
|
|
608733 |
diff --git a/defs.h b/defs.h
|
|
|
608733 |
index e6e3850..b05aecc 100644
|
|
|
608733 |
--- a/defs.h
|
|
|
608733 |
+++ b/defs.h
|
|
|
608733 |
@@ -2031,6 +2031,7 @@ struct offset_table { /* stash of commonly-used offsets */
|
|
|
608733 |
long bpf_prog_aux_load_time;
|
|
|
608733 |
long bpf_prog_aux_user;
|
|
|
608733 |
long user_struct_uid;
|
|
|
608733 |
+ long idr_cur;
|
|
|
608733 |
};
|
|
|
608733 |
|
|
|
608733 |
struct size_table { /* stash of commonly-used sizes */
|
|
|
608733 |
@@ -5591,6 +5592,12 @@ enum {
|
|
|
608733 |
void dev_init(void);
|
|
|
608733 |
void dump_dev_table(void);
|
|
|
608733 |
|
|
|
608733 |
+/*
|
|
|
608733 |
+ * ipcs.c
|
|
|
608733 |
+ */
|
|
|
608733 |
+void ipcs_init(void);
|
|
|
608733 |
+ulong idr_find(ulong, int);
|
|
|
608733 |
+
|
|
|
608733 |
#ifdef ARM
|
|
|
608733 |
void arm_init(int);
|
|
|
608733 |
void arm_dump_machdep_table(ulong);
|
|
|
608733 |
diff --git a/ipcs.c b/ipcs.c
|
|
|
608733 |
index ef51fdd..80f78e4 100644
|
|
|
608733 |
--- a/ipcs.c
|
|
|
608733 |
+++ b/ipcs.c
|
|
|
608733 |
@@ -79,13 +79,11 @@ struct ipcs_table {
|
|
|
608733 |
* function declaration
|
|
|
608733 |
*/
|
|
|
608733 |
|
|
|
608733 |
-static void ipcs_init(void);
|
|
|
608733 |
static int dump_shared_memory(int, ulong, int, ulong);
|
|
|
608733 |
static int dump_semaphore_arrays(int, ulong, int, ulong);
|
|
|
608733 |
static int dump_message_queues(int, ulong, int, ulong);
|
|
|
608733 |
static int ipc_search_idr(ulong, int, ulong, int (*)(ulong, int, ulong, int, int), int);
|
|
|
608733 |
static int ipc_search_array(ulong, int, ulong, int (*)(ulong, int, ulong, int, int), int);
|
|
|
608733 |
-static ulong idr_find(ulong, int);
|
|
|
608733 |
static int dump_shm_info(ulong, int, ulong, int, int);
|
|
|
608733 |
static int dump_sem_info(ulong, int, ulong, int, int);
|
|
|
608733 |
static int dump_msg_info(ulong, int, ulong, int, int);
|
|
|
608733 |
@@ -101,7 +99,7 @@ static void gather_radix_tree_entries(ulong);
|
|
|
608733 |
*/
|
|
|
608733 |
static struct ipcs_table ipcs_table = { 0 };
|
|
|
608733 |
|
|
|
608733 |
-static void
|
|
|
608733 |
+void
|
|
|
608733 |
ipcs_init(void)
|
|
|
608733 |
{
|
|
|
608733 |
if (ipcs_table.init_flags & IPCS_INIT) {
|
|
|
608733 |
@@ -119,6 +117,7 @@ ipcs_init(void)
|
|
|
608733 |
MEMBER_OFFSET_INIT(idr_layer_layer, "idr_layer", "layer");
|
|
|
608733 |
MEMBER_OFFSET_INIT(idr_layer_ary, "idr_layer", "ary");
|
|
|
608733 |
MEMBER_OFFSET_INIT(idr_top, "idr", "top");
|
|
|
608733 |
+ MEMBER_OFFSET_INIT(idr_cur, "idr", "cur");
|
|
|
608733 |
MEMBER_OFFSET_INIT(ipc_id_ary_p, "ipc_id_ary", "p");
|
|
|
608733 |
MEMBER_OFFSET_INIT(ipc_ids_entries, "ipc_ids", "entries");
|
|
|
608733 |
MEMBER_OFFSET_INIT(ipc_ids_max_id, "ipc_ids", "max_id");
|
|
|
608733 |
@@ -188,7 +187,10 @@ ipcs_init(void)
|
|
|
608733 |
ipcs_table.shm_f_op_huge_addr = -1;
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
- if (BITS32())
|
|
|
608733 |
+ if (VALID_MEMBER(idr_layer_ary) &&
|
|
|
608733 |
+ get_array_length("idr_layer.ary", NULL, 0) > 64)
|
|
|
608733 |
+ ipcs_table.idr_bits = 8;
|
|
|
608733 |
+ else if (BITS32())
|
|
|
608733 |
ipcs_table.idr_bits = 5;
|
|
|
608733 |
else if (BITS64())
|
|
|
608733 |
ipcs_table.idr_bits = 6;
|
|
|
608733 |
@@ -635,7 +637,7 @@ ipc_search_idr(ulong ipc_ids_p, int specified, ulong specified_value, int (*fn)(
|
|
|
608733 |
/*
|
|
|
608733 |
* search every idr_layer
|
|
|
608733 |
*/
|
|
|
608733 |
-static ulong
|
|
|
608733 |
+ulong
|
|
|
608733 |
idr_find(ulong idp, int id)
|
|
|
608733 |
{
|
|
|
608733 |
ulong idr_layer_p;
|
|
|
608733 |
diff --git a/symbols.c b/symbols.c
|
|
|
608733 |
index bf55319..8ff1430 100644
|
|
|
608733 |
--- a/symbols.c
|
|
|
608733 |
+++ b/symbols.c
|
|
|
608733 |
@@ -10055,6 +10055,8 @@ dump_offset_table(char *spec, ulong makestruct)
|
|
|
608733 |
OFFSET(idr_layers));
|
|
|
608733 |
fprintf(fp, " idr_top: %ld\n",
|
|
|
608733 |
OFFSET(idr_top));
|
|
|
608733 |
+ fprintf(fp, " idr_cur: %ld\n",
|
|
|
608733 |
+ OFFSET(idr_cur));
|
|
|
608733 |
fprintf(fp, " ipc_id_ary_p: %ld\n",
|
|
|
608733 |
OFFSET(ipc_id_ary_p));
|
|
|
608733 |
fprintf(fp, " ipc_ids_entries: %ld\n",
|
|
|
608733 |
|
|
|
608733 |
commit b21633026a725a10b9394aabc65d8c57d5bbe33a
|
|
|
608733 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
608733 |
Date: Tue Jul 10 15:24:38 2018 -0400
|
|
|
608733 |
|
|
|
608733 |
Third phase of support for x86_64 5-level page tables in Linux 4.17
|
|
|
608733 |
and later kernels. With this patch, the usage of 5-level page tables
|
|
|
608733 |
is automatically detected on live systems and when running against
|
|
|
608733 |
vmcores that contain the new "NUMBER(pgtable_l5_enabled)" VMCOREINFO
|
|
|
608733 |
entry. Without the patch, the "--machdep vm=5level" command line
|
|
|
608733 |
option is required.
|
|
|
608733 |
(douly.fnst@cn.fujitsu.com, anderson@redhat.com)
|
|
|
608733 |
|
|
|
608733 |
diff --git a/x86_64.c b/x86_64.c
|
|
|
608733 |
index 6d1ae2f..b07d6f2 100644
|
|
|
608733 |
--- a/x86_64.c
|
|
|
608733 |
+++ b/x86_64.c
|
|
|
608733 |
@@ -294,25 +294,6 @@ x86_64_init(int when)
|
|
|
608733 |
machdep->machspec->pgdir_shift = PGDIR_SHIFT;
|
|
|
608733 |
machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD;
|
|
|
608733 |
break;
|
|
|
608733 |
-
|
|
|
608733 |
- case VM_5LEVEL:
|
|
|
608733 |
- machdep->machspec->userspace_top = USERSPACE_TOP_5LEVEL;
|
|
|
608733 |
- machdep->machspec->page_offset = PAGE_OFFSET_5LEVEL;
|
|
|
608733 |
- machdep->machspec->vmalloc_start_addr = VMALLOC_START_ADDR_5LEVEL;
|
|
|
608733 |
- machdep->machspec->vmalloc_end = VMALLOC_END_5LEVEL;
|
|
|
608733 |
- machdep->machspec->modules_vaddr = MODULES_VADDR_5LEVEL;
|
|
|
608733 |
- machdep->machspec->modules_end = MODULES_END_5LEVEL;
|
|
|
608733 |
- machdep->machspec->vmemmap_vaddr = VMEMMAP_VADDR_5LEVEL;
|
|
|
608733 |
- machdep->machspec->vmemmap_end = VMEMMAP_END_5LEVEL;
|
|
|
608733 |
- if (symbol_exists("vmemmap_populate"))
|
|
|
608733 |
- machdep->flags |= VMEMMAP;
|
|
|
608733 |
- machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_5LEVEL;
|
|
|
608733 |
- machdep->machspec->pgdir_shift = PGDIR_SHIFT_5LEVEL;
|
|
|
608733 |
- machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD_5LEVEL;
|
|
|
608733 |
- if ((machdep->machspec->p4d = (char *)malloc(PAGESIZE())) == NULL)
|
|
|
608733 |
- error(FATAL, "cannot malloc p4d space.");
|
|
|
608733 |
- machdep->machspec->last_p4d_read = 0;
|
|
|
608733 |
- machdep->uvtop = x86_64_uvtop_level4; /* 5-level is optional per-task */
|
|
|
608733 |
}
|
|
|
608733 |
machdep->kvbase = (ulong)PAGE_OFFSET;
|
|
|
608733 |
machdep->identity_map_base = (ulong)PAGE_OFFSET;
|
|
|
608733 |
@@ -346,6 +327,43 @@ x86_64_init(int when)
|
|
|
608733 |
break;
|
|
|
608733 |
|
|
|
608733 |
case POST_RELOC:
|
|
|
608733 |
+ /* Check for 5-level paging */
|
|
|
608733 |
+ if (!(machdep->flags & VM_5LEVEL)) {
|
|
|
608733 |
+ int l5_enabled = 0;
|
|
|
608733 |
+ if ((string = pc->read_vmcoreinfo("NUMBER(pgtable_l5_enabled)"))) {
|
|
|
608733 |
+ l5_enabled = atoi(string);
|
|
|
608733 |
+ free(string);
|
|
|
608733 |
+ } else if (kernel_symbol_exists("__pgtable_l5_enabled"))
|
|
|
608733 |
+ readmem(symbol_value("__pgtable_l5_enabled"), KVADDR,
|
|
|
608733 |
+ &l5_enabled, sizeof(int), "__pgtable_l5_enabled",
|
|
|
608733 |
+ FAULT_ON_ERROR);
|
|
|
608733 |
+
|
|
|
608733 |
+ if (l5_enabled)
|
|
|
608733 |
+ machdep->flags |= VM_5LEVEL;
|
|
|
608733 |
+ }
|
|
|
608733 |
+ if (machdep->flags & VM_5LEVEL) {
|
|
|
608733 |
+ machdep->machspec->userspace_top = USERSPACE_TOP_5LEVEL;
|
|
|
608733 |
+ machdep->machspec->page_offset = PAGE_OFFSET_5LEVEL;
|
|
|
608733 |
+ machdep->machspec->vmalloc_start_addr = VMALLOC_START_ADDR_5LEVEL;
|
|
|
608733 |
+ machdep->machspec->vmalloc_end = VMALLOC_END_5LEVEL;
|
|
|
608733 |
+ machdep->machspec->modules_vaddr = MODULES_VADDR_5LEVEL;
|
|
|
608733 |
+ machdep->machspec->modules_end = MODULES_END_5LEVEL;
|
|
|
608733 |
+ machdep->machspec->vmemmap_vaddr = VMEMMAP_VADDR_5LEVEL;
|
|
|
608733 |
+ machdep->machspec->vmemmap_end = VMEMMAP_END_5LEVEL;
|
|
|
608733 |
+ if (symbol_exists("vmemmap_populate"))
|
|
|
608733 |
+ machdep->flags |= VMEMMAP;
|
|
|
608733 |
+ machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_5LEVEL;
|
|
|
608733 |
+ machdep->machspec->pgdir_shift = PGDIR_SHIFT_5LEVEL;
|
|
|
608733 |
+ machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD_5LEVEL;
|
|
|
608733 |
+ if ((machdep->machspec->p4d = (char *)malloc(PAGESIZE())) == NULL)
|
|
|
608733 |
+ error(FATAL, "cannot malloc p4d space.");
|
|
|
608733 |
+ machdep->machspec->last_p4d_read = 0;
|
|
|
608733 |
+ machdep->uvtop = x86_64_uvtop_level4; /* 5-level is optional per-task */
|
|
|
608733 |
+ machdep->kvbase = (ulong)PAGE_OFFSET;
|
|
|
608733 |
+ machdep->identity_map_base = (ulong)PAGE_OFFSET;
|
|
|
608733 |
+
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
/*
|
|
|
608733 |
* Check for CONFIG_RANDOMIZE_MEMORY, and set page_offset here.
|
|
|
608733 |
* The remainder of the virtual address range setups will get
|
|
|
608733 |
|
|
|
608733 |
commit 6596f1121b89162f96d1e1825c2905b83b59bec1
|
|
|
608733 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
608733 |
Date: Wed Jul 11 16:25:59 2018 -0400
|
|
|
608733 |
|
|
|
608733 |
The existing "list" command uses a hash table to detect duplicate
|
|
|
608733 |
items as it traverses the list. The hash table approach has worked
|
|
|
608733 |
well for many years. However, with increasing memory sizes and list
|
|
|
608733 |
sizes, the overhead of the hash table can be substantial, often
|
|
|
608733 |
leading to commands running for a very long time. For large lists,
|
|
|
608733 |
we have found that the existing hash based approach may slow the
|
|
|
608733 |
system to a crawl and possibly never complete. You can turn off
|
|
|
608733 |
the hash with "set hash off" but then there is no loop detection; in
|
|
|
608733 |
that case, loop detection must be done manually after dumping the
|
|
|
608733 |
list to disk or some other method. This patch is an implementation
|
|
|
608733 |
of the cycle detection algorithm from R. P. Brent as an alternative
|
|
|
608733 |
algorithm for the "list" command. The algorithm both avoids the
|
|
|
608733 |
overhead of the hash table and yet is able to detect a loop. In
|
|
|
608733 |
addition, further loop characteristics are printed, such as the
|
|
|
608733 |
distance to the start of the loop as well as the loop length.
|
|
|
608733 |
An excellent description of the algorithm can be found here on
|
|
|
608733 |
the crash-utility mailing list:
|
|
|
608733 |
|
|
|
608733 |
https://www.redhat.com/archives/crash-utility/2018-July/msg00019.html
|
|
|
608733 |
|
|
|
608733 |
A new "list -B" option has been added to the "list" command to
|
|
|
608733 |
invoke this new algorithm rather than using the hash table. In
|
|
|
608733 |
addition to low memory usage, the output of the list command is
|
|
|
608733 |
slightly different when a loop is detected. In addition to printing
|
|
|
608733 |
the first duplicate entry, the length of the loop, and the distance
|
|
|
608733 |
to the loop is output.
|
|
|
608733 |
(dwysocha@redhat.com)
|
|
|
608733 |
|
|
|
608733 |
diff --git a/defs.h b/defs.h
|
|
|
608733 |
index b05aecc..5af82be 100644
|
|
|
608733 |
--- a/defs.h
|
|
|
608733 |
+++ b/defs.h
|
|
|
608733 |
@@ -2491,6 +2491,7 @@ struct list_data { /* generic structure used by do_list() to walk */
|
|
|
608733 |
#define CALLBACK_RETURN (VERBOSE << 12)
|
|
|
608733 |
#define LIST_PARSE_MEMBER (VERBOSE << 13)
|
|
|
608733 |
#define LIST_READ_MEMBER (VERBOSE << 14)
|
|
|
608733 |
+#define LIST_BRENT_ALGO (VERBOSE << 15)
|
|
|
608733 |
|
|
|
608733 |
struct tree_data {
|
|
|
608733 |
ulong flags;
|
|
|
608733 |
@@ -4944,6 +4945,7 @@ char *shift_string_right(char *, int);
|
|
|
608733 |
int bracketed(char *, char *, int);
|
|
|
608733 |
void backspace(int);
|
|
|
608733 |
int do_list(struct list_data *);
|
|
|
608733 |
+int do_list_no_hash(struct list_data *);
|
|
|
608733 |
struct radix_tree_ops {
|
|
|
608733 |
void (*entry)(ulong node, ulong slot, const char *path,
|
|
|
608733 |
ulong index, void *private);
|
|
|
608733 |
diff --git a/help.c b/help.c
|
|
|
608733 |
index 638c6ec..54bf9b4 100644
|
|
|
608733 |
--- a/help.c
|
|
|
608733 |
+++ b/help.c
|
|
|
608733 |
@@ -5724,7 +5724,7 @@ char *help__list[] = {
|
|
|
608733 |
"list",
|
|
|
608733 |
"linked list",
|
|
|
608733 |
"[[-o] offset][-e end][-[s|S] struct[.member[,member] [-l offset]] -[x|d]]"
|
|
|
608733 |
-"\n [-r|-h|-H] start",
|
|
|
608733 |
+"\n [-r|-B] [-h|-H] start",
|
|
|
608733 |
" ",
|
|
|
608733 |
" This command dumps the contents of a linked list. The entries in a linked",
|
|
|
608733 |
" list are typically data structures that are tied together in one of two",
|
|
|
608733 |
@@ -5822,6 +5822,12 @@ char *help__list[] = {
|
|
|
608733 |
" -r For a list linked with list_head structures, traverse the list",
|
|
|
608733 |
" in the reverse order by using the \"prev\" pointer instead",
|
|
|
608733 |
" of \"next\".",
|
|
|
608733 |
+" -B Use the algorithm from R. P. Brent to detect loops instead of",
|
|
|
608733 |
+" using a hash table. This algorithm uses a tiny fixed amount of",
|
|
|
608733 |
+" memory and so is especially helpful for longer lists. The output",
|
|
|
608733 |
+" is slightly different than the normal list output as it will",
|
|
|
608733 |
+" print the length of the loop, the start of the loop, and the",
|
|
|
608733 |
+" first duplicate in the list.",
|
|
|
608733 |
" ",
|
|
|
608733 |
" The meaning of the \"start\" argument, which can be expressed symbolically,",
|
|
|
608733 |
" in hexadecimal format, or an expression evaluating to an address, depends",
|
|
|
608733 |
diff --git a/tools.c b/tools.c
|
|
|
608733 |
index 1a83643..634aec6 100644
|
|
|
608733 |
--- a/tools.c
|
|
|
608733 |
+++ b/tools.c
|
|
|
608733 |
@@ -3266,9 +3266,12 @@ cmd_list(void)
|
|
|
608733 |
BZERO(ld, sizeof(struct list_data));
|
|
|
608733 |
struct_list_offset = 0;
|
|
|
608733 |
|
|
|
608733 |
- while ((c = getopt(argcnt, args, "Hhrs:S:e:o:xdl:")) != EOF) {
|
|
|
608733 |
+ while ((c = getopt(argcnt, args, "BHhrs:S:e:o:xdl:")) != EOF) {
|
|
|
608733 |
switch(c)
|
|
|
608733 |
{
|
|
|
608733 |
+ case 'B':
|
|
|
608733 |
+ ld->flags |= LIST_BRENT_ALGO;
|
|
|
608733 |
+ break;
|
|
|
608733 |
case 'H':
|
|
|
608733 |
ld->flags |= LIST_HEAD_FORMAT;
|
|
|
608733 |
ld->flags |= LIST_HEAD_POINTER;
|
|
|
608733 |
@@ -3516,9 +3519,13 @@ next_arg:
|
|
|
608733 |
ld->flags &= ~(LIST_OFFSET_ENTERED|LIST_START_ENTERED);
|
|
|
608733 |
ld->flags |= VERBOSE;
|
|
|
608733 |
|
|
|
608733 |
- hq_open();
|
|
|
608733 |
- c = do_list(ld);
|
|
|
608733 |
- hq_close();
|
|
|
608733 |
+ if (ld->flags & LIST_BRENT_ALGO)
|
|
|
608733 |
+ c = do_list_no_hash(ld);
|
|
|
608733 |
+ else {
|
|
|
608733 |
+ hq_open();
|
|
|
608733 |
+ c = do_list(ld);
|
|
|
608733 |
+ hq_close();
|
|
|
608733 |
+ }
|
|
|
608733 |
|
|
|
608733 |
if (ld->structname_args)
|
|
|
608733 |
FREEBUF(ld->structname);
|
|
|
608733 |
@@ -3862,6 +3869,283 @@ do_list(struct list_data *ld)
|
|
|
608733 |
return count;
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
+static void
|
|
|
608733 |
+do_list_debug_entry(struct list_data *ld)
|
|
|
608733 |
+{
|
|
|
608733 |
+ int i, others;
|
|
|
608733 |
+
|
|
|
608733 |
+ if (CRASHDEBUG(1)) {
|
|
|
608733 |
+ others = 0;
|
|
|
608733 |
+ console(" flags: %lx (", ld->flags);
|
|
|
608733 |
+ if (ld->flags & VERBOSE)
|
|
|
608733 |
+ console("%sVERBOSE", others++ ? "|" : "");
|
|
|
608733 |
+ if (ld->flags & LIST_OFFSET_ENTERED)
|
|
|
608733 |
+ console("%sLIST_OFFSET_ENTERED", others++ ? "|" : "");
|
|
|
608733 |
+ if (ld->flags & LIST_START_ENTERED)
|
|
|
608733 |
+ console("%sLIST_START_ENTERED", others++ ? "|" : "");
|
|
|
608733 |
+ if (ld->flags & LIST_HEAD_FORMAT)
|
|
|
608733 |
+ console("%sLIST_HEAD_FORMAT", others++ ? "|" : "");
|
|
|
608733 |
+ if (ld->flags & LIST_HEAD_POINTER)
|
|
|
608733 |
+ console("%sLIST_HEAD_POINTER", others++ ? "|" : "");
|
|
|
608733 |
+ if (ld->flags & RETURN_ON_DUPLICATE)
|
|
|
608733 |
+ console("%sRETURN_ON_DUPLICATE", others++ ? "|" : "");
|
|
|
608733 |
+ if (ld->flags & RETURN_ON_LIST_ERROR)
|
|
|
608733 |
+ console("%sRETURN_ON_LIST_ERROR", others++ ? "|" : "");
|
|
|
608733 |
+ if (ld->flags & RETURN_ON_LIST_ERROR)
|
|
|
608733 |
+ console("%sRETURN_ON_LIST_ERROR", others++ ? "|" : "");
|
|
|
608733 |
+ if (ld->flags & LIST_STRUCT_RADIX_10)
|
|
|
608733 |
+ console("%sLIST_STRUCT_RADIX_10", others++ ? "|" : "");
|
|
|
608733 |
+ if (ld->flags & LIST_STRUCT_RADIX_16)
|
|
|
608733 |
+ console("%sLIST_STRUCT_RADIX_16", others++ ? "|" : "");
|
|
|
608733 |
+ if (ld->flags & LIST_ALLOCATE)
|
|
|
608733 |
+ console("%sLIST_ALLOCATE", others++ ? "|" : "");
|
|
|
608733 |
+ if (ld->flags & LIST_CALLBACK)
|
|
|
608733 |
+ console("%sLIST_CALLBACK", others++ ? "|" : "");
|
|
|
608733 |
+ if (ld->flags & CALLBACK_RETURN)
|
|
|
608733 |
+ console("%sCALLBACK_RETURN", others++ ? "|" : "");
|
|
|
608733 |
+ console(")\n");
|
|
|
608733 |
+ console(" start: %lx\n", ld->start);
|
|
|
608733 |
+ console(" member_offset: %ld\n", ld->member_offset);
|
|
|
608733 |
+ console(" list_head_offset: %ld\n", ld->list_head_offset);
|
|
|
608733 |
+ console(" end: %lx\n", ld->end);
|
|
|
608733 |
+ console(" searchfor: %lx\n", ld->searchfor);
|
|
|
608733 |
+ console(" structname_args: %lx\n", ld->structname_args);
|
|
|
608733 |
+ if (!ld->structname_args)
|
|
|
608733 |
+ console(" structname: (unused)\n");
|
|
|
608733 |
+ for (i = 0; i < ld->structname_args; i++)
|
|
|
608733 |
+ console(" structname[%d]: %s\n", i, ld->structname[i]);
|
|
|
608733 |
+ console(" header: %s\n", ld->header);
|
|
|
608733 |
+ console(" list_ptr: %lx\n", (ulong)ld->list_ptr);
|
|
|
608733 |
+ console(" callback_func: %lx\n", (ulong)ld->callback_func);
|
|
|
608733 |
+ console(" callback_data: %lx\n", (ulong)ld->callback_data);
|
|
|
608733 |
+ console("struct_list_offset: %lx\n", ld->struct_list_offset);
|
|
|
608733 |
+ }
|
|
|
608733 |
+}
|
|
|
608733 |
+
|
|
|
608733 |
+
|
|
|
608733 |
+static void
|
|
|
608733 |
+do_list_output_struct(struct list_data *ld, ulong next, ulong offset,
|
|
|
608733 |
+ unsigned int radix, struct req_entry **e)
|
|
|
608733 |
+{
|
|
|
608733 |
+ int i;
|
|
|
608733 |
+
|
|
|
608733 |
+ for (i = 0; i < ld->structname_args; i++) {
|
|
|
608733 |
+ switch (count_chars(ld->structname[i], '.'))
|
|
|
608733 |
+ {
|
|
|
608733 |
+ case 0:
|
|
|
608733 |
+ dump_struct(ld->structname[i],
|
|
|
608733 |
+ next - offset, radix);
|
|
|
608733 |
+ break;
|
|
|
608733 |
+ default:
|
|
|
608733 |
+ if (ld->flags & LIST_PARSE_MEMBER)
|
|
|
608733 |
+ dump_struct_members(ld, i, next);
|
|
|
608733 |
+ else if (ld->flags & LIST_READ_MEMBER)
|
|
|
608733 |
+ dump_struct_members_fast(e[i],
|
|
|
608733 |
+ radix, next - offset);
|
|
|
608733 |
+ break;
|
|
|
608733 |
+ }
|
|
|
608733 |
+ }
|
|
|
608733 |
+}
|
|
|
608733 |
+
|
|
|
608733 |
+static int
|
|
|
608733 |
+do_list_no_hash_readmem(struct list_data *ld, ulong *next_ptr,
|
|
|
608733 |
+ ulong readflag)
|
|
|
608733 |
+{
|
|
|
608733 |
+ if (!readmem(*next_ptr + ld->member_offset, KVADDR, next_ptr,
|
|
|
608733 |
+ sizeof(void *), "list entry", readflag)) {
|
|
|
608733 |
+ error(INFO, "\ninvalid list entry: %lx\n", *next_ptr);
|
|
|
608733 |
+ return -1;
|
|
|
608733 |
+ }
|
|
|
608733 |
+ return 0;
|
|
|
608733 |
+}
|
|
|
608733 |
+
|
|
|
608733 |
+static ulong brent_x; /* tortoise */
|
|
|
608733 |
+static ulong brent_y; /* hare */
|
|
|
608733 |
+static ulong brent_r; /* power */
|
|
|
608733 |
+static ulong brent_lambda; /* loop length */
|
|
|
608733 |
+static ulong brent_mu; /* distance to start of loop */
|
|
|
608733 |
+static ulong brent_loop_detect;
|
|
|
608733 |
+static ulong brent_loop_exit;
|
|
|
608733 |
+/*
|
|
|
608733 |
+ * 'ptr': representative of x or y; modified on return
|
|
|
608733 |
+ */
|
|
|
608733 |
+static int
|
|
|
608733 |
+brent_f(ulong *ptr, struct list_data *ld, ulong readflag)
|
|
|
608733 |
+{
|
|
|
608733 |
+ return do_list_no_hash_readmem(ld, ptr, readflag);
|
|
|
608733 |
+}
|
|
|
608733 |
+
|
|
|
608733 |
+/*
|
|
|
608733 |
+ * Similar to do_list() but without the hash_table or LIST_ALLOCATE.
|
|
|
608733 |
+ * Useful for the 'list' command and other callers needing faster list
|
|
|
608733 |
+ * enumeration.
|
|
|
608733 |
+ */
|
|
|
608733 |
+int
|
|
|
608733 |
+do_list_no_hash(struct list_data *ld)
|
|
|
608733 |
+{
|
|
|
608733 |
+ ulong next, last, first, offset;
|
|
|
608733 |
+ ulong searchfor, readflag;
|
|
|
608733 |
+ int i, count, ret;
|
|
|
608733 |
+ unsigned int radix;
|
|
|
608733 |
+ struct req_entry **e = NULL;
|
|
|
608733 |
+
|
|
|
608733 |
+ do_list_debug_entry(ld);
|
|
|
608733 |
+
|
|
|
608733 |
+ count = 0;
|
|
|
608733 |
+ searchfor = ld->searchfor;
|
|
|
608733 |
+ ld->searchfor = 0;
|
|
|
608733 |
+ if (ld->flags & LIST_STRUCT_RADIX_10)
|
|
|
608733 |
+ radix = 10;
|
|
|
608733 |
+ else if (ld->flags & LIST_STRUCT_RADIX_16)
|
|
|
608733 |
+ radix = 16;
|
|
|
608733 |
+ else
|
|
|
608733 |
+ radix = 0;
|
|
|
608733 |
+ next = ld->start;
|
|
|
608733 |
+
|
|
|
608733 |
+ readflag = ld->flags & RETURN_ON_LIST_ERROR ?
|
|
|
608733 |
+ (RETURN_ON_ERROR|QUIET) : FAULT_ON_ERROR;
|
|
|
608733 |
+
|
|
|
608733 |
+ if (!readmem(next + ld->member_offset, KVADDR, &first, sizeof(void *),
|
|
|
608733 |
+ "first list entry", readflag)) {
|
|
|
608733 |
+ error(INFO, "\ninvalid list entry: %lx\n", next);
|
|
|
608733 |
+ return -1;
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
+ if (ld->header)
|
|
|
608733 |
+ fprintf(fp, "%s", ld->header);
|
|
|
608733 |
+
|
|
|
608733 |
+ offset = ld->list_head_offset + ld->struct_list_offset;
|
|
|
608733 |
+
|
|
|
608733 |
+ if (ld->structname && (ld->flags & LIST_READ_MEMBER)) {
|
|
|
608733 |
+ e = (struct req_entry **)GETBUF(sizeof(*e) * ld->structname_args);
|
|
|
608733 |
+ for (i = 0; i < ld->structname_args; i++)
|
|
|
608733 |
+ e[i] = fill_member_offsets(ld->structname[i]);
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
+ brent_loop_detect = brent_loop_exit = 0;
|
|
|
608733 |
+ brent_lambda = 0;
|
|
|
608733 |
+ brent_r = 2;
|
|
|
608733 |
+ brent_x = brent_y = next;
|
|
|
608733 |
+ ret = brent_f(&brent_y, ld, readflag);
|
|
|
608733 |
+ if (ret == -1)
|
|
|
608733 |
+ return -1;
|
|
|
608733 |
+ while (1) {
|
|
|
608733 |
+ if (!brent_loop_detect && ld->flags & VERBOSE) {
|
|
|
608733 |
+ fprintf(fp, "%lx\n", next - ld->list_head_offset);
|
|
|
608733 |
+ if (ld->structname) {
|
|
|
608733 |
+ do_list_output_struct(ld, next, offset, radix, e);
|
|
|
608733 |
+ }
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
+ if (next && brent_loop_exit) {
|
|
|
608733 |
+ if (ld->flags &
|
|
|
608733 |
+ (RETURN_ON_DUPLICATE|RETURN_ON_LIST_ERROR)) {
|
|
|
608733 |
+ error(INFO, "\nduplicate list entry: %lx\n",
|
|
|
608733 |
+ brent_x);
|
|
|
608733 |
+ return -1;
|
|
|
608733 |
+ }
|
|
|
608733 |
+ error(FATAL, "\nduplicate list entry: %lx\n", brent_x);
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
+ if ((searchfor == next) ||
|
|
|
608733 |
+ (searchfor == (next - ld->list_head_offset)))
|
|
|
608733 |
+ ld->searchfor = searchfor;
|
|
|
608733 |
+
|
|
|
608733 |
+ count++;
|
|
|
608733 |
+ last = next;
|
|
|
608733 |
+
|
|
|
608733 |
+ if ((ld->flags & LIST_CALLBACK) &&
|
|
|
608733 |
+ ld->callback_func((void *)(next - ld->list_head_offset),
|
|
|
608733 |
+ ld->callback_data) && (ld->flags & CALLBACK_RETURN))
|
|
|
608733 |
+ break;
|
|
|
608733 |
+
|
|
|
608733 |
+ ret = do_list_no_hash_readmem(ld, &next, readflag);
|
|
|
608733 |
+ if (ret == -1)
|
|
|
608733 |
+ return -1;
|
|
|
608733 |
+
|
|
|
608733 |
+ if (!brent_loop_detect) {
|
|
|
608733 |
+ if (brent_x == brent_y) {
|
|
|
608733 |
+ brent_loop_detect = 1;
|
|
|
608733 |
+ error(INFO, "loop detected, loop length: %lx\n", brent_lambda);
|
|
|
608733 |
+ /* reset x and y to start; advance y loop length */
|
|
|
608733 |
+ brent_mu = 0;
|
|
|
608733 |
+ brent_x = brent_y = ld->start;
|
|
|
608733 |
+ while (brent_lambda--) {
|
|
|
608733 |
+ ret = brent_f(&brent_y, ld, readflag);
|
|
|
608733 |
+ if (ret == -1)
|
|
|
608733 |
+ return -1;
|
|
|
608733 |
+ }
|
|
|
608733 |
+ } else {
|
|
|
608733 |
+ if (brent_r == brent_lambda) {
|
|
|
608733 |
+ brent_x = brent_y;
|
|
|
608733 |
+ brent_r *= 2;
|
|
|
608733 |
+ brent_lambda = 0;
|
|
|
608733 |
+ }
|
|
|
608733 |
+ brent_y = next;
|
|
|
608733 |
+ brent_lambda++;
|
|
|
608733 |
+ }
|
|
|
608733 |
+ } else {
|
|
|
608733 |
+ if (!brent_loop_exit && brent_x == brent_y) {
|
|
|
608733 |
+ brent_loop_exit = 1;
|
|
|
608733 |
+ error(INFO, "length from start to loop: %lx",
|
|
|
608733 |
+ brent_mu);
|
|
|
608733 |
+ } else {
|
|
|
608733 |
+ ret = brent_f(&brent_x, ld, readflag);
|
|
|
608733 |
+ if (ret == -1)
|
|
|
608733 |
+ return -1;
|
|
|
608733 |
+ ret = brent_f(&brent_y, ld, readflag);
|
|
|
608733 |
+ if (ret == -1)
|
|
|
608733 |
+ return -1;
|
|
|
608733 |
+ brent_mu++;
|
|
|
608733 |
+ }
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
+ if (next == 0) {
|
|
|
608733 |
+ if (ld->flags & LIST_HEAD_FORMAT) {
|
|
|
608733 |
+ error(INFO, "\ninvalid list entry: 0\n");
|
|
|
608733 |
+ return -1;
|
|
|
608733 |
+ }
|
|
|
608733 |
+ if (CRASHDEBUG(1))
|
|
|
608733 |
+ console("do_list end: next:%lx\n", next);
|
|
|
608733 |
+
|
|
|
608733 |
+ break;
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
+ if (next == ld->end) {
|
|
|
608733 |
+ if (CRASHDEBUG(1))
|
|
|
608733 |
+ console("do_list end: next:%lx == end:%lx\n",
|
|
|
608733 |
+ next, ld->end);
|
|
|
608733 |
+ break;
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
+ if (next == ld->start) {
|
|
|
608733 |
+ if (CRASHDEBUG(1))
|
|
|
608733 |
+ console("do_list end: next:%lx == start:%lx\n",
|
|
|
608733 |
+ next, ld->start);
|
|
|
608733 |
+ break;
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
+ if (next == last) {
|
|
|
608733 |
+ if (CRASHDEBUG(1))
|
|
|
608733 |
+ console("do_list end: next:%lx == last:%lx\n",
|
|
|
608733 |
+ next, last);
|
|
|
608733 |
+ break;
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
+ if ((next == first) && (count != 1)) {
|
|
|
608733 |
+ if (CRASHDEBUG(1))
|
|
|
608733 |
+ console("do_list end: next:%lx == first:%lx (count %d)\n",
|
|
|
608733 |
+ next, last, count);
|
|
|
608733 |
+ break;
|
|
|
608733 |
+ }
|
|
|
608733 |
+ }
|
|
|
608733 |
+
|
|
|
608733 |
+ if (CRASHDEBUG(1))
|
|
|
608733 |
+ console("do_list count: %d\n", count);
|
|
|
608733 |
+
|
|
|
608733 |
+ return count;
|
|
|
608733 |
+}
|
|
|
608733 |
+
|
|
|
608733 |
/*
|
|
|
608733 |
* Issue a dump_struct_member() call for one or more structure
|
|
|
608733 |
* members. Multiple members are passed in a comma-separated
|
|
|
608733 |
|
|
|
608733 |
commit 582f8b1ea4bb843f996d5285288e7a12b519ee73
|
|
|
608733 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
608733 |
Date: Thu Jul 12 14:06:22 2018 -0400
|
|
|
608733 |
|
|
|
608733 |
Fix for x86_64 "bt" command to prevent an in-kernel exception frame
|
|
|
608733 |
from not being displayed. Without the patch, if the RIP in a pt_regs
|
|
|
608733 |
structure on the stack is not a kernel text address, such as a NULL
|
|
|
608733 |
pointer, it is not recognized as an exception frame and the register
|
|
|
608733 |
set is not displayed.
|
|
|
608733 |
(anderson@redhat.com)
|
|
|
608733 |
|
|
|
608733 |
diff --git a/x86_64.c b/x86_64.c
|
|
|
608733 |
index b07d6f2..15800fb 100644
|
|
|
608733 |
--- a/x86_64.c
|
|
|
608733 |
+++ b/x86_64.c
|
|
|
608733 |
@@ -4662,6 +4662,8 @@ x86_64_eframe_verify(struct bt_info *bt, long kvaddr, long cs, long ss,
|
|
|
608733 |
STREQ(sp->name, "page_fault"))
|
|
|
608733 |
return TRUE;
|
|
|
608733 |
|
|
|
608733 |
+ if ((kvaddr + SIZE(pt_regs)) == rsp)
|
|
|
608733 |
+ return TRUE;
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
if ((cs == 0x10) && kvaddr) {
|
|
|
608733 |
@@ -8393,7 +8395,7 @@ x86_64_get_framesize(struct bt_info *bt, ulong textaddr, ulong rsp)
|
|
|
608733 |
*p1 = NULLCHAR;
|
|
|
608733 |
p2 = arglist[arg];
|
|
|
608733 |
reterror = 0;
|
|
|
608733 |
- offset = htol(p2+1, RETURN_ON_ERROR, &reterror);
|
|
|
608733 |
+ offset = htol(p2+1, RETURN_ON_ERROR|QUIET, &reterror);
|
|
|
608733 |
if (reterror)
|
|
|
608733 |
continue;
|
|
|
608733 |
framesize += offset;
|
|
|
608733 |
|
|
|
608733 |
commit 528849c15a02d9162c2dd17f4551390763711ad5
|
|
|
608733 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
608733 |
Date: Fri Jul 13 13:50:44 2018 -0400
|
|
|
608733 |
|
|
|
608733 |
Fix for the "repeat" command when the argument consists of an input
|
|
|
608733 |
file construct, for example, "repeat -1 < input_file". Without the
|
|
|
608733 |
patch, only the first command line in the input file is executed
|
|
|
608733 |
each time.
|
|
|
608733 |
(anderson@redhat.com)
|
|
|
608733 |
|
|
|
608733 |
diff --git a/cmdline.c b/cmdline.c
|
|
|
608733 |
index aab37ce..ee08f06 100644
|
|
|
608733 |
--- a/cmdline.c
|
|
|
608733 |
+++ b/cmdline.c
|
|
|
608733 |
@@ -1,8 +1,8 @@
|
|
|
608733 |
/* cmdline.c - core analysis suite
|
|
|
608733 |
*
|
|
|
608733 |
* Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
|
|
|
608733 |
- * Copyright (C) 2002-2015,2017 David Anderson
|
|
|
608733 |
- * Copyright (C) 2002-2015,2017 Red Hat, Inc. All rights reserved.
|
|
|
608733 |
+ * Copyright (C) 2002-2015,2018 David Anderson
|
|
|
608733 |
+ * Copyright (C) 2002-2015,2018 Red Hat, Inc. All rights reserved.
|
|
|
608733 |
*
|
|
|
608733 |
* This program is free software; you can redistribute it and/or modify
|
|
|
608733 |
* it under the terms of the GNU General Public License as published by
|
|
|
608733 |
@@ -2324,6 +2324,9 @@ is_args_input_file(struct command_table_entry *ct, struct args_input_file *aif)
|
|
|
608733 |
if (pc->curcmd_flags & NO_MODIFY)
|
|
|
608733 |
return FALSE;
|
|
|
608733 |
|
|
|
608733 |
+ if (STREQ(ct->name, "repeat"))
|
|
|
608733 |
+ return FALSE;
|
|
|
608733 |
+
|
|
|
608733 |
BZERO(aif, sizeof(struct args_input_file));
|
|
|
608733 |
retval = FALSE;
|
|
|
608733 |
|
|
|
608733 |
|
|
|
608733 |
commit 61fcad549faa479e6831d5283387f8f2e4ec9202
|
|
|
608733 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
608733 |
Date: Mon Jul 16 09:32:57 2018 -0400
|
|
|
608733 |
|
|
|
608733 |
Fourth phase of support for x86_64 5-level page tables in Linux 4.17
|
|
|
608733 |
and later kernels. This patch adds support for user virtual address
|
|
|
608733 |
translation when the kernel is configured with CONFIG_X86_5LEVEL.
|
|
|
608733 |
(douly.fnst@cn.fujitsu.com)
|
|
|
608733 |
|
|
|
608733 |
diff --git a/x86_64.c b/x86_64.c
|
|
|
608733 |
index 15800fb..4073acb 100644
|
|
|
608733 |
--- a/x86_64.c
|
|
|
608733 |
+++ b/x86_64.c
|
|
|
608733 |
@@ -24,7 +24,6 @@ static int x86_64_uvtop(struct task_context *, ulong, physaddr_t *, int);
|
|
|
608733 |
static int x86_64_uvtop_level4(struct task_context *, ulong, physaddr_t *, int);
|
|
|
608733 |
static int x86_64_uvtop_level4_xen_wpt(struct task_context *, ulong, physaddr_t *, int);
|
|
|
608733 |
static int x86_64_uvtop_level4_rhel4_xen_wpt(struct task_context *, ulong, physaddr_t *, int);
|
|
|
608733 |
-static int x86_64_task_uses_5level(struct task_context *);
|
|
|
608733 |
static ulong x86_64_vmalloc_start(void);
|
|
|
608733 |
static int x86_64_is_task_addr(ulong);
|
|
|
608733 |
static int x86_64_verify_symbol(const char *, ulong, char);
|
|
|
608733 |
@@ -341,6 +340,7 @@ x86_64_init(int when)
|
|
|
608733 |
if (l5_enabled)
|
|
|
608733 |
machdep->flags |= VM_5LEVEL;
|
|
|
608733 |
}
|
|
|
608733 |
+
|
|
|
608733 |
if (machdep->flags & VM_5LEVEL) {
|
|
|
608733 |
machdep->machspec->userspace_top = USERSPACE_TOP_5LEVEL;
|
|
|
608733 |
machdep->machspec->page_offset = PAGE_OFFSET_5LEVEL;
|
|
|
608733 |
@@ -361,7 +361,6 @@ x86_64_init(int when)
|
|
|
608733 |
machdep->uvtop = x86_64_uvtop_level4; /* 5-level is optional per-task */
|
|
|
608733 |
machdep->kvbase = (ulong)PAGE_OFFSET;
|
|
|
608733 |
machdep->identity_map_base = (ulong)PAGE_OFFSET;
|
|
|
608733 |
-
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
/*
|
|
|
608733 |
@@ -812,7 +811,7 @@ x86_64_dump_machdep_table(ulong arg)
|
|
|
608733 |
else if (machdep->uvtop == x86_64_uvtop_level4) {
|
|
|
608733 |
fprintf(fp, " uvtop: x86_64_uvtop_level4()");
|
|
|
608733 |
if (machdep->flags & VM_5LEVEL)
|
|
|
608733 |
- fprintf(fp, " or x86_64_uvtop_5level()");
|
|
|
608733 |
+ fprintf(fp, " (uses 5-level page tables)");
|
|
|
608733 |
fprintf(fp, "\n");
|
|
|
608733 |
} else if (machdep->uvtop == x86_64_uvtop_level4_xen_wpt)
|
|
|
608733 |
fprintf(fp, " uvtop: x86_64_uvtop_level4_xen_wpt()\n");
|
|
|
608733 |
@@ -1915,7 +1914,7 @@ x86_64_uvtop_level4(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, in
|
|
|
608733 |
goto no_upage;
|
|
|
608733 |
|
|
|
608733 |
/* If the VM is in 5-level page table */
|
|
|
608733 |
- if (machdep->flags & VM_5LEVEL && x86_64_task_uses_5level(tc)) {
|
|
|
608733 |
+ if (machdep->flags & VM_5LEVEL) {
|
|
|
608733 |
ulong p4d_pte;
|
|
|
608733 |
/*
|
|
|
608733 |
* p4d = p4d_offset(pgd, address);
|
|
|
608733 |
@@ -1987,12 +1986,6 @@ no_upage:
|
|
|
608733 |
}
|
|
|
608733 |
|
|
|
608733 |
static int
|
|
|
608733 |
-x86_64_task_uses_5level(struct task_context *tc)
|
|
|
608733 |
-{
|
|
|
608733 |
- return FALSE;
|
|
|
608733 |
-}
|
|
|
608733 |
-
|
|
|
608733 |
-static int
|
|
|
608733 |
x86_64_uvtop_level4_xen_wpt(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbose)
|
|
|
608733 |
{
|
|
|
608733 |
ulong pgd_pte;
|
|
|
608733 |
|
|
|
608733 |
commit eb823b79385f61be97411a06dd57b6fc0973d280
|
|
|
608733 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
608733 |
Date: Mon Jul 16 10:50:19 2018 -0400
|
|
|
608733 |
|
|
|
608733 |
Fix to prevent an unnecessary "read error" message during session
|
|
|
608733 |
initialization on live systems running a kernel that is configured
|
|
|
608733 |
with CONFIG_X86_5LEVEL. Without the patch, a message indicating
|
|
|
608733 |
"crash: read error: kernel virtual address: <address> type:
|
|
|
608733 |
__pgtable_l5_enabled" will be displayed if /proc/kcore gets
|
|
|
608733 |
selected as the live memory source after /dev/mem is determined
|
|
|
608733 |
to be unusable.
|
|
|
608733 |
(anderson@redhat.com)
|
|
|
608733 |
|
|
|
608733 |
diff --git a/x86_64.c b/x86_64.c
|
|
|
608733 |
index 4073acb..0574041 100644
|
|
|
608733 |
--- a/x86_64.c
|
|
|
608733 |
+++ b/x86_64.c
|
|
|
608733 |
@@ -335,7 +335,7 @@ x86_64_init(int when)
|
|
|
608733 |
} else if (kernel_symbol_exists("__pgtable_l5_enabled"))
|
|
|
608733 |
readmem(symbol_value("__pgtable_l5_enabled"), KVADDR,
|
|
|
608733 |
&l5_enabled, sizeof(int), "__pgtable_l5_enabled",
|
|
|
608733 |
- FAULT_ON_ERROR);
|
|
|
608733 |
+ QUIET|FAULT_ON_ERROR);
|
|
|
608733 |
|
|
|
608733 |
if (l5_enabled)
|
|
|
608733 |
machdep->flags |= VM_5LEVEL;
|