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:
that could possibly be leveraged to do such a thing. In fact
his help page uses the page structure as an example:
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(a)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(a)redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility