[Crash-utility] [PATCH] kmem: Show a page's _mapcount value in dump_mem_map()
Dave Anderson
anderson at redhat.com
Fri Apr 10 18:47:00 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.
>
> 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 at redhat.com>
> ---
> 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 at redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility
>
More information about the Crash-utility
mailing list