From d54e5ff1ffb84704009a7ef9609711aa57634958 Mon Sep 17 00:00:00 2001
From: Vinayak Menon <vinayak.menon@broadcom.com>
Date: Fri, 29 Mar 2013 17:36:45 +0530
Subject: [PATCH] memory: adding an option to kmem to display the pagetypeinfo

Signed-off-by: Vinayak Menon <vinayakm.list@gmail.com>
---
 crash-6.0.8/help.c   |   22 ++++++-
 crash-6.0.8/memory.c |  179 ++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 194 insertions(+), 7 deletions(-)

diff --git a/crash-6.0.8/help.c b/crash-6.0.8/help.c
index 6d6ac5e..9ad6c00 100755
--- a/crash-6.0.8/help.c
+++ b/crash-6.0.8/help.c
@@ -5147,7 +5147,7 @@ NULL
 char *help_kmem[] = {
 "kmem",
 "kernel memory",
-"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-z-o] [slab] [[-P] address]\n"
+"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-m|-z-o] [slab] [[-P] address]\n"
 "       [-g [flags]]",
 "  This command displays information about the use of kernel memory.\n",
 "        -f  displays the contents of the system free memory headers.",
@@ -5174,6 +5174,8 @@ char *help_kmem[] = {
 "            values to translate them into kernel virtual addresses.",
 "        -g  displays the enumerator value of all bits in the page structure's",
 "            \"flags\" field.",
+"        -m  displays the number of pages per migrate type for all orders, for all",
+"            nodes.",
 "     flags  when used with -g, translates all bits in this hexadecimal page",
 "            structure flags value into its enumerator values.",
 "      slab  when used with -s or -S, limits the command to only the slab cache",
@@ -5605,6 +5607,24 @@ char *help_kmem[] = {
 "      PG_slab            7  0000080",
 "      PG_head           14  0004000",
 "    %s>",
+"\n  Display pages per migrate type for all orders, for all nodes:\n",
+"    %s> kmem -m",
+"    Free pages count per migrate type at order [0-10]:",
+"    Node    0, zone   Normal, type    Unmovable    155    172     92     39     20      8     10     15      7      3      1",
+"    Node    0, zone  HighMem, type    Unmovable      1      2      0      0      0      0      0      0      0      0      0",
+"    Node    0, zone  Movable, type    Unmovable      0      0      0      0      0      0      0      0      0      0      0",
+"    Node    0, zone   Normal, type  Reclaimable      9      3      0      0      1      1      0      0      0      0      0",
+"    Node    0, zone  HighMem, type  Reclaimable      0      0      0      0      0      0      0      0      0      0      0",
+"    Node    0, zone  Movable, type  Reclaimable      0      0      0      0      0      0      0      0      0      0      0",
+"    Node    0, zone   Normal, type      Movable      7     68     35    253    137     38     16      4      0      0     66",
+"    Node    0, zone  HighMem, type      Movable      0      1      0      0      0      0      0      0      0      0      0",
+"    Node    0, zone  Movable, type      Movable      0      0      0      0      0      0      0      0      0      0      0",
+"    Node    0, zone   Normal, type      Reserve      0      0      0      0      0      0      0      0      0      0      1",
+"    Node    0, zone  HighMem, type      Reserve     11      7      5      1      0      0      0      0      0      0      0",
+"    Node    0, zone  Movable, type      Reserve      0      0      0      0      0      0      0      0      0      0      0",
+"    Node    0, zone   Normal, type      Isolate      0      0      0      0      0      0      0      0      0      0      0",
+"    Node    0, zone  HighMem, type      Isolate      0      0      0      0      0      0      0      0      0      0      0",
+"    Node    0, zone  Movable, type      Isolate      0      0      0      0      0      0      0      0      0      0      0",
 NULL               
 };
 
diff --git a/crash-6.0.8/memory.c b/crash-6.0.8/memory.c
index 02a6de1..e03db84 100755
--- a/crash-6.0.8/memory.c
+++ b/crash-6.0.8/memory.c
@@ -264,6 +264,7 @@ static int verify_pfn(ulong);
 static void dump_per_cpu_offsets(void);
 static void dump_page_flags(ulonglong);
 static ulong kmem_cache_nodelists(ulong);
+static void dump_pgtype_info(void);
 
 /*
  *  Memory display modes specific to this file.
@@ -4044,6 +4045,8 @@ get_task_mem_usage(ulong task, struct task_mem_usage *tm)
  *      -c  displays the number of pages in the page_hash_table.
  *      -C  displays all entries in the page_hash_table.
  *      -i  displays informational data shown by /proc/meminfo.
+ *      -m  displays information on the number of pages per migrate type
+ *          for all orders, for all nodes.
  *
  *      -P  forces address to be defined as a physical address
  * address  when used with -f, the address can be either a page pointer
@@ -4090,7 +4093,7 @@ cmd_kmem(void)
 	int i;
 	int c;
 	int sflag, Sflag, pflag, fflag, Fflag, vflag, zflag, oflag, gflag; 
-	int nflag, cflag, Cflag, iflag, lflag, Lflag, Pflag, Vflag;
+	int nflag, cflag, Cflag, iflag, lflag, Lflag, Pflag, Vflag, mflag;
 	struct meminfo meminfo;
 	ulonglong value[MAXARGS];
 	char buf[BUFSIZE];
@@ -4100,12 +4103,12 @@ cmd_kmem(void)
 	spec_addr = 0;
         sflag =	Sflag = pflag = fflag = Fflag = Pflag = zflag = oflag = 0;
 	vflag = Cflag = cflag = iflag = nflag = lflag = Lflag = Vflag = 0;
-	gflag = 0;
+	gflag = mflag = 0;
 	escape = FALSE;
 	BZERO(&meminfo, sizeof(struct meminfo));
 	BZERO(&value[0], sizeof(ulonglong)*MAXARGS);
 
-        while ((c = getopt(argcnt, args, "gI:sSFfpvczCinl:L:PVo")) != EOF) {
+        while ((c = getopt(argcnt, args, "gI:sSFfpvczCinml:L:PVo")) != EOF) {
                 switch(c)
 		{
 		case 'V':
@@ -4206,6 +4209,10 @@ cmd_kmem(void)
 			gflag = 1;
 			break;
 
+		case 'm':
+			mflag = 1;
+			break;
+
 		default:
 			argerrs++;
 			break;
@@ -4215,8 +4222,8 @@ cmd_kmem(void)
 	if (argerrs)
 		cmd_usage(pc->curcmd, SYNOPSIS);
 
-        if ((sflag + Sflag + pflag + fflag + Fflag + Vflag + oflag +
-            vflag + Cflag + cflag + iflag + lflag + Lflag + gflag) > 1) {
+        if ((sflag + Sflag + pflag + fflag + Fflag + Vflag + oflag + vflag +
+		Cflag + cflag + iflag + lflag + Lflag + gflag + mflag) > 1) {
 		error(INFO, "only one flag allowed!\n");
 		cmd_usage(pc->curcmd, SYNOPSIS);
 	} 
@@ -4444,9 +4451,12 @@ cmd_kmem(void)
 	if (gflag == 1)
 		dump_page_flags(0);
 
+	if (mflag == 1)
+		dump_pgtype_info();
+
 	if (!(sflag + Sflag + pflag + fflag + Fflag + vflag + 
 	      Vflag + zflag + oflag + cflag + Cflag + iflag + 
-	      nflag + lflag + Lflag + gflag + meminfo.calls))
+	      nflag + lflag + Lflag + gflag + mflag + meminfo.calls))
 		cmd_usage(pc->curcmd, SYNOPSIS);
 
 }
@@ -7051,6 +7061,163 @@ bailout:
 	return total_free;
 }
 
+static void dump_pgtype_info(void)
+{
+	int n, m, z, o;
+	int list_count = 0;
+	int free_cnt = 0;
+	int mtype_sym = 0;
+	int mtype_len = 0;
+	ulong *mtypes;
+	ulong node_zones;
+	ulong temp;
+	ulong freelist;
+	ulong *free_ptr;
+	char *free_list_buf;
+	char name_buf[BUFSIZE];
+	char buf[BUFSIZE];
+	struct node_table *nt;
+	struct list_data list_data;
+
+	if (!(vt->flags & (NODES|ZONES)))
+		error(FATAL,
+			"dump_pgtype_info called without (NODES|ZONES)\n");
+
+	if (!VALID_STRUCT(zone))
+		error(FATAL,
+			"zone struct not available in this kernel\n");
+
+	if (VALID_STRUCT(free_area)) {
+		if (SIZE(free_area) == (3 * sizeof(ulong)))
+			error(FATAL,
+				"free_area type not supported by command\n");
+		else
+			list_count = MEMBER_SIZE("free_area",
+					"free_list")/SIZE(list_head);
+	} else
+		error(FATAL,
+			"free_area structure not found\n");
+
+	free_list_buf = GETBUF(SIZE(list_head));
+
+	do {
+		if (symbol_exists("migratetype_names") &&
+			(get_symbol_type("migratetype_names",
+					 NULL, NULL) == TYPE_CODE_ARRAY)) {
+
+			open_tmpfile();
+			sprintf(buf, "whatis migratetype_names");
+			if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) {
+				close_tmpfile();
+				break;
+			}
+
+			rewind(pc->tmpfile);
+			while (fgets(buf, BUFSIZE, pc->tmpfile)) {
+				if (STRNEQ(buf, "type = "))
+					break;
+			}
+			close_tmpfile();
+
+			if (!strstr(buf, "char *") ||
+				(count_chars(buf, '[') != 1) ||
+				(count_chars(buf, ']') != 1))
+				break;
+
+			mtype_len = get_array_length("migratetype_names",
+					NULL, 0);
+
+			mtypes = (ulong *)GETBUF(mtype_len * sizeof(ulong));
+
+			readmem(symbol_value("migratetype_names"),
+					KVADDR, mtypes,
+					(mtype_len * sizeof(ulong)),
+					NULL, FAULT_ON_ERROR);
+
+			mtype_sym = 1;
+		}
+	} while (0);
+
+	fprintf(fp, "%-43s [%d-%d]:",
+			"Free pages count per migrate type at order",
+			0, vt->nr_free_areas - 1);
+
+	fprintf(fp, "\n");
+
+	for (n = 0; n < vt->numnodes; n++) {
+		nt = &vt->node_table[n];
+		node_zones = nt->pgdat + OFFSET(pglist_data_node_zones);
+
+		for (m = 0; m < list_count; m++) {
+
+			for (z = 0; z < vt->nr_zones; z++) {
+				readmem((node_zones + (z * SIZE(zone)))
+					+ OFFSET(zone_name), KVADDR, &temp,
+					sizeof(void *), "node_zones name",
+					FAULT_ON_ERROR);
+				read_string(temp, name_buf, BUFSIZE-1);
+
+				fprintf(fp, "Node %4d, ", nt->node_id);
+				fprintf(fp, "zone %8s, ", name_buf);
+
+				if (mtype_sym) {
+					read_string(mtypes[m],
+						name_buf, BUFSIZE-1);
+					fprintf(fp, "type %12s ", name_buf);
+				} else
+					fprintf(fp, "type %12d ", m);
+
+				for (o = 0; o < vt->nr_free_areas; o++) {
+					freelist =
+					(node_zones + (z * SIZE(zone)))
+					+ (OFFSET(zone_free_area) +
+					(o * SIZE(free_area))) +
+					(m * SIZE(list_head));
+
+					readmem(freelist, KVADDR, free_list_buf,
+						SIZE(list_head),
+						"free_area free_list",
+						FAULT_ON_ERROR);
+
+					free_ptr = (ulong *)free_list_buf;
+
+					if (!(*free_ptr) ||
+						(*free_ptr == freelist)) {
+						fprintf(fp, "%6lu ", 0);
+						continue;
+					}
+
+					BZERO(&list_data,
+						sizeof(struct list_data));
+					list_data.flags = RETURN_ON_DUPLICATE;
+					list_data.start = *free_ptr;
+					list_data.end = freelist;
+					list_data.list_head_offset =
+						OFFSET(page_lru) +
+						OFFSET(list_head_next);
+
+					free_cnt = do_list(&list_data);
+					if (free_cnt < 0) {
+						error(pc->curcmd_flags &
+						IGNORE_ERRORS ? INFO : FATAL,
+						"corrupted free list\n");
+						free_cnt = 0;
+					}
+
+					fprintf(fp, "%6lu ", free_cnt);
+				}
+				fprintf(fp, "\n");
+			}
+		}
+		node_zones + OFFSET(zone_free_area);
+	}
+
+	FREEBUF(free_list_buf);
+
+	if (mtype_sym)
+		FREEBUF(mtypes);
+}
+
 /*
  *  dump_kmeminfo displays basic memory use information typically shown 
  *  by /proc/meminfo, and then some...
-- 
1.7.6

