----- Original Message -----
 Hi Dave,
 
 Please share your thoughts on adding a -m option to kmem to display
 the free pages per migrate type.
 This is similar to /proc/pagetypeinfo. 
OK, now there's two competing "kmem -m" patch requests out there -- neither
of which I'm particularly interested in maintaining.
Look, the crash utility could effectively mimic every file in the
/proc filesystem.  But that doesn't mean that it should -- somewhere
that has to be a line to be drawn.
Can you make it an extension module?  I'll host it on the extensions
web page, and if there becomes a consensus where people find that they
can't live without it, then it can be reconsidered for the base
crash utility.
Dave
 
 
 Sample output (without formatting). Patch attached.
 
 crash>
 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
 
 
 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