[Crash-utility] [PATCH] Add -m option to kmem

Dave Anderson anderson at redhat.com
Fri Mar 1 21:20:45 UTC 2013



----- Original Message -----
> kmem -m is used for displaying information of all ksm pages or
> some ksm pages for specified ksm stable tree node addresses
> The information includes:
>         - physical address of ksm page,
>         - pid of tasks using this ksm page,
>         - counts of ksm page references for each task
> 
> for example:
>     crash> kmem -m ffff8803573964c0
>                  PID: 15864 16781
>            793005000:  8713  5584
> 
> ffff8803573964c0 is the address of ksm stable tree node.
> task 15864 has 8713 virtual pages mapping the page with address 793005000.
> task 16781 has 5584 virtual pages mapping the page with address 793005000.
> 
> P.S.
> This patch is based on the patch from Qiao(qiaonuohan at cn.fujitsu.com)
>     0001-make-rbtree-manipulation-functions-global.patch
> Because this patch also uses rb_tree operations.

I'll get to this patch after I get Qiao's patch straightened out and
checked in.

But a couple quick questions... 

What does "kmem -m" alone look like?  Your help page example only
shows the command passing a "ksm stable tree node address".  How
would a user know what one of those addresses would be?

And for "kmem -m <address>", what if there are dozens of PIDs that
are mapping the same physical address?  Regardless of the size of
the display window, eventually it would get messy if it extends to 
more than one line.  I try to avoid having commands extend beyond
80 columns if at all possible.  

Dave


> 
> Signed-off-by: Zhang Yanfei <zhangyanfei at cn.fujitsu.com>
> ---
>  defs.h    |    6 ++
>  help.c    |   19 +++++++-
>  memory.c  |  160
>  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  symbols.c |   12 +++++
>  4 files changed, 189 insertions(+), 8 deletions(-)
> 
> diff --git a/defs.h b/defs.h
> index 2993f2b..f6996be 100755
> --- a/defs.h
> +++ b/defs.h
> @@ -1848,6 +1848,12 @@ struct offset_table {                    /*
> stash of commonly-used offsets */
>  	long vmap_area_list;
>  	long vmap_area_flags;
>  	long vmap_area_vm;
> +	long stable_node_node;
> +	long stable_node_hlist;
> +	long stable_node_kpfn;
> +	long rmap_item_mm;
> +	long rmap_item_address;
> +	long rmap_item_hlist;
>  };
>  
>  struct size_table {         /* stash of commonly-used sizes */
> diff --git a/help.c b/help.c
> index c542743..bb5b675 100755
> --- a/help.c
> +++ b/help.c
> @@ -5148,7 +5148,7 @@ char *help_kmem[] = {
>  "kmem",
>  "kernel memory",
>  "[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-z-o] [slab] [[-P] address]\n"
> -"       [-g [flags]]",
> +"       [-g [flags] [-m [address]]",
>  "  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.",
> @@ -5174,6 +5174,11 @@ char *help_kmem[] = {
>  "            values to translate them into kernel virtual
>  addresses.",
>  "        -g  displays the enumerator value of all bits in the page
>  structure's",
>  "            \"flags\" field.",
> +"        -m  displays information of all ksm pages or some ksm pages
> for",
> +"            specified ksm stable tree node addresses. The
> information contains:",
> +"                physical address of ksm page",
> +"                pid of tasks using this ksm page",
> +"                counts of ksm page references for each task",
>  "     flags  when used with -g, translates all bits in this
>  hexadecimal page",
>  "            structure flags value into its enumerator values.",
>  "      slab  when used with -s or -S, limits the command to only the
>  slab cache",
> @@ -5204,7 +5209,10 @@ char *help_kmem[] = {
>  "            the page address is displayed if it is contained with
>  the list.",
>  "   address  when used with -v, the address can be a mapped kernel
>  virtual",
>  "            address or physical address; the mapped region
>  containing the",
> -"            address is displayed.\n",
> +"            address is displayed.",
> +"   address  when used with -m, the address should be a ksm stable
> tree node",
> +"            address; the information of the ksm page hanging off
> this node",
> +"            is displayed.\n",
>  "  All address arguments above must be expressed in hexadecimal
>  format.",
>  "\nEXAMPLES",
>  "  Display memory usage information:\n",
> @@ -5605,6 +5613,13 @@ char *help_kmem[] = {
>  "      PG_slab            7  0000080",
>  "      PG_head           14  0004000",
>  "    %s>",
> +"\n  Display information of ksm pages:\n",
> +"    %s> kmem -m ffff88086f22eec0 ffff8803573964c0",
> +"                 PID: 16781 ",
> +"           75e6af000:     2 ",
> +"",
> +"                 PID: 15864 16781 ",
> +"           793005000:  8713  5584 ",
>  NULL
>  };
>  
> diff --git a/memory.c b/memory.c
> index 02a6de1..bd9146f 100755
> --- a/memory.c
> +++ b/memory.c
> @@ -264,6 +264,7 @@ static int verify_pfn(ulong);
>  static void dump_per_cpu_offsets(void);
>  static void dump_page_flags(ulonglong);
>  static ulong kmem_cache_nodelists(ulong);
> +static void dump_ksm(struct meminfo *);
>  
>  /*
>   *  Memory display modes specific to this file.
> @@ -1012,6 +1013,16 @@ vm_init(void)
>  	PG_reserved_flag_init();
>  	PG_slab_flag_init();
>  
> +	if (STRUCT_EXISTS("stable_node")) {
> +		MEMBER_OFFSET_INIT(stable_node_node, "stable_node", "node");
> +		MEMBER_OFFSET_INIT(stable_node_hlist, "stable_node", "hlist");
> +		MEMBER_OFFSET_INIT(stable_node_kpfn, "stable_node", "kpfn");
> +		MEMBER_OFFSET_INIT(stable_node_node, "stable_node", "node");
> +		MEMBER_OFFSET_INIT(rmap_item_mm, "rmap_item", "mm");
> +		MEMBER_OFFSET_INIT(rmap_item_address, "rmap_item", "address");
> +		ANON_MEMBER_OFFSET_INIT(rmap_item_hlist, "rmap_item", "hlist");
> +	}
> +
>  	vt->flags |= VM_INIT;
>  }
>  
> @@ -4090,22 +4101,24 @@ cmd_kmem(void)
>  	int i;
>  	int c;
>  	int sflag, Sflag, pflag, fflag, Fflag, vflag, zflag, oflag, gflag;
> -	int nflag, cflag, Cflag, iflag, lflag, Lflag, Pflag, Vflag;
> +	int nflag, cflag, Cflag, iflag, lflag, Lflag, Pflag, Vflag, mflag;
>  	struct meminfo meminfo;
>  	ulonglong value[MAXARGS];
>  	char buf[BUFSIZE];
>  	char *p1;
>  	int spec_addr, escape;
> +	ulong ksm_pages_shared;
>  
>  	spec_addr = 0;
>          sflag =	Sflag = pflag = fflag = Fflag = Pflag = zflag =
>          oflag = 0;
>  	vflag = Cflag = cflag = iflag = nflag = lflag = Lflag = Vflag = 0;
> -	gflag = 0;
> +	gflag = mflag = 0;
>  	escape = FALSE;
> +	ksm_pages_shared = 0;
>  	BZERO(&meminfo, sizeof(struct meminfo));
>  	BZERO(&value[0], sizeof(ulonglong)*MAXARGS);
>  
> -        while ((c = getopt(argcnt, args, "gI:sSFfpvczCinl:L:PVo"))
> != EOF) {
> +        while ((c = getopt(argcnt, args, "gI:sSFfpvczCinl:L:PVom"))
> != EOF) {
>                  switch(c)
>  		{
>  		case 'V':
> @@ -4206,6 +4219,12 @@ cmd_kmem(void)
>  			gflag = 1;
>  			break;
>  
> +		case 'm':
> +			if (INVALID_MEMBER(stable_node_node))
> +				option_not_supported(c);
> +			mflag = 1;
> +			break;
> +
>  		default:
>  			argerrs++;
>  			break;
> @@ -4216,7 +4235,8 @@ cmd_kmem(void)
>  		cmd_usage(pc->curcmd, SYNOPSIS);
>  
>          if ((sflag + Sflag + pflag + fflag + Fflag + Vflag + oflag +
> -            vflag + Cflag + cflag + iflag + lflag + Lflag + gflag) >
> 1) {
> +            vflag + Cflag + cflag + iflag + lflag + Lflag + gflag +
> +	    mflag) > 1) {
>  		error(INFO, "only one flag allowed!\n");
>  		cmd_usage(pc->curcmd, SYNOPSIS);
>  	}
> @@ -4224,6 +4244,15 @@ cmd_kmem(void)
>  	if (sflag || Sflag || !(vt->flags & KMEM_CACHE_INIT))
>  		kmem_cache_init();
>  
> +	if (mflag) {
> +		get_symbol_data("ksm_pages_shared", sizeof(ulong),
> +				&ksm_pages_shared);
> +		if (!ksm_pages_shared) {
> +			fprintf(fp, "ksm may not be enabled\n");
> +			return;
> +		}
> +	}
> +
>  	while (args[optind]) {
>                  if (hexadecimal(args[optind], 0)) {
>                          value[spec_addr++] =
> @@ -4347,6 +4376,13 @@ cmd_kmem(void)
>  			gflag++;
>  		}
>  
> +		if (mflag) {
> +			meminfo.spec_addr = value[i];
> +			meminfo.flags = ADDRESS_SPECIFIED;
> +			dump_ksm(&meminfo);
> +			mflag++;
> +		}
> +
>                  /*
>                   * no value arguments allowed!
>                   */
> @@ -4358,7 +4394,7 @@ cmd_kmem(void)
>  		}
>  
>          	if (!(sflag + Sflag + pflag + fflag + vflag + cflag +
> -		      lflag + Lflag + gflag)) {
> +		      lflag + Lflag + gflag + mflag)) {
>  			meminfo.spec_addr = value[i];
>                          meminfo.flags = ADDRESS_SPECIFIED;
>                          if (meminfo.calls++)
> @@ -4444,9 +4480,12 @@ cmd_kmem(void)
>  	if (gflag == 1)
>  		dump_page_flags(0);
>  
> +	if (mflag == 1)
> +		dump_ksm(NULL);
> +
>  	if (!(sflag + Sflag + pflag + fflag + Fflag + vflag +
>  	      Vflag + zflag + oflag + cflag + Cflag + iflag +
> -	      nflag + lflag + Lflag + gflag + meminfo.calls))
> +	      nflag + lflag + Lflag + gflag + mflag + meminfo.calls))
>  		cmd_usage(pc->curcmd, SYNOPSIS);
>  
>  }
> @@ -15799,6 +15838,115 @@ dump_page_flags(ulonglong flags)
>          close_tmpfile();
>  }
>  
> +struct page_ref {
> +	ulong mm;
> +	ulong pid;
> +	int ref;
> +};
> +
> +/*
> + * dump_ksm() displays information of ksm pages.
> + */
> +static void
> +dump_ksm(struct meminfo *mi)
> +{
> +	ulong root_stable_tree, stable_node, kpfn;
> +	ulong rmap_item, mm, paddr;
> +	struct rb_root *root;
> +	struct rb_node *node;
> +	ulong first, next;
> +	struct task_context *tc;
> +	int i, ref_size, refs, found;
> +	struct page_ref *ref;
> +
> +	if (!symbol_exists("root_stable_tree")) {
> +		error(INFO, "cannot determine ksm stable tree address from
> root_stable_tree\n");
> +		return;
> +	}
> +	root_stable_tree = symbol_value("root_stable_tree");
> +	root = (struct rb_root *)root_stable_tree;
> +
> +	refs = 0;
> +	ref_size = sizeof(struct page_ref) * RUNNING_TASKS();
> +	ref = (struct page_ref *)GETBUF(ref_size);
> +	BZERO(ref, ref_size);
> +
> +	found = mi ? 0 : -1;
> +	for (node = rb_first(root); node; node = rb_next(node)) {
> +		stable_node = (ulong) node - OFFSET(stable_node_node);
> +		if (CRASHDEBUG(1))
> +			fprintf(fp, "  stable_node = %lx\n", stable_node);
> +
> +		readmem(stable_node + OFFSET(stable_node_hlist),
> +			KVADDR, &first, sizeof(ulong),
> +			"stable_node hlist", FAULT_ON_ERROR);
> +
> +		if (found == 0 && mi->spec_addr == stable_node)
> +			found = 1;
> +		if (found == 0)
> +			continue;
> +
> +		readmem(stable_node + OFFSET(stable_node_kpfn),
> +			KVADDR, &kpfn, sizeof(ulong),
> +			"stable_node kpfn", FAULT_ON_ERROR);
> +		paddr = kpfn << PAGE_SHIFT;
> +
> +		readmem(stable_node + OFFSET(stable_node_hlist),
> +			KVADDR, &first, sizeof(ulong),
> +			"stable_node hlist", FAULT_ON_ERROR);
> +
> +		next = first;
> +		while (next) {
> +			rmap_item = next - OFFSET(rmap_item_hlist);
> +			readmem(rmap_item + OFFSET(rmap_item_mm),
> +				KVADDR, &mm, sizeof(ulong),
> +				"rmap_item mm", FAULT_ON_ERROR);
> +
> +			for (i = 0; i < refs; i++) {
> +				if (ref[i].mm == mm) {
> +					ref[i].ref += 1;
> +					goto next;
> +				}
> +			}
> +
> +			tc = FIRST_CONTEXT();
> +       			for (i = 0; i < RUNNING_TASKS(); i++, tc++) {
> +				if (tc->mm_struct == mm) {
> +					ref[refs].mm = mm;
> +					ref[refs].pid = tc->pid;
> +					ref[refs++].ref = 1;
> +					break;
> +				}
> +			}
> +
> +next:
> +			readmem(next + OFFSET(hlist_node_next),
> +				KVADDR, &next, sizeof(ulong),
> +				"hlist_node next", FAULT_ON_ERROR);
> +		};
> +
> +		if (refs)
> +			fprintf(fp, "             PID: ");
> +		for (i = 0; i < refs; i++)
> +			fprintf(fp, "%5ld ", ref[i].pid);
> +		if (refs)
> +			fprintf(fp, "\n%16lx: ", paddr);
> +		for (i = 0; i < refs; i++)
> +			fprintf(fp, "%5d ", ref[i].ref);
> +		if (refs)
> +			fprintf(fp, "\n\n");
> +		refs = 0;
> +
> +		if (found == 1)
> +			break;
> +	}
> +
> +	if (found == 0)
> +		fprintf(fp, "address 0x%llx cannot specify a stable node\n",
> +			mi->spec_addr);
> +
> +	FREEBUF(ref);
> +}
>  
>  /*
>   *  Support for slub.c slab cache.
> diff --git a/symbols.c b/symbols.c
> index 4fb397c..6c730ad 100755
> --- a/symbols.c
> +++ b/symbols.c
> @@ -8860,6 +8860,18 @@ dump_offset_table(char *spec, ulong
> makestruct)
>  		OFFSET(rt_rq_highest_prio));
>  	fprintf(fp, "           rt_rq_rt_nr_running: %ld\n",
>  		OFFSET(rt_rq_rt_nr_running));
> +	fprintf(fp, "              stable_node_node: %ld\n",
> +		OFFSET(stable_node_node));
> +	fprintf(fp, "             stable_node_hlist: %ld\n",
> +		OFFSET(stable_node_hlist));
> +	fprintf(fp, "              stable_node_kpfn: %ld\n",
> +		OFFSET(stable_node_kpfn));
> +	fprintf(fp, "                  rmap_item_mm: %ld\n",
> +		OFFSET(rmap_item_mm));
> +	fprintf(fp, "             rmap_item_address: %ld\n",
> +		OFFSET(rmap_item_address));
> +	fprintf(fp, "               rmap_item_hlist: %ld\n",
> +		OFFSET(rmap_item_hlist));
>  
>  	fprintf(fp, "\n                    size_table:\n");
>  	fprintf(fp, "                          page: %ld\n", SIZE(page));
> --
> 1.7.1
> 
> --
> 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