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

Zhang Yanfei zhangyanfei at cn.fujitsu.com
Fri Mar 1 08:00:45 UTC 2013


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.

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




More information about the Crash-utility mailing list