----- 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. > > For kernels where the page data structure includes the _mapcount field, > this patch is an enhancement to the "kmem -p" option to include a given > page's _mapcount value to be appended to the traditional output of the > command. > > For example: > > crash> kmem -p > PAGE PHYSICAL MAPPING INDEX COUNT MAPCOUNT FLAGS > ffffea0000000000 0 0 0 0 0 0 > ffffea0000000040 1000 0 0 1 -1 1ffff800000400 reserved > ffffea0000000080 2000 0 0 1 -1 1ffff800000400 reserved > ffffea00000000c0 3000 0 0 1 -1 1ffff800000400 reserved > ffffea0000000100 4000 0 0 1 -1 1ffff800000400 reserved > ... > > Please note that a given page's _mapcount value (much like the index field) > is always displayed by default regardless. The relevant kernel sources > should be consulted for the meaning of the hexadecimal bit value. And therein lies the rub... Back in the day -- as recently as the 2.6.18 era -- life was much simpler, where "kmem -p" just showed 4 fields from the actual page structure: crash> kmem -p PAGE PHYSICAL MAPPING INDEX CNT FLAGS ffff810100000000 0 0 0 1 400 ffff810100000038 1000 0 0 1 400 ffff810100000070 2000 0 0 1 400 ... where each of the 4 displayed fields were unique: crash> page -o struct page { [0] unsigned long flags; => FLAGS [8] atomic_t _count; => CNT [12] atomic_t _mapcount; union { struct { [16] unsigned long private; [24] struct address_space *mapping; => MAPPING }; [16] spinlock_t ptl; }; [32] unsigned long index; => INDEX [40] struct list_head lru; } SIZE: 56 crash> But since then, as you're well aware of, the page structure has been in a constant state of flux via the use of anonymous unions/structures. As a result, page->mapping and page->index now have multiple meanings, as does your proposed page->_mapcount field, which would be the most overloaded member: crash> page -o struct page { [0] unsigned long flags; => FLAGS union { [8] struct address_space *mapping; => MAPPING [8] void *s_mem; => MAPPING }; struct { union { [16] unsigned long index; => INDEX [16] void *freelist; => INDEX [16] bool pfmemalloc; => INDEX }; union { [24] unsigned long counters; struct { union { [24] atomic_t _mapcount; => MAPCOUNT struct { [24] unsigned int inuse : 16; => MAPCOUNT [24] unsigned int objects : 15; => MAPCOUNT [24] unsigned int frozen : 1; => MAPCOUNT }; [24] int units; => MAPCOUNT }; [28] atomic_t _count; => COUNT }; [24] unsigned int active; => MAPCOUNT }; }; union { [32] struct list_head lru; struct { [32] struct page *next; [40] int pages; [44] int pobjects; }; [32] struct slab *slab_page; [32] struct callback_head callback_head; [32] pgtable_t pmd_huge_pte; }; union { [48] unsigned long private; [48] spinlock_t ptl; [48] struct kmem_cache *slab_cache; [48] struct page *first_page; }; [56] struct mem_cgroup *mem_cgroup; } SIZE: 64 crash> As a result, the display of "kmem -p" is a mix-matching mess of pointers, bit-masks, and counter values, and where your patch actually makes things more confusing. For a few examples: crash> kmem -p PAGE PHYSICAL MAPPING INDEX COUNT MAPCOUNT FLAGS ffffea0000000000 0 0 0 0 0 0 ffffea0000000040 1000 0 0 1 -1 1ffff800000400 reserved ffffea0000000080 2000 0 0 1 -1 1ffff800000400 reserved ... ffffea0000000800 20000 0 ffff880000020680 1 -2143289293 1ffff800000080 slab ... ffffea0000000c00 30000 0 0 0 -128 1ffff800000000 ... ffffea0000004a40 129000 0 ffff880000129ec0 1 4194343 1ffff800000080 slab ffffea0000004a80 12a000 0 ffff88000012b200 1 2097156 1ffff800004080 slab,head ffffea0000004ac0 12b000 0 0 0 -1 1ffff800008000 tail ffffea0000004b00 12c000 0 0 1 1376277 1ffff800000080 slab ffffea0000004b40 12d000 0 0 1 2228258 1ffff800000080 slab ffffea0000004b80 12e000 0 ffff88000012ea80 1 -2146107383 1ffff800004080 slab,head ... It's probably the only place in the crash utility where the data displayed under a named column is simply not "right". I wonder whether somebody really needing specifics from page structures would be better served by combining the PAGE, PHYSICAL and perhaps FLAGS fields -- appended with a user-specified list of desired members? A while back Qiao Nuohan wrote a "pstruct" extension module: http://people.redhat.com/anderson/extensions.html#PSTRUCT that could possibly be leveraged to do such a thing. In fact his help page uses the page structure as an example: http://people.redhat.com/anderson/extensions/pstruct_help.html NAME pstruct - print structure member's data in one line SYNOPSIS pstruct struct_name.member[.member...,member...] [-d|-x] [-l offset] [address|symbol] DESCRIPTION This command displays the contents of a structure's members in one line. The arguments are as follows: struct_name name of a C-code structure used by the kernel. .member... name of a structure member; to display multiple members of a structure, use a comma-separated list of members. -l offset if the address argument is a pointer to a structure member that is contained by the target data structure, typically a pointer to an embedded list_head, the offset to the embedded member may be entered in either of the following manners: 1. in "structure.member" format. 2. a number of bytes. -x override default output format with hexadecimal format. -d override default output format with decimal format. EXAMPLE Display the page's member private, _count.counter, inuse at address 0xffffea00000308f0: crash> pstruct page.private,_count.counter,inuse 0xffffea00000308f0 0 198896 59904 Display the page's member mapping, index at address 0xffffea00000308f0 in hexadecimal format: crash> pstruct page.mapping,index ffffea000004c778 -x 0xffff88004b6412b8 0x100167 Maybe an option could be added for use with "kmem -p" only, that supplies a comma-separated list of desired fields, i.e., something like: crash> kmem -p -m member1,member2,member3 At least then you could get exactly what you want, and specify how you want it served. Comments? (from anybody in the list) Thanks, Dave > > Signed-off-by: Aaron Tomlin <atomlin@xxxxxxxxxx> > --- > defs.h | 1 + > memory.c | 60 ++++++++++++++++++++++++++++++++++++++++++------------------ > 2 files changed, 43 insertions(+), 18 deletions(-) > > diff --git a/defs.h b/defs.h > index f285622..c2d7a14 100644 > --- a/defs.h > +++ b/defs.h > @@ -1323,6 +1323,7 @@ struct offset_table { /* stash of > commonly-used offsets */ > long page_inode; > long page_offset; > long page_count; > + long page_mapcount; > long page_flags; > long page_mapping; > long page_index; > diff --git a/memory.c b/memory.c > index aacf929..7970be0 100644 > --- a/memory.c > +++ b/memory.c > @@ -424,6 +424,10 @@ vm_init(void) > if (INVALID_MEMBER(page_count)) > ANON_MEMBER_OFFSET_INIT(page_count, "page", "_count"); > } > + MEMBER_OFFSET_INIT(page_mapcount, "page", "_mapcount"); > + if (INVALID_MEMBER(page_mapcount)) { > + ANON_MEMBER_OFFSET_INIT(page_mapcount, "page", "_mapcount"); > + } > MEMBER_OFFSET_INIT(page_flags, "page", "flags"); > MEMBER_SIZE_INIT(page_flags, "page", "flags"); > MEMBER_OFFSET_INIT(page_mapping, "page", "mapping"); > @@ -431,8 +435,8 @@ vm_init(void) > ANON_MEMBER_OFFSET_INIT(page_mapping, "page", "mapping"); > if (INVALID_MEMBER(page_mapping) && > (THIS_KERNEL_VERSION < LINUX(2,6,17)) && > - MEMBER_EXISTS("page", "_mapcount")) > - ASSIGN_OFFSET(page_mapping) = MEMBER_OFFSET("page", "_mapcount") + > + VALID_MEMBER(page_mapcount)) > + ASSIGN_OFFSET(page_mapping) = OFFSET(page_mapcount) + > STRUCT_SIZE("atomic_t") + sizeof(ulong); > MEMBER_OFFSET_INIT(page_index, "page", "index"); > if (INVALID_MEMBER(page_index)) > @@ -4950,14 +4954,14 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) > { > ulong i; > long total_pages; > - int others, page_not_mapped, phys_not_mapped, page_mapping; > + int others, page_not_mapped, phys_not_mapped, page_mapping, page_mapcount; > ulong pp, ppend; > physaddr_t phys, physend; > ulong tmp, reserved, shared, slabs; > ulong PG_reserved_flag; > long buffers; > ulong inode, offset, flags, mapping, index; > - uint count; > + uint count, mapcount; > int print_hdr, pg_spec, phys_spec, done; > int v22; > char hdr[BUFSIZE]; > @@ -4996,7 +5000,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) > space(MINSPACE), > mkstring(buf4, 8, CENTER|RJUST, " "), > " "); > - sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%2d ", > + sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%6d ", > VADDR_PRLEN, > space(MINSPACE), > (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), > @@ -5004,7 +5008,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) > mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "-------"), > space(MINSPACE), > mkstring(buf4, 8, CENTER|RJUST, "-----")); > - sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%2d ", > + sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%6d ", > VADDR_PRLEN, > space(MINSPACE), > (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), > @@ -5013,9 +5017,10 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) > space(MINSPACE)); > > v22 = VALID_MEMBER(page_inode); /* page.inode vs. page.mapping */ > + page_mapcount = VALID_MEMBER(page_mapcount); > > if (v22) { > - sprintf(hdr, "%s%s%s%s%s%s%s%sCNT FLAGS\n", > + sprintf(hdr, "%s%s%s%s%s%s%s%sCOUNT FLAGS\n", > mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), > space(MINSPACE), > mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), > @@ -5026,7 +5031,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) > mkstring(buf4, 8, CENTER|LJUST, "OFFSET"), > space(MINSPACE-1)); > } else { > - sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n", > + sprintf(hdr, "%s%s%s%s%s%s%sCOUNT%sFLAGS\n", > mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), > space(MINSPACE), > mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), > @@ -5034,7 +5039,8 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) > space(MINSPACE), > mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"), > space(MINSPACE), > - mkstring(buf4, 8, CENTER|RJUST, "INDEX")); > + mkstring(buf4, 10, CENTER|RJUST, "INDEX"), > + (page_mapcount ? " MAPCOUNT " : " ")); > } > > mapping = index = 0; > @@ -5279,10 +5285,18 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) > else if (!page_mapping) > bufferindex += sprintf(outputbuffer+bufferindex, > (char *)&style3, pp, phys, count); > - else > + else { > bufferindex += sprintf(outputbuffer+bufferindex, > (char *)&style4, pp, phys, > mapping, index, count); > + if (page_mapcount) { > + mapcount = UINT(pcache + > + OFFSET(page_mapcount)); > + > + bufferindex += sprintf(outputbuffer+bufferindex, > + "%8d ", mapcount); > + } > + } > } > > others = 0; > @@ -5420,7 +5434,7 @@ dump_mem_map(struct meminfo *mi) > { > long i, n; > long total_pages; > - int others, page_not_mapped, phys_not_mapped, page_mapping; > + int others, page_not_mapped, phys_not_mapped, page_mapping, page_mapcount; > ulong pp, ppend; > physaddr_t phys, physend; > ulong tmp, reserved, shared, slabs; > @@ -5428,7 +5442,7 @@ dump_mem_map(struct meminfo *mi) > long buffers; > ulong inode, offset, flags, mapping, index; > ulong node_size; > - uint count; > + uint count, mapcount; > int print_hdr, pg_spec, phys_spec, done; > int v22; > struct node_table *nt; > @@ -5472,7 +5486,7 @@ dump_mem_map(struct meminfo *mi) > space(MINSPACE), > mkstring(buf4, 8, CENTER|RJUST, " "), > " "); > - sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%2d ", > + sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%6d ", > VADDR_PRLEN, > space(MINSPACE), > (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), > @@ -5480,7 +5494,7 @@ dump_mem_map(struct meminfo *mi) > mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "-------"), > space(MINSPACE), > mkstring(buf4, 8, CENTER|RJUST, "-----")); > - sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%2d ", > + sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%6d ", > VADDR_PRLEN, > space(MINSPACE), > (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), > @@ -5489,9 +5503,10 @@ dump_mem_map(struct meminfo *mi) > space(MINSPACE)); > > v22 = VALID_MEMBER(page_inode); /* page.inode vs. page.mapping */ > + page_mapcount = VALID_MEMBER(page_mapcount); > > if (v22) { > - sprintf(hdr, "%s%s%s%s%s%s%s%sCNT FLAGS\n", > + sprintf(hdr, "%s%s%s%s%s%s%s%sCOUNT FLAGS\n", > mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), > space(MINSPACE), > mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), > @@ -5502,7 +5517,7 @@ dump_mem_map(struct meminfo *mi) > mkstring(buf4, 8, CENTER|LJUST, "OFFSET"), > space(MINSPACE-1)); > } else { > - sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n", > + sprintf(hdr, "%s%s%s%s%s%s%sCOUNT%sFLAGS\n", > mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), > space(MINSPACE), > mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), > @@ -5510,7 +5525,8 @@ dump_mem_map(struct meminfo *mi) > space(MINSPACE), > mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"), > space(MINSPACE), > - mkstring(buf4, 8, CENTER|RJUST, "INDEX")); > + mkstring(buf4, 8, CENTER|RJUST, "INDEX"), > + (page_mapcount ? " MAPCOUNT " : " ")); > } > > mapping = index = 0; > @@ -5717,10 +5733,18 @@ dump_mem_map(struct meminfo *mi) > else if (!page_mapping) > bufferindex += sprintf(outputbuffer+bufferindex, > (char *)&style3, pp, phys, count); > - else > + else { > bufferindex += sprintf(outputbuffer+bufferindex, > (char *)&style4, pp, phys, > mapping, index, count); > + if (page_mapcount) { > + mapcount = UINT(pcache + > + OFFSET(page_mapcount)); > + > + bufferindex += sprintf(outputbuffer+bufferindex, > + "%8d ", mapcount); > + } > + } > } > > others = 0; > -- > 1.9.3 > > -- > Crash-utility mailing list > Crash-utility@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/crash-utility > -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility