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@xxxxxxxxxx> --- 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 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility