[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