Hi Dave,
Hopefully this is satisfactory:
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(a)redhat.com>
---
help.c | 19 +++-
memory.c | 357 ++++++++++++++++++++++++++++++++++++++++++---------------------
2 files changed, 257 insertions(+), 119 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..0ec5f5a 100644
--- a/memory.c
+++ b/memory.c
@@ -54,6 +54,8 @@ struct meminfo { /* general purpose memory information
structure */
int current_cache_index;
ulong found;
ulong retval;
+ ulong nr_members;
+ struct struct_member_data *page_member_cache;
char *ignore;
int errors;
int calls;
@@ -4214,6 +4216,101 @@ tgid_quick_search(ulong tgid)
return NULL;
}
+static void
+collect_page_member_data(char *optlist, struct meminfo *mi)
+{
+ 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");
+
+ if ((LASTCHAR(optlist) == ',') || (LASTCHAR(optlist) == '.'))
+ error(FATAL, "invalid format: %s\n", optlist);
+
+ 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);
+ }
+ }
+
+ mi->nr_members = members;
+ mi->page_member_cache = page_member_cache;
+
+ FREEBUF(page_member_cache);
+}
+
+static int
+show_page_member_data(ulong *pp, struct meminfo *mi, char *outputbuffer)
+{
+ int bufferindex, i;
+ ulong buf;
+ struct struct_member_data *pmd;
+
+ bufferindex = 0;
+ pmd = mi->page_member_cache;
+
+ bufferindex += sprintf(outputbuffer + bufferindex,
+ "%lx\t", *pp);
+
+ for (i = 0; i < mi->nr_members; pmd++, i++) {
+
+ switch (pmd->type)
+ {
+ case TYPE_CODE_PTR:
+ readmem(*pp + pmd->offset, KVADDR, &buf,
+ pmd->length, "page_member_cache offset", FAULT_ON_ERROR);
+ bufferindex += sprintf(outputbuffer + bufferindex, "0x%lx\t",
+ buf);
+ break;
+ case TYPE_CODE_INT:
+ readmem(*pp + pmd->offset, KVADDR, &buf,
+ pmd->length, "page_member_cache offset", FAULT_ON_ERROR);
+ if (pmd->unsigned_type ||
+ pmd->length == sizeof(ulonglong))
+ bufferindex += sprintf(outputbuffer + bufferindex,
+ "%lu\t", buf);
+ else
+ bufferindex += sprintf(outputbuffer + bufferindex,
+ "%d\t", (int)buf);
+ break;
+ default:
+ error(FATAL, "invalid data structure reference: %s.%s\n",
+ pmd->structure, pmd->member);
+ break;
+ }
+ }
+
+ return bufferindex += sprintf(outputbuffer+bufferindex, "\n");
+}
+
/*
* Fill in the task_mem_usage structure with the RSS, virtual memory size,
* percent of physical memory being used, and the mm_struct address.
@@ -4425,7 +4522,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 +4577,10 @@ cmd_kmem(void)
pflag = 1;
break;
+ case 'm':
+ collect_page_member_data(optarg, &meminfo);
+ break;
+
case 'I':
meminfo.ignore = optarg;
break;
@@ -4980,62 +5081,64 @@ 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));
-
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->nr_members) {
+ 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"));
+ }
+ }
mapping = index = 0;
reserved = shared = slabs = buffers = inode = offset = 0;
@@ -5065,7 +5168,8 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
error(FATAL, "dump_mem_map: no memtype specified\n");
break;
}
- print_hdr = TRUE;
+ if (!mi->nr_members)
+ print_hdr = TRUE;
break;
case GET_ALL:
@@ -5092,7 +5196,8 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
break;
default:
- print_hdr = TRUE;
+ if (!mi->nr_members)
+ print_hdr = TRUE;
break;
}
@@ -5188,6 +5293,11 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
if (!done && (pg_spec || phys_spec))
continue;
+
+ if (mi->nr_members) {
+ bufferindex += show_page_member_data(&pp, mi, outputbuffer+bufferindex);
+ goto display_members;
+ }
flags = ULONG(pcache + OFFSET(page_flags));
if (SIZE(page_flags) == 4)
@@ -5364,6 +5474,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
bufferindex += sprintf(outputbuffer+bufferindex, "\n");
}
+display_members:
if (bufferindex > buffersize) {
fprintf(fp, "%s", outputbuffer);
bufferindex = 0;
@@ -5443,6 +5554,11 @@ dump_mem_map(struct meminfo *mi)
char *outputbuffer;
int bufferindex;
+ if (IS_SPARSEMEM()) {
+ dump_mem_map_SPARSEMEM(mi);
+ return;
+ }
+
buffersize = 1024 * 1024;
outputbuffer = GETBUF(buffersize + 512);
@@ -5451,67 +5567,64 @@ dump_mem_map(struct meminfo *mi)
char style3[100];
char style4[100];
- if (IS_SPARSEMEM()) {
- dump_mem_map_SPARSEMEM(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));
-
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->nr_members) {
+ 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"));
+ }
+ }
mapping = index = 0;
reserved = shared = slabs = buffers = inode = offset = 0;
@@ -5541,7 +5654,8 @@ dump_mem_map(struct meminfo *mi)
error(FATAL, "dump_mem_map: no memtype specified\n");
break;
}
- print_hdr = TRUE;
+ if (!mi->nr_members)
+ print_hdr = TRUE;
break;
case GET_ALL:
@@ -5568,7 +5682,8 @@ dump_mem_map(struct meminfo *mi)
break;
default:
- print_hdr = TRUE;
+ if (!mi->nr_members)
+ print_hdr = TRUE;
break;
}
@@ -5626,6 +5741,11 @@ dump_mem_map(struct meminfo *mi)
if (!done && (pg_spec || phys_spec))
continue;
+ if (mi->nr_members) {
+ bufferindex += show_page_member_data(&pp, mi, outputbuffer+bufferindex);
+ goto display_members;
+ }
+
flags = ULONG(pcache + OFFSET(page_flags));
if (SIZE(page_flags) == 4)
flags &= 0xffffffff;
@@ -5802,6 +5922,7 @@ dump_mem_map(struct meminfo *mi)
bufferindex += sprintf(outputbuffer+bufferindex, "\n");
}
+display_members:
if (bufferindex > buffersize) {
fprintf(fp, "%s", outputbuffer);
bufferindex = 0;
--
1.9.3