[Crash-utility] [PATCH] kmem: introduce -m option

Dave Anderson anderson at redhat.com
Fri Apr 24 19:46:45 UTC 2015



----- Original Message -----
> The dump_mem_map() function displays basic data about each entry in the
> mem_map[] array, or if an address is specified, just the mem_map[] entry
> for that address. This patch introduces the -m option to be used with
> 'kmem -p' exclusively. When used with -p, a comma-separated list of one or
> more struct page members may be specified to generate a custom, formatted
> display. For example:
> 
>   crash> kmem -p -m mapping,index,_mapcount.counter,_count.counter
>   ffffea0000000000	0x0	0	0	0
>   ffffea0000000040	0x0	0	-1	1
>   ffffea0000000080	0x0	0	-1	1
>   ffffea00000000c0	0x0	0	-1	1
>   ffffea0000000100	0x0	0	-1	1
>   ffffea0000000140	0x0	0	-1	1
>   ffffea0000000180	0x0	0	-1	1
>   ffffea00000001c0	0x0	0	-1	1
>   ffffea0000000200	0x0	0	-1	1
>   ffffea0000000240	0x0	0	-1	1
>   ...
> 
> Signed-off-by: Aaron Tomlin <atomlin at redhat.com>

Hi Aaron,

I've been waiting patiently for this patch to arrive, and it is
a good start, but this may take a couple go-arounds.

First off, it's almost impossible for me to effectively review this
patch because it does all the work inside of the already utterly-confusing
dump_mem_map_sparsemem() and dump_mem_map() functions.  I'll take the blame
for their current condition, because over the years I have patched and
re-patched, and taken in other folk's patches, many times -- all to 
the detriment of understandability/maintainability.  So please 
understand that I am reviewing my own code as much as yours.

So here are my initial suggestions.  

The -m optarg string received in cmd_kmem() should immediately be error-checked
and then handled in one place instead of duplicating the functionality in both
dump_mem_map_SPARSEMEM() and dump_mem_map() functions.

And the same thing goes w/respect to the duplication of effort when making
the calls to fill_struct_member_data().

When you posted your first patch a few weeks ago, I had tinkered with a proof-of-concept
of this option, which led to my creation of the fill_struct_member_data().  Here's what
I did:

First, in cmd_kmem(), the option string was immediately vetted like so:

                case 'm':
                        collect_page_member_data(optarg);
                        break;

Second, in collect_page_member_data(), I created an array of struct_member_data 
structures:

static void
collect_page_member_data(char *optlist)
{
	int i;
	int members;
	char *opt_string;
	char *memberlist[MAXARGS];
	struct struct_member_data *page_member_cache, *pmd;

        if ((count_chars(optlist, ',')+1) > MAXARGS)
                error(FATAL, "too many members in comma-separated list\n");

	opt_string = STRDUPBUF(optlist);
        replace_string(opt_string, ",", ' ');

	if (!(members = parse_line(opt_string, memberlist)))
		error(FATAL, "invalid page struct member list format: %s\n", 
			optlist);

	page_member_cache = (struct struct_member_data *)
		GETBUF(sizeof(struct struct_member_data) * members);

	for (i = 0, pmd = page_member_cache; i < members; i++, pmd++) {
		pmd->structure = "page";
		pmd->member = memberlist[i];
		if (!fill_struct_member_data(pmd))
			error(FATAL, "invalid %s struct member: %s\n", 
				pmd->structure, pmd->member);
		if (CRASHDEBUG(1)) {
			fprintf(fp, "      structure: %s\n", pmd->structure);
			fprintf(fp, "         member: %s\n", pmd->member);
			fprintf(fp, "           type: %ld\n", pmd->type);
			fprintf(fp, "  unsigned_type: %ld\n", pmd->unsigned_type);
			fprintf(fp, "         length: %ld\n", pmd->length);
			fprintf(fp, "         offset: %ld\n", pmd->offset);
			fprintf(fp, "         bitpos: %ld\n", pmd->bitpos);
			fprintf(fp, "        bitsize: %ld\n", pmd->bitsize);
		}
	}
}

However, that's as far as I took it.  What would also need to be done is for cmd_kmem()
to pass the meminfo pointer in to collect_page_member_data(), and have it store both
the "members" count and the "page_member_cache" pointer into new members in the meminfo
structure.

Then, like your meminfo->include, dump_mem_map_SPARSEMEM() and dump_mem_map() can key
on the existence of a non-zero meminfo "members" counter to perform the new functionality.

But the biggest change I'd like you to make it to move the new display functionality
completely out of dump_mem_map_SPARSEMEM() and dump_mem_map(), and put it in a
new common function.  Let's not make those two functions any uglier than they
already are.  

So taking dump_mem_map_SPARSEMEM() for example, it should simply require the addition
of a few lines to each function, i.e., something like this: 

       for (section_nr = 0; section_nr < nr_mem_sections ; section_nr++) {
 ... [ cut ] ...
                for (i = 0; i < section_size;
                     i++, pp += SIZE(page), phys += PAGESIZE()) {
 ... [ cut ] ...

                        if (!done && (pg_spec || phys_spec))
                                continue;

+                       if (mi->members_count) {
+                               bufferindex += do_your_function(pp, pcache, mi, outputbuffer+bufferindex);
+                               goto display_members;
+                       }

 ... [ cut ] ...
 
+ display_members:
                        if (bufferindex > buffersize) {
                                fprintf(fp, "%s", outputbuffer);
                                bufferindex = 0;
                        }

You would still need to prevent the old header from being displayed similar to what
you have done in your patch, but something like the above should be possible.

Then I could just review the actual functionality of your patch.  There are a few 
issues there I'd like to discuss, but how about we get my initial bitch-fest out
of the way first.

Agreed?  

Dave



> ---
>  help.c   |   19 +-
>  memory.c | 1074
>  ++++++++++++++++++++++++++++++++++++--------------------------
>  2 files changed, 649 insertions(+), 444 deletions(-)
> 
> diff --git a/help.c b/help.c
> index b2f4d21..76b640a 100644
> --- a/help.c
> +++ b/help.c
> @@ -5530,7 +5530,7 @@ char *help_kmem[] = {
>  "kmem",
>  "kernel memory",
>  "[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-z|-o|-h] [slab] [[-P] address]\n"
> -"       [-g [flags]] [-I slab[,slab]]",
> +"       [-g [flags]] [-I slab[,slab]] [-m member[,member]]",
>  "  This command displays information about the use of kernel memory.\n",
>  "        -f  displays the contents of the system free memory headers.",
>  "            also verifies that the page count equals nr_free_pages.",
> @@ -5565,6 +5565,9 @@ char *help_kmem[] = {
>  "            all slab cache names and addresses are listed.",
>  "   -I slab  when used with -s or -S, one or more slab cache names in a",
>  "            comma-separated list may be specified as slab caches to
>  ignore.",
> +" -m member  when used with -p, a comma-separated list of one or more",
> +"            struct page members may be specified to generate a custom",
> +"            formatted display.",
>  "        -P  declares that the following address argument is a physical
>  address.",
>  "   address  when used without any flag, the address can be a kernel
>  virtual,",
>  "            or physical address; a search is made through the symbol
>  table,",
> @@ -5717,6 +5720,20 @@ char *help_kmem[] = {
>  "    f5c51440     22000         0         0  1 80 slab",
>  "    ...",
>  "    ",
> +"  Dump the mem_map[] array but select desired fields:\n",
> +"    %s> kmem -p -m mapping,index,_mapcount.counter",
> +"    ffffea0000000000	0x0	0	0",
> +"    ffffea0000000040	0x0	0	-1",
> +"    ffffea0000000080	0x0	0	-1",
> +"    ffffea00000000c0	0x0	0	-1",
> +"    ffffea0000000100	0x0	0	-1",
> +"    ffffea0000000140	0x0	0	-1",
> +"    ffffea0000000180	0x0	0	-1",
> +"    ffffea00000001c0	0x0	0	-1",
> +"    ffffea0000000200	0x0	0	-1",
> +"    ffffea0000000240	0x0	0	-1",
> +"    ...",
> +"    ",
>  "  Use the commands above with a page pointer or a physical address
>  argument:\n",
>  "    %s> kmem -f c40425b0",
>  "    NODE ",
> diff --git a/memory.c b/memory.c
> index aacf929..d4114c2 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -55,6 +55,7 @@ struct meminfo {           /* general purpose memory
> information structure */
>  	ulong found;
>  	ulong retval;
>  	char *ignore;
> +	char *include;
>  	int errors;
>  	int calls;
>  	int cpu;
> @@ -4425,7 +4426,7 @@ cmd_kmem(void)
>  	BZERO(&meminfo, sizeof(struct meminfo));
>  	BZERO(&value[0], sizeof(ulonglong)*MAXARGS);
>  
> -        while ((c = getopt(argcnt, args, "gI:sSFfpvczCinl:L:PVoh")) != EOF)
> {
> +        while ((c = getopt(argcnt, args, "gI:sSFfm:pvczCinl:L:PVoh")) !=
> EOF) {
>                  switch(c)
>  		{
>  		case 'V':
> @@ -4480,6 +4481,10 @@ cmd_kmem(void)
>  			pflag = 1;
>  			break;
>  
> +		case 'm':
> +			meminfo.include = optarg;
> +			break;
> +
>  		case 'I':
>  			meminfo.ignore = optarg;
>  			break;
> @@ -4948,7 +4953,7 @@ PG_slab_flag_init(void)
>  static void
>  dump_mem_map_SPARSEMEM(struct meminfo *mi)
>  {
> -	ulong i;
> +	ulong i, j;
>  	long total_pages;
>  	int others, page_not_mapped, phys_not_mapped, page_mapping;
>  	ulong pp, ppend;
> @@ -4967,7 +4972,11 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
>  	char buf4[BUFSIZE];
>  	char *page_cache;
>  	char *pcache;
> -	ulong section, section_nr, nr_mem_sections, section_size;
> +	char *members = NULL;
> +	char *memberlist[MAXARGS];
> +	struct struct_member_data *member_data[MAXARGS];
> +	int nr_members, populated;
> +	ulong tmpvalue, section, section_nr, nr_mem_sections, section_size;
>  	long buffersize;
>  	char *outputbuffer;
>  	int bufferindex;
> @@ -4980,66 +4989,81 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
>  	char style3[100];
>  	char style4[100];
>  
> -	sprintf((char *)&style1, "%%lx%s%%%dllx%s%%%dlx%s%%8lx %%2d%s",
> -			space(MINSPACE),
> -			(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> -			space(MINSPACE),
> -			VADDR_PRLEN,
> -			space(MINSPACE),
> -			space(MINSPACE));
> -	sprintf((char *)&style2, "%%-%dlx%s%%%dllx%s%s%s%s %2s ",
> -			VADDR_PRLEN,
> -			space(MINSPACE),
> -			(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> -			space(MINSPACE),
> -			mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, " "),
> -			space(MINSPACE),
> -			mkstring(buf4, 8, CENTER|RJUST, " "),
> -			" ");
> -	sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%2d ",
> -			VADDR_PRLEN,
> -			space(MINSPACE),
> -			(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> -			space(MINSPACE),
> -			mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "-------"),
> -			space(MINSPACE),
> -			mkstring(buf4, 8, CENTER|RJUST, "-----"));
> -	sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%2d ",
> -			VADDR_PRLEN,
> -			space(MINSPACE),
> -			(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> -			space(MINSPACE),
> -			VADDR_PRLEN,
> -			space(MINSPACE));
> +	nr_members = mapping = index = 0;
> +	reserved = shared = slabs = buffers = inode = offset = 0;
> +	pg_spec = phys_spec = print_hdr = FALSE;
>  
>  	v22 = VALID_MEMBER(page_inode);  /* page.inode vs. page.mapping */
>  
> -        if (v22) {
> -		sprintf(hdr, "%s%s%s%s%s%s%s%sCNT FLAGS\n",
> -		    mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"),
> -		    space(MINSPACE),
> -                    mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> -			RJUST, "PHYSICAL"),
> -		    space(MINSPACE),
> -		    mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "INODE"),
> -		    space(MINSPACE),
> -		    mkstring(buf4, 8, CENTER|LJUST, "OFFSET"),
> -		    space(MINSPACE-1));
> -        } else {
> -		sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n",
> -		    mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"),
> -		    space(MINSPACE),
> -                    mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> -                        RJUST, "PHYSICAL"),
> -		    space(MINSPACE),
> -		    mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"),
> -		    space(MINSPACE),
> -		    mkstring(buf4, 8, CENTER|RJUST, "INDEX"));
> -        }
> +	if (!mi->include) {
> +		sprintf((char *)&style1, "%%lx%s%%%dllx%s%%%dlx%s%%8lx %%2d%s",
> +				space(MINSPACE),
> +				(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> +				space(MINSPACE),
> +				VADDR_PRLEN,
> +				space(MINSPACE),
> +				space(MINSPACE));
> +		sprintf((char *)&style2, "%%-%dlx%s%%%dllx%s%s%s%s %2s ",
> +				VADDR_PRLEN,
> +				space(MINSPACE),
> +				(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> +				space(MINSPACE),
> +				mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, " "),
> +				space(MINSPACE),
> +				mkstring(buf4, 8, CENTER|RJUST, " "),
> +				" ");
> +		sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%2d ",
> +				VADDR_PRLEN,
> +				space(MINSPACE),
> +				(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> +				space(MINSPACE),
> +				mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "-------"),
> +				space(MINSPACE),
> +				mkstring(buf4, 8, CENTER|RJUST, "-----"));
> +		sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%2d ",
> +				VADDR_PRLEN,
> +				space(MINSPACE),
> +				(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> +				space(MINSPACE),
> +				VADDR_PRLEN,
> +				space(MINSPACE));
> +
> +		if (v22) {
> +			sprintf(hdr, "%s%s%s%s%s%s%s%sCNT FLAGS\n",
> +			    mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"),
> +			    space(MINSPACE),
> +			    mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> +				RJUST, "PHYSICAL"),
> +			    space(MINSPACE),
> +			    mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "INODE"),
> +			    space(MINSPACE),
> +			    mkstring(buf4, 8, CENTER|LJUST, "OFFSET"),
> +			    space(MINSPACE-1));
> +		} else {
> +			sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n",
> +			    mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"),
> +			    space(MINSPACE),
> +			    mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> +				RJUST, "PHYSICAL"),
> +			    space(MINSPACE),
> +			    mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"),
> +			    space(MINSPACE),
> +			    mkstring(buf4, 8, CENTER|RJUST, "INDEX"));
> +		}
> +	} else {
> +		if (count_chars(mi->include, ',') > MAXARGS)
> +			error(FATAL, "too many members in comma-separated list!\n");
>  
> -	mapping = index = 0;
> -	reserved = shared = slabs = buffers = inode = offset = 0;
> -	pg_spec = phys_spec = print_hdr = FALSE;
> +		if ((LASTCHAR(mi->include) == ',') || (LASTCHAR(mi->include) == '.'))
> +			error(FATAL, "invalid format: %s\n", mi->include);
> +
> +		members = GETBUF(strlen(mi->include)+1);
> +		strcpy(members, mi->include);
> +		replace_string(members, ",", ' ');
> +		nr_members = parse_line(members, memberlist);
> +		populated = FALSE;
> +
> +	}
>  
>  	switch (mi->flags)
>  	{
> @@ -5065,7 +5089,8 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
>  			error(FATAL, "dump_mem_map: no memtype specified\n");
>  			break;
>  		}
> -		print_hdr = TRUE;
> +		if (!mi->include)
> +			print_hdr = TRUE;
>  		break;
>  
>  	case GET_ALL:
> @@ -5092,7 +5117,8 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
>  		break;
>  
>  	default:
> -		print_hdr = TRUE;
> +		if (!mi->include)
> +			print_hdr = TRUE;
>  		break;
>  	}
>  
> @@ -5188,187 +5214,251 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
>  
>  			if (!done && (pg_spec || phys_spec))
>  				continue;
> -
> -			flags = ULONG(pcache + OFFSET(page_flags));
> -			if (SIZE(page_flags) == 4)
> -				flags &= 0xffffffff;
> -			count = UINT(pcache + OFFSET(page_count));
>  
> -	                switch (mi->flags)
> -			{
> -			case GET_ALL:
> -			case GET_BUFFERS_PAGES:
> -				if (VALID_MEMBER(page_buffers)) {
> -					tmp = ULONG(pcache +
> -						OFFSET(page_buffers));
> -					if (tmp)
> -						buffers++;
> -				} else if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) {
> -	                                if ((flags >> v26_PG_private) & 1)
> -						buffers++;
> -				} else
> -					error(FATAL,
> -			       "cannot determine whether pages have buffers\n");
> +			if (mi->include) {
> +				if (!populated) {
>  
> -				if (mi->flags != GET_ALL)
> -					continue;
> +					j = 0;
> +					do {
> +						if (!(member_data[j] = malloc(sizeof(struct struct_member_data)))) {
> +							error(WARNING, "cannot malloc member_data space.\n");
> +							nr_members = j += 1;
> +							goto failed_member_data;
> +						}
>  
> -				/* FALLTHROUGH */
> +						member_data[j]->structure = "page";
> +						member_data[j]->member = memberlist[j];
> +						if (!(fill_struct_member_data(member_data[j]))) {
> +							error(WARNING, "Failed to populate member_data: "
> +								"%s.%s does not exist.\n",
> +								member_data[j]->structure, member_data[j]->member);
> +							nr_members = j += 1;
> +							goto failed_member_data;
> +						}
>  
> -			case GET_SLAB_PAGES:
> -				if (v22) {
> -	                                if ((flags >> v22_PG_Slab) & 1)
> -						slabs++;
> -				} else if (vt->PG_slab) {
> -	                                if ((flags >> vt->PG_slab) & 1)
> -						slabs++;
> -				} else {
> -	                                if ((flags >> v24_PG_slab) & 1)
> -						slabs++;
> +					} while (++j < nr_members);
> +					populated = TRUE;
>  				}
> -				if (mi->flags != GET_ALL)
> -					continue;
>  
> -				/* FALLTHROUGH */
>  
> -			case GET_SHARED_PAGES:
> -			case GET_TOTALRAM_PAGES:
> -                                if (vt->PG_reserved)
> -					PG_reserved_flag = vt->PG_reserved;
> -				else
> -                                        PG_reserved_flag = v22 ?
> -                                                1 << v22_PG_reserved :
> -                                                1 << v24_PG_reserved;
> +				bufferindex += sprintf(outputbuffer + bufferindex,
> +					"%lx\t", pp);
>  
> -	                        if (flags & PG_reserved_flag) {
> -	                                reserved++;
> -				} else {
> -					if ((int)count >
> -					    (vt->flags & PGCNT_ADJ ? 0 : 1))
> -						shared++;
> -				}
> -	                        continue;
> -	                }
> -			page_mapping = VALID_MEMBER(page_mapping);
> -
> -			if (v22) {
> -				inode = ULONG(pcache + OFFSET(page_inode));
> -				offset = ULONG(pcache + OFFSET(page_offset));
> -			} else if (page_mapping) {
> -				mapping = ULONG(pcache +
> -					OFFSET(page_mapping));
> -				index = ULONG(pcache + OFFSET(page_index));
> -			}
> -
> -			page_not_mapped = phys_not_mapped = FALSE;
> +				j = 0;
> +				do {
> +					switch (member_data[j]->type)
> +					{
> +					case TYPE_CODE_PTR:
> +						readmem(pp + member_data[j]->offset, KVADDR, &tmpvalue,
> +							member_data[j]->length, "tmpvalue", FAULT_ON_ERROR);
> +						bufferindex += sprintf(outputbuffer + bufferindex, "0x%lx\t",
> +							tmpvalue);
> +						break;
> +					case TYPE_CODE_INT:
> +						readmem(pp + member_data[j]->offset, KVADDR, &tmpvalue,
> +							member_data[j]->length, "tmpvalue", FAULT_ON_ERROR);
> +						if (member_data[j]->unsigned_type ||
> +							member_data[j]->length == sizeof(ulonglong))
> +							bufferindex += sprintf(outputbuffer + bufferindex,
> +								"%lu\t", tmpvalue);
> +						else
> +							bufferindex += sprintf(outputbuffer + bufferindex,
> +								"%d\t",	(int)tmpvalue);
> +						break;
> +					default:
> +						error(WARNING, "invalid data structure reference %s.%s\n",
> +							member_data[j]->structure, member_data[j]->member);
> +						nr_members = j += 1;
> +						goto failed_member_data;
> +						break;
> +					}
> +				} while (++j < nr_members);
> +
> +				bufferindex += sprintf(outputbuffer+bufferindex, "\n");
>  
> -			if (v22) {
> -				bufferindex += sprintf(outputbuffer+bufferindex,
> -						(char *)&style1, pp, phys, inode,
> -						offset, count);
>  			} else {
> -				if ((vt->flags & V_MEM_MAP)) {
> -				    	if (!machdep->verify_paddr(phys))
> -						phys_not_mapped = TRUE;
> -					if (!kvtop(NULL, pp, NULL, 0))
> -						page_not_mapped = TRUE;
> +
> +				flags = ULONG(pcache + OFFSET(page_flags));
> +				if (SIZE(page_flags) == 4)
> +					flags &= 0xffffffff;
> +				count = UINT(pcache + OFFSET(page_count));
> +
> +				switch (mi->flags)
> +				{
> +				case GET_ALL:
> +				case GET_BUFFERS_PAGES:
> +					if (VALID_MEMBER(page_buffers)) {
> +						tmp = ULONG(pcache +
> +							OFFSET(page_buffers));
> +						if (tmp)
> +							buffers++;
> +					} else if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) {
> +						if ((flags >> v26_PG_private) & 1)
> +							buffers++;
> +					} else
> +						error(FATAL,
> +				       "cannot determine whether pages have buffers\n");
> +
> +					if (mi->flags != GET_ALL)
> +						continue;
> +
> +					/* FALLTHROUGH */
> +
> +				case GET_SLAB_PAGES:
> +					if (v22) {
> +						if ((flags >> v22_PG_Slab) & 1)
> +							slabs++;
> +					} else if (vt->PG_slab) {
> +						if ((flags >> vt->PG_slab) & 1)
> +							slabs++;
> +					} else {
> +						if ((flags >> v24_PG_slab) & 1)
> +							slabs++;
> +					}
> +					if (mi->flags != GET_ALL)
> +						continue;
> +
> +					/* FALLTHROUGH */
> +
> +				case GET_SHARED_PAGES:
> +				case GET_TOTALRAM_PAGES:
> +					if (vt->PG_reserved)
> +						PG_reserved_flag = vt->PG_reserved;
> +					else
> +						PG_reserved_flag = v22 ?
> +							1 << v22_PG_reserved :
> +							1 << v24_PG_reserved;
> +
> +					if (flags & PG_reserved_flag) {
> +						reserved++;
> +					} else {
> +						if ((int)count >
> +						    (vt->flags & PGCNT_ADJ ? 0 : 1))
> +							shared++;
> +					}
> +					continue;
>  				}
> -				if (page_not_mapped)
> -					bufferindex += sprintf(outputbuffer+bufferindex,
> -							(char *)&style2, pp, phys);
> -				else if (!page_mapping)
> -					bufferindex += sprintf(outputbuffer+bufferindex,
> -							(char *)&style3, pp, phys, count);
> -				else
> +				page_mapping = VALID_MEMBER(page_mapping);
> +
> +				if (v22) {
> +					inode = ULONG(pcache + OFFSET(page_inode));
> +					offset = ULONG(pcache + OFFSET(page_offset));
> +				} else if (page_mapping) {
> +					mapping = ULONG(pcache +
> +						OFFSET(page_mapping));
> +					index = ULONG(pcache + OFFSET(page_index));
> +				}
> +
> +				page_not_mapped = phys_not_mapped = FALSE;
> +
> +				if (v22) {
>  					bufferindex += sprintf(outputbuffer+bufferindex,
> -							(char *)&style4, pp, phys,
> -							mapping, index, count);
> -			}
> -
> -			others = 0;
> -
> +							(char *)&style1, pp, phys, inode,
> +							offset, count);
> +				} else {
> +					if ((vt->flags & V_MEM_MAP)) {
> +						if (!machdep->verify_paddr(phys))
> +							phys_not_mapped = TRUE;
> +						if (!kvtop(NULL, pp, NULL, 0))
> +							page_not_mapped = TRUE;
> +					}
> +					if (page_not_mapped)
> +						bufferindex += sprintf(outputbuffer+bufferindex,
> +								(char *)&style2, pp, phys);
> +					else if (!page_mapping)
> +						bufferindex += sprintf(outputbuffer+bufferindex,
> +								(char *)&style3, pp, phys, count);
> +					else
> +						bufferindex += sprintf(outputbuffer+bufferindex,
> +								(char *)&style4, pp, phys,
> +								mapping, index, count);
> +				}
> +
> +				others = 0;
> +
>  #define sprintflag(X) sprintf(outputbuffer + bufferindex, X, others++ ? ","
>  : "")
>  
> -			if (v22) {
> -		                if ((flags >> v22_PG_DMA) & 1)
> -					bufferindex += sprintflag("%sDMA");
> -				if ((flags >> v22_PG_locked) & 1)
> -					bufferindex += sprintflag("%slocked");
> -				if ((flags >> v22_PG_error) & 1)
> -					bufferindex += sprintflag("%serror");
> -				if ((flags >> v22_PG_referenced) & 1)
> -					bufferindex += sprintflag("%sreferenced");
> -				if ((flags >> v22_PG_dirty) & 1)
> -					bufferindex += sprintflag("%sdirty");
> -				if ((flags >> v22_PG_uptodate) & 1)
> -					bufferindex += sprintflag("%suptodate");
> -				if ((flags >> v22_PG_free_after) & 1)
> -					bufferindex += sprintflag("%sfree_after");
> -				if ((flags >> v22_PG_decr_after) & 1)
> -					bufferindex += sprintflag("%sdecr_after");
> -				if ((flags >> v22_PG_swap_unlock_after) & 1)
> -					bufferindex += sprintflag("%sswap_unlock_after");
> -				if ((flags >> v22_PG_Slab) & 1)
> -					bufferindex += sprintflag("%sslab");
> -				if ((flags >> v22_PG_swap_cache) & 1)
> -					bufferindex += sprintflag("%sswap_cache");
> -				if ((flags >> v22_PG_skip) & 1)
> -					bufferindex += sprintflag("%sskip");
> -	                        if ((flags >> v22_PG_reserved) & 1)
> -					bufferindex += sprintflag("%sreserved");
> -				bufferindex += sprintf(outputbuffer+bufferindex, "\n");
> -			} else if (THIS_KERNEL_VERSION > LINUX(2,4,9)) {
> -				if (vt->flags & PAGEFLAGS)
> -					bufferindex += translate_page_flags(outputbuffer+bufferindex, flags);
> -				else
> -					bufferindex += sprintf(outputbuffer+bufferindex, "%lx\n", flags);
> -			} else {
> -
> -		                if ((flags >> v24_PG_locked) & 1)
> -					bufferindex += sprintflag("%slocked");
> -				if ((flags >> v24_PG_error) & 1)
> -					bufferindex += sprintflag("%serror");
> -				if ((flags >> v24_PG_referenced) & 1)
> -					bufferindex += sprintflag("%sreferenced");
> -				if ((flags >> v24_PG_uptodate) & 1)
> -					bufferindex += sprintflag("%suptodate");
> -                                if ((flags >> v24_PG_dirty) & 1)
> -					bufferindex += sprintflag("%sdirty");
> -				if ((flags >> v24_PG_decr_after) & 1)
> -					bufferindex += sprintflag("%sdecr_after");
> -                                if ((flags >> v24_PG_active) & 1)
> -					bufferindex += sprintflag("%sactive");
> -                                if ((flags >> v24_PG_inactive_dirty) & 1)
> -					bufferindex += sprintflag("%sinactive_dirty");
> -				if ((flags >> v24_PG_slab) & 1)
> -					bufferindex += sprintflag("%sslab");
> -				if ((flags >> v24_PG_swap_cache) & 1)
> -					bufferindex += sprintflag("%sswap_cache");
> -				if ((flags >> v24_PG_skip) & 1)
> -					bufferindex += sprintflag("%sskip");
> -				if ((flags >> v24_PG_inactive_clean) & 1)
> -					bufferindex += sprintflag("%sinactive_clean");
> -				if ((flags >> v24_PG_highmem) & 1)
> -					bufferindex += sprintflag("%shighmem");
> -				if ((flags >> v24_PG_checked) & 1)
> -					bufferindex += sprintflag("%schecked");
> -				if ((flags >> v24_PG_bigpage) & 1)
> -					bufferindex += sprintflag("%sbigpage");
> -                                if ((flags >> v24_PG_arch_1) & 1)
> -					bufferindex += sprintflag("%sarch_1");
> -				if ((flags >> v24_PG_reserved) & 1)
> -					bufferindex += sprintflag("%sreserved");
> -				if (phys_not_mapped)
> -					bufferindex += sprintflag("%s[NOT MAPPED]");
> -
> -				bufferindex += sprintf(outputbuffer+bufferindex, "\n");
> +				if (v22) {
> +					if ((flags >> v22_PG_DMA) & 1)
> +						bufferindex += sprintflag("%sDMA");
> +					if ((flags >> v22_PG_locked) & 1)
> +						bufferindex += sprintflag("%slocked");
> +					if ((flags >> v22_PG_error) & 1)
> +						bufferindex += sprintflag("%serror");
> +					if ((flags >> v22_PG_referenced) & 1)
> +						bufferindex += sprintflag("%sreferenced");
> +					if ((flags >> v22_PG_dirty) & 1)
> +						bufferindex += sprintflag("%sdirty");
> +					if ((flags >> v22_PG_uptodate) & 1)
> +						bufferindex += sprintflag("%suptodate");
> +					if ((flags >> v22_PG_free_after) & 1)
> +						bufferindex += sprintflag("%sfree_after");
> +					if ((flags >> v22_PG_decr_after) & 1)
> +						bufferindex += sprintflag("%sdecr_after");
> +					if ((flags >> v22_PG_swap_unlock_after) & 1)
> +						bufferindex += sprintflag("%sswap_unlock_after");
> +					if ((flags >> v22_PG_Slab) & 1)
> +						bufferindex += sprintflag("%sslab");
> +					if ((flags >> v22_PG_swap_cache) & 1)
> +						bufferindex += sprintflag("%sswap_cache");
> +					if ((flags >> v22_PG_skip) & 1)
> +						bufferindex += sprintflag("%sskip");
> +					if ((flags >> v22_PG_reserved) & 1)
> +						bufferindex += sprintflag("%sreserved");
> +					bufferindex += sprintf(outputbuffer+bufferindex, "\n");
> +				} else if (THIS_KERNEL_VERSION > LINUX(2,4,9)) {
> +					if (vt->flags & PAGEFLAGS)
> +						bufferindex += translate_page_flags(outputbuffer+bufferindex, flags);
> +					else
> +						bufferindex += sprintf(outputbuffer+bufferindex, "%lx\n", flags);
> +				} else {
> +
> +					if ((flags >> v24_PG_locked) & 1)
> +						bufferindex += sprintflag("%slocked");
> +					if ((flags >> v24_PG_error) & 1)
> +						bufferindex += sprintflag("%serror");
> +					if ((flags >> v24_PG_referenced) & 1)
> +						bufferindex += sprintflag("%sreferenced");
> +					if ((flags >> v24_PG_uptodate) & 1)
> +						bufferindex += sprintflag("%suptodate");
> +					if ((flags >> v24_PG_dirty) & 1)
> +						bufferindex += sprintflag("%sdirty");
> +					if ((flags >> v24_PG_decr_after) & 1)
> +						bufferindex += sprintflag("%sdecr_after");
> +					if ((flags >> v24_PG_active) & 1)
> +						bufferindex += sprintflag("%sactive");
> +					if ((flags >> v24_PG_inactive_dirty) & 1)
> +						bufferindex += sprintflag("%sinactive_dirty");
> +					if ((flags >> v24_PG_slab) & 1)
> +						bufferindex += sprintflag("%sslab");
> +					if ((flags >> v24_PG_swap_cache) & 1)
> +						bufferindex += sprintflag("%sswap_cache");
> +					if ((flags >> v24_PG_skip) & 1)
> +						bufferindex += sprintflag("%sskip");
> +					if ((flags >> v24_PG_inactive_clean) & 1)
> +						bufferindex += sprintflag("%sinactive_clean");
> +					if ((flags >> v24_PG_highmem) & 1)
> +						bufferindex += sprintflag("%shighmem");
> +					if ((flags >> v24_PG_checked) & 1)
> +						bufferindex += sprintflag("%schecked");
> +					if ((flags >> v24_PG_bigpage) & 1)
> +						bufferindex += sprintflag("%sbigpage");
> +					if ((flags >> v24_PG_arch_1) & 1)
> +						bufferindex += sprintflag("%sarch_1");
> +					if ((flags >> v24_PG_reserved) & 1)
> +						bufferindex += sprintflag("%sreserved");
> +					if (phys_not_mapped)
> +						bufferindex += sprintflag("%s[NOT MAPPED]");
> +
> +					bufferindex += sprintf(outputbuffer+bufferindex, "\n");
> +				}
>  			}
>  
>  			if (bufferindex > buffersize) {
>  				fprintf(fp, "%s", outputbuffer);
>  				bufferindex = 0;
>  			}
> -
> +
>  			if (done)
>  				break;
>  		}
> @@ -5413,12 +5503,18 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
>  
>  	FREEBUF(outputbuffer);
>  	FREEBUF(page_cache);
> +failed_member_data:
> +	if (mi->include) {
> +		FREEBUF(members);
> +		for (i = 0; i < nr_members; i++)
> +			free(member_data[i]);
> +	}
>  }
>  
>  static void
>  dump_mem_map(struct meminfo *mi)
>  {
> -	long i, n;
> +	ulong i, n, j;
>  	long total_pages;
>  	int others, page_not_mapped, phys_not_mapped, page_mapping;
>  	ulong pp, ppend;
> @@ -5439,6 +5535,11 @@ dump_mem_map(struct meminfo *mi)
>  	char buf4[BUFSIZE];
>  	char *page_cache;
>  	char *pcache;
> +	char *members = NULL;
> +	char *memberlist[MAXARGS];
> +	struct struct_member_data *member_data[MAXARGS];
> +	int nr_members, populated;
> +	ulong tmpvalue;
>  	long buffersize;
>  	char *outputbuffer;
>  	int bufferindex;
> @@ -5456,67 +5557,82 @@ dump_mem_map(struct meminfo *mi)
>  		return;
>  	}
>  
> -	sprintf((char *)&style1, "%%lx%s%%%dllx%s%%%dlx%s%%8lx %%2d%s",
> -			space(MINSPACE),
> -			(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> -			space(MINSPACE),
> -			VADDR_PRLEN,
> -			space(MINSPACE),
> -			space(MINSPACE));
> -	sprintf((char *)&style2, "%%-%dlx%s%%%dllx%s%s%s%s %2s ",
> -			VADDR_PRLEN,
> -			space(MINSPACE),
> -			(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> -			space(MINSPACE),
> -			mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, " "),
> -			space(MINSPACE),
> -			mkstring(buf4, 8, CENTER|RJUST, " "),
> -			" ");
> -	sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%2d ",
> -			VADDR_PRLEN,
> -			space(MINSPACE),
> -			(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> -			space(MINSPACE),
> -			mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "-------"),
> -			space(MINSPACE),
> -			mkstring(buf4, 8, CENTER|RJUST, "-----"));
> -	sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%2d ",
> -			VADDR_PRLEN,
> -			space(MINSPACE),
> -			(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> -			space(MINSPACE),
> -			VADDR_PRLEN,
> -			space(MINSPACE));
> +	nr_members = mapping = index = 0;
> +	reserved = shared = slabs = buffers = inode = offset = 0;
> +	pg_spec = phys_spec = print_hdr = FALSE;
>  
>  	v22 = VALID_MEMBER(page_inode);  /* page.inode vs. page.mapping */
>  
> -        if (v22) {
> -		sprintf(hdr, "%s%s%s%s%s%s%s%sCNT FLAGS\n",
> -		    mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"),
> -		    space(MINSPACE),
> -                    mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> -			RJUST, "PHYSICAL"),
> -		    space(MINSPACE),
> -		    mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "INODE"),
> -		    space(MINSPACE),
> -		    mkstring(buf4, 8, CENTER|LJUST, "OFFSET"),
> -		    space(MINSPACE-1));
> -        } else {
> -		sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n",
> -		    mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"),
> -		    space(MINSPACE),
> -                    mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> -                        RJUST, "PHYSICAL"),
> -		    space(MINSPACE),
> -		    mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"),
> -		    space(MINSPACE),
> -		    mkstring(buf4, 8, CENTER|RJUST, "INDEX"));
> -        }
> +	if (!mi->include) {
> +		sprintf((char *)&style1, "%%lx%s%%%dllx%s%%%dlx%s%%8lx %%2d%s",
> +				space(MINSPACE),
> +				(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> +				space(MINSPACE),
> +				VADDR_PRLEN,
> +				space(MINSPACE),
> +				space(MINSPACE));
> +		sprintf((char *)&style2, "%%-%dlx%s%%%dllx%s%s%s%s %2s ",
> +				VADDR_PRLEN,
> +				space(MINSPACE),
> +				(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> +				space(MINSPACE),
> +				mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, " "),
> +				space(MINSPACE),
> +				mkstring(buf4, 8, CENTER|RJUST, " "),
> +				" ");
> +		sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%2d ",
> +				VADDR_PRLEN,
> +				space(MINSPACE),
> +				(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> +				space(MINSPACE),
> +				mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "-------"),
> +				space(MINSPACE),
> +				mkstring(buf4, 8, CENTER|RJUST, "-----"));
> +		sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%2d ",
> +				VADDR_PRLEN,
> +				space(MINSPACE),
> +				(int)MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> +				space(MINSPACE),
> +				VADDR_PRLEN,
> +				space(MINSPACE));
> +
> +		if (v22) {
> +			sprintf(hdr, "%s%s%s%s%s%s%s%sCNT FLAGS\n",
> +			    mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"),
> +			    space(MINSPACE),
> +			    mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> +				RJUST, "PHYSICAL"),
> +			    space(MINSPACE),
> +			    mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "INODE"),
> +			    space(MINSPACE),
> +			    mkstring(buf4, 8, CENTER|LJUST, "OFFSET"),
> +			    space(MINSPACE-1));
> +		} else {
> +			sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n",
> +			    mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"),
> +			    space(MINSPACE),
> +			    mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")),
> +				RJUST, "PHYSICAL"),
> +			    space(MINSPACE),
> +			    mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"),
> +			    space(MINSPACE),
> +			    mkstring(buf4, 8, CENTER|RJUST, "INDEX"));
> +		}
> +	} else {
> +		if (count_chars(mi->include, ',') > MAXARGS)
> +			error(FATAL, "too many members in comma-separated list!\n");
> +
> +		if ((LASTCHAR(mi->include) == ',') || (LASTCHAR(mi->include) == '.'))
> +			error(FATAL, "invalid format: %s\n", mi->include);
> +
> +		members = GETBUF(strlen(mi->include)+1);
> +		strcpy(members, mi->include);
> +		replace_string(members, ",", ' ');
> +		nr_members = parse_line(members, memberlist);
> +		populated = FALSE;
> +
> +	}
>  
> -	mapping = index = 0;
> -	reserved = shared = slabs = buffers = inode = offset = 0;
> -	pg_spec = phys_spec = print_hdr = FALSE;
> -
>  	switch (mi->flags)
>  	{
>  	case ADDRESS_SPECIFIED:
> @@ -5541,7 +5657,8 @@ dump_mem_map(struct meminfo *mi)
>  			error(FATAL, "dump_mem_map: no memtype specified\n");
>  			break;
>  		}
> -		print_hdr = TRUE;
> +		if (!mi->include)
> +			print_hdr = TRUE;
>  		break;
>  
>  	case GET_ALL:
> @@ -5568,7 +5685,8 @@ dump_mem_map(struct meminfo *mi)
>  		break;
>  
>  	default:
> -		print_hdr = TRUE;
> +		if (!mi->include)
> +			print_hdr = TRUE;
>  		break;
>  	}
>  
> @@ -5625,181 +5743,245 @@ dump_mem_map(struct meminfo *mi)
>  
>  			if (!done && (pg_spec || phys_spec))
>  				continue;
> -
> -			flags = ULONG(pcache + OFFSET(page_flags));
> -			if (SIZE(page_flags) == 4)
> -				flags &= 0xffffffff;
> -			count = UINT(pcache + OFFSET(page_count));
>  
> -	                switch (mi->flags)
> -			{
> -			case GET_ALL:
> -			case GET_BUFFERS_PAGES:
> -				if (VALID_MEMBER(page_buffers)) {
> -					tmp = ULONG(pcache +
> -						OFFSET(page_buffers));
> -					if (tmp)
> -						buffers++;
> -				} else if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) {
> -	                                if ((flags >> v26_PG_private) & 1)
> -						buffers++;
> -				} else
> -					error(FATAL,
> -			       "cannot determine whether pages have buffers\n");
> +			if (mi->include) {
> +				if (!populated) {
>  
> -				if (mi->flags != GET_ALL)
> -					continue;
> +					j = 0;
> +					do {
> +						if (!(member_data[j] = malloc(sizeof(struct struct_member_data)))) {
> +							error(WARNING, "cannot malloc member_data space.\n");
> +							nr_members = j += 1;
> +							goto failed_member_data;
> +						}
>  
> -				/* FALLTHROUGH */
> +						member_data[j]->structure = "page";
> +						member_data[j]->member = memberlist[j];
> +						if (!(fill_struct_member_data(member_data[j]))) {
> +							error(WARNING, "Failed to populate member_data: "
> +								"%s.%s does not exist.\n",
> +								member_data[j]->structure, member_data[j]->member);
> +							nr_members = j += 1;
> +							goto failed_member_data;
> +						}
>  
> -			case GET_SLAB_PAGES:
> -				if (v22) {
> -	                                if ((flags >> v22_PG_Slab) & 1)
> -						slabs++;
> -				} else if (vt->PG_slab) {
> -	                                if ((flags >> vt->PG_slab) & 1)
> -						slabs++;
> -				} else {
> -	                                if ((flags >> v24_PG_slab) & 1)
> -						slabs++;
> +					} while (++j < nr_members);
> +					populated = TRUE;
>  				}
> -				if (mi->flags != GET_ALL)
> -					continue;
>  
> -				/* FALLTHROUGH */
>  
> -			case GET_SHARED_PAGES:
> -			case GET_TOTALRAM_PAGES:
> -                                if (vt->PG_reserved)
> -					PG_reserved_flag = vt->PG_reserved;
> -				else
> -                                        PG_reserved_flag = v22 ?
> -                                                1 << v22_PG_reserved :
> -                                                1 << v24_PG_reserved;
> +				bufferindex += sprintf(outputbuffer + bufferindex,
> +					"%lx\t", pp);
>  
> -	                        if (flags & PG_reserved_flag) {
> -	                                reserved++;
> -				} else {
> -					if ((int)count >
> -					    (vt->flags & PGCNT_ADJ ? 0 : 1))
> -						shared++;
> -				}
> -	                        continue;
> -	                }
> -
> -			page_mapping = VALID_MEMBER(page_mapping);
> -
> -			if (v22) {
> -				inode = ULONG(pcache + OFFSET(page_inode));
> -				offset = ULONG(pcache + OFFSET(page_offset));
> -			} else if (page_mapping) {
> -				mapping = ULONG(pcache +
> -					OFFSET(page_mapping));
> -				index = ULONG(pcache + OFFSET(page_index));
> -			}
> -
> -			page_not_mapped = phys_not_mapped = FALSE;
> +				j = 0;
> +				do {
> +					switch (member_data[j]->type)
> +					{
> +					case TYPE_CODE_PTR:
> +						readmem(pp + member_data[j]->offset, KVADDR, &tmpvalue,
> +							member_data[j]->length, "tmpvalue", FAULT_ON_ERROR);
> +						bufferindex += sprintf(outputbuffer + bufferindex, "0x%lx\t",
> +							tmpvalue);
> +						break;
> +					case TYPE_CODE_INT:
> +						readmem(pp + member_data[j]->offset, KVADDR, &tmpvalue,
> +							member_data[j]->length, "tmpvalue", FAULT_ON_ERROR);
> +						if (member_data[j]->unsigned_type ||
> +							member_data[j]->length == sizeof(ulonglong))
> +							bufferindex += sprintf(outputbuffer + bufferindex,
> +								"%lu\t", tmpvalue);
> +						else
> +							bufferindex += sprintf(outputbuffer + bufferindex,
> +								"%d\t",	(int)tmpvalue);
> +						break;
> +					default:
> +						error(WARNING, "invalid data structure reference %s.%s\n",
> +							member_data[j]->structure, member_data[j]->member);
> +						nr_members = j += 1;
> +						goto failed_member_data;
> +						break;
> +					}
> +				} while (++j < nr_members);
> +
> +				bufferindex += sprintf(outputbuffer+bufferindex, "\n");
>  
> -			if (v22) {
> -				bufferindex += sprintf(outputbuffer+bufferindex,
> -						(char *)&style1, pp, phys, inode,
> -						offset, count);
>  			} else {
> -				if ((vt->flags & V_MEM_MAP)) {
> -				    	if (!machdep->verify_paddr(phys))
> -						phys_not_mapped = TRUE;
> -					if (!kvtop(NULL, pp, NULL, 0))
> -						page_not_mapped = TRUE;
> +
> +				flags = ULONG(pcache + OFFSET(page_flags));
> +				if (SIZE(page_flags) == 4)
> +					flags &= 0xffffffff;
> +				count = UINT(pcache + OFFSET(page_count));
> +
> +				switch (mi->flags)
> +				{
> +				case GET_ALL:
> +				case GET_BUFFERS_PAGES:
> +					if (VALID_MEMBER(page_buffers)) {
> +						tmp = ULONG(pcache +
> +							OFFSET(page_buffers));
> +						if (tmp)
> +							buffers++;
> +					} else if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) {
> +						if ((flags >> v26_PG_private) & 1)
> +							buffers++;
> +					} else
> +						error(FATAL,
> +				       "cannot determine whether pages have buffers\n");
> +
> +					if (mi->flags != GET_ALL)
> +						continue;
> +
> +					/* FALLTHROUGH */
> +
> +				case GET_SLAB_PAGES:
> +					if (v22) {
> +						if ((flags >> v22_PG_Slab) & 1)
> +							slabs++;
> +					} else if (vt->PG_slab) {
> +						if ((flags >> vt->PG_slab) & 1)
> +							slabs++;
> +					} else {
> +						if ((flags >> v24_PG_slab) & 1)
> +							slabs++;
> +					}
> +					if (mi->flags != GET_ALL)
> +						continue;
> +
> +					/* FALLTHROUGH */
> +
> +				case GET_SHARED_PAGES:
> +				case GET_TOTALRAM_PAGES:
> +					if (vt->PG_reserved)
> +						PG_reserved_flag = vt->PG_reserved;
> +					else
> +						PG_reserved_flag = v22 ?
> +							1 << v22_PG_reserved :
> +							1 << v24_PG_reserved;
> +
> +					if (flags & PG_reserved_flag) {
> +						reserved++;
> +					} else {
> +						if ((int)count >
> +						    (vt->flags & PGCNT_ADJ ? 0 : 1))
> +							shared++;
> +					}
> +					continue;
>  				}
> -				if (page_not_mapped)
> -					bufferindex += sprintf(outputbuffer+bufferindex,
> -							(char *)&style2, pp, phys);
> -				else if (!page_mapping)
> -					bufferindex += sprintf(outputbuffer+bufferindex,
> -							(char *)&style3, pp, phys, count);
> -				else
> +
> +				page_mapping = VALID_MEMBER(page_mapping);
> +
> +				if (v22) {
> +					inode = ULONG(pcache + OFFSET(page_inode));
> +					offset = ULONG(pcache + OFFSET(page_offset));
> +				} else if (page_mapping) {
> +					mapping = ULONG(pcache +
> +						OFFSET(page_mapping));
> +					index = ULONG(pcache + OFFSET(page_index));
> +				}
> +
> +				page_not_mapped = phys_not_mapped = FALSE;
> +
> +				if (v22) {
>  					bufferindex += sprintf(outputbuffer+bufferindex,
> -							(char *)&style4, pp, phys,
> -							mapping, index, count);
> -			}
> -
> -			others = 0;
> -
> +							(char *)&style1, pp, phys, inode,
> +							offset, count);
> +				} else {
> +					if ((vt->flags & V_MEM_MAP)) {
> +						if (!machdep->verify_paddr(phys))
> +							phys_not_mapped = TRUE;
> +						if (!kvtop(NULL, pp, NULL, 0))
> +							page_not_mapped = TRUE;
> +					}
> +					if (page_not_mapped)
> +						bufferindex += sprintf(outputbuffer+bufferindex,
> +								(char *)&style2, pp, phys);
> +					else if (!page_mapping)
> +						bufferindex += sprintf(outputbuffer+bufferindex,
> +								(char *)&style3, pp, phys, count);
> +					else
> +						bufferindex += sprintf(outputbuffer+bufferindex,
> +								(char *)&style4, pp, phys,
> +								mapping, index, count);
> +				}
> +
> +				others = 0;
> +
>  #define sprintflag(X) sprintf(outputbuffer + bufferindex, X, others++ ? ","
>  : "")
>  
> -			if (v22) {
> -		                if ((flags >> v22_PG_DMA) & 1)
> -					bufferindex += sprintflag("%sDMA");
> -				if ((flags >> v22_PG_locked) & 1)
> -					bufferindex += sprintflag("%slocked");
> -				if ((flags >> v22_PG_error) & 1)
> -					bufferindex += sprintflag("%serror");
> -				if ((flags >> v22_PG_referenced) & 1)
> -					bufferindex += sprintflag("%sreferenced");
> -				if ((flags >> v22_PG_dirty) & 1)
> -					bufferindex += sprintflag("%sdirty");
> -				if ((flags >> v22_PG_uptodate) & 1)
> -					bufferindex += sprintflag("%suptodate");
> -				if ((flags >> v22_PG_free_after) & 1)
> -					bufferindex += sprintflag("%sfree_after");
> -				if ((flags >> v22_PG_decr_after) & 1)
> -					bufferindex += sprintflag("%sdecr_after");
> -				if ((flags >> v22_PG_swap_unlock_after) & 1)
> -					bufferindex += sprintflag("%sswap_unlock_after");
> -				if ((flags >> v22_PG_Slab) & 1)
> -					bufferindex += sprintflag("%sslab");
> -				if ((flags >> v22_PG_swap_cache) & 1)
> -					bufferindex += sprintflag("%sswap_cache");
> -				if ((flags >> v22_PG_skip) & 1)
> -					bufferindex += sprintflag("%sskip");
> -	                        if ((flags >> v22_PG_reserved) & 1)
> -					bufferindex += sprintflag("%sreserved");
> -				bufferindex += sprintf(outputbuffer+bufferindex, "\n");
> -			} else if (THIS_KERNEL_VERSION > LINUX(2,4,9)) {
> -				if (vt->flags & PAGEFLAGS)
> -					bufferindex += translate_page_flags(outputbuffer+bufferindex, flags);
> -				else
> -					bufferindex += sprintf(outputbuffer+bufferindex, "%lx\n", flags);
> -			} else {
> -
> -		                if ((flags >> v24_PG_locked) & 1)
> -					bufferindex += sprintflag("%slocked");
> -				if ((flags >> v24_PG_error) & 1)
> -					bufferindex += sprintflag("%serror");
> -				if ((flags >> v24_PG_referenced) & 1)
> -					bufferindex += sprintflag("%sreferenced");
> -				if ((flags >> v24_PG_uptodate) & 1)
> -					bufferindex += sprintflag("%suptodate");
> -                                if ((flags >> v24_PG_dirty) & 1)
> -					bufferindex += sprintflag("%sdirty");
> -				if ((flags >> v24_PG_decr_after) & 1)
> -					bufferindex += sprintflag("%sdecr_after");
> -                                if ((flags >> v24_PG_active) & 1)
> -					bufferindex += sprintflag("%sactive");
> -                                if ((flags >> v24_PG_inactive_dirty) & 1)
> -					bufferindex += sprintflag("%sinactive_dirty");
> -				if ((flags >> v24_PG_slab) & 1)
> -					bufferindex += sprintflag("%sslab");
> -				if ((flags >> v24_PG_swap_cache) & 1)
> -					bufferindex += sprintflag("%sswap_cache");
> -				if ((flags >> v24_PG_skip) & 1)
> -					bufferindex += sprintflag("%sskip");
> -				if ((flags >> v24_PG_inactive_clean) & 1)
> -					bufferindex += sprintflag("%sinactive_clean");
> -				if ((flags >> v24_PG_highmem) & 1)
> -					bufferindex += sprintflag("%shighmem");
> -				if ((flags >> v24_PG_checked) & 1)
> -					bufferindex += sprintflag("%schecked");
> -				if ((flags >> v24_PG_bigpage) & 1)
> -					bufferindex += sprintflag("%sbigpage");
> -                                if ((flags >> v24_PG_arch_1) & 1)
> -					bufferindex += sprintflag("%sarch_1");
> -				if ((flags >> v24_PG_reserved) & 1)
> -					bufferindex += sprintflag("%sreserved");
> -				if (phys_not_mapped)
> -					bufferindex += sprintflag("%s[NOT MAPPED]");
> -
> -				bufferindex += sprintf(outputbuffer+bufferindex, "\n");
> +				if (v22) {
> +					if ((flags >> v22_PG_DMA) & 1)
> +						bufferindex += sprintflag("%sDMA");
> +					if ((flags >> v22_PG_locked) & 1)
> +						bufferindex += sprintflag("%slocked");
> +					if ((flags >> v22_PG_error) & 1)
> +						bufferindex += sprintflag("%serror");
> +					if ((flags >> v22_PG_referenced) & 1)
> +						bufferindex += sprintflag("%sreferenced");
> +					if ((flags >> v22_PG_dirty) & 1)
> +						bufferindex += sprintflag("%sdirty");
> +					if ((flags >> v22_PG_uptodate) & 1)
> +						bufferindex += sprintflag("%suptodate");
> +					if ((flags >> v22_PG_free_after) & 1)
> +						bufferindex += sprintflag("%sfree_after");
> +					if ((flags >> v22_PG_decr_after) & 1)
> +						bufferindex += sprintflag("%sdecr_after");
> +					if ((flags >> v22_PG_swap_unlock_after) & 1)
> +						bufferindex += sprintflag("%sswap_unlock_after");
> +					if ((flags >> v22_PG_Slab) & 1)
> +						bufferindex += sprintflag("%sslab");
> +					if ((flags >> v22_PG_swap_cache) & 1)
> +						bufferindex += sprintflag("%sswap_cache");
> +					if ((flags >> v22_PG_skip) & 1)
> +						bufferindex += sprintflag("%sskip");
> +					if ((flags >> v22_PG_reserved) & 1)
> +						bufferindex += sprintflag("%sreserved");
> +					bufferindex += sprintf(outputbuffer+bufferindex, "\n");
> +				} else if (THIS_KERNEL_VERSION > LINUX(2,4,9)) {
> +					if (vt->flags & PAGEFLAGS)
> +						bufferindex += translate_page_flags(outputbuffer+bufferindex, flags);
> +					else
> +						bufferindex += sprintf(outputbuffer+bufferindex, "%lx\n", flags);
> +				} else {
> +
> +					if ((flags >> v24_PG_locked) & 1)
> +						bufferindex += sprintflag("%slocked");
> +					if ((flags >> v24_PG_error) & 1)
> +						bufferindex += sprintflag("%serror");
> +					if ((flags >> v24_PG_referenced) & 1)
> +						bufferindex += sprintflag("%sreferenced");
> +					if ((flags >> v24_PG_uptodate) & 1)
> +						bufferindex += sprintflag("%suptodate");
> +					if ((flags >> v24_PG_dirty) & 1)
> +						bufferindex += sprintflag("%sdirty");
> +					if ((flags >> v24_PG_decr_after) & 1)
> +						bufferindex += sprintflag("%sdecr_after");
> +					if ((flags >> v24_PG_active) & 1)
> +						bufferindex += sprintflag("%sactive");
> +					if ((flags >> v24_PG_inactive_dirty) & 1)
> +						bufferindex += sprintflag("%sinactive_dirty");
> +					if ((flags >> v24_PG_slab) & 1)
> +						bufferindex += sprintflag("%sslab");
> +					if ((flags >> v24_PG_swap_cache) & 1)
> +						bufferindex += sprintflag("%sswap_cache");
> +					if ((flags >> v24_PG_skip) & 1)
> +						bufferindex += sprintflag("%sskip");
> +					if ((flags >> v24_PG_inactive_clean) & 1)
> +						bufferindex += sprintflag("%sinactive_clean");
> +					if ((flags >> v24_PG_highmem) & 1)
> +						bufferindex += sprintflag("%shighmem");
> +					if ((flags >> v24_PG_checked) & 1)
> +						bufferindex += sprintflag("%schecked");
> +					if ((flags >> v24_PG_bigpage) & 1)
> +						bufferindex += sprintflag("%sbigpage");
> +					if ((flags >> v24_PG_arch_1) & 1)
> +						bufferindex += sprintflag("%sarch_1");
> +					if ((flags >> v24_PG_reserved) & 1)
> +						bufferindex += sprintflag("%sreserved");
> +					if (phys_not_mapped)
> +						bufferindex += sprintflag("%s[NOT MAPPED]");
> +
> +					bufferindex += sprintf(outputbuffer+bufferindex, "\n");
> +				}
>  			}
>  	
>  			if (bufferindex > buffersize) {
> @@ -5851,6 +6033,12 @@ dump_mem_map(struct meminfo *mi)
>  
>  	FREEBUF(outputbuffer);
>  	FREEBUF(page_cache);
> +failed_member_data:
> +	if (mi->include) {
> +		FREEBUF(members);
> +		for (i = 0; i < nr_members; i++)
> +			free(member_data[i]);
> +	}
>  }
>  
>  /*
> --
> 1.9.3
> 
> --
> Crash-utility mailing list
> Crash-utility at redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility
> 




More information about the Crash-utility mailing list