Blame SOURCES/github_9b494b70_to_eb823b79.patch

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;