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

Zhang Yanfei zhangyanfei at cn.fujitsu.com
Wed Mar 27 02:30:39 UTC 2013


kmem -m|-M is used for displaying information of all ksm pages or
some ksm pages for specified ksm stable tree node addresses

for example:
crash> kmem -m
STABLE_NODE     : ffff88083fc927e0
PAGE            : ffffea000e667998
PHYSICAL ADDRESS: 41d475000

             PID: 2967 MAPPING: 3

STABLE_NODE     : ffff88083fc84a10
PAGE            : ffffea000e3dd5d8
PHYSICAL ADDRESS: 411aad000

             PID: 2967 MAPPING: 7

STABLE_NODE     : ffff88041980dda8
PAGE            : ffffea000e335568
PHYSICAL ADDRESS: 40eaab000

             PID: 2967 MAPPING: 8
...

STABLE_NODE     : ffff880841ea43f8
PAGE            : ffffea000f62de38
PHYSICAL ADDRESS: 465641000

             PID: 2967 MAPPING: 729
             PID: 3017 MAPPING: 499

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    |   41 +++++++++++-
 memory.c  |  209 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 symbols.c |   12 ++++
 4 files changed, 259 insertions(+), 9 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..38a3341 100755
--- a/help.c
+++ b/help.c
@@ -5147,8 +5147,8 @@ NULL
 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]]",
+"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-z|-o|-m|-M] [slab] [[-P] address]\n"
+"       [-g [flags]",
 "  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.",
@@ -5172,6 +5172,9 @@ char *help_kmem[] = {
 "        -z  displays per-zone memory statistics.",
 "        -o  displays each cpu's offset value that is added to per-cpu symbol",
 "            values to translate them into kernel virtual addresses.",
+"        -m  displays information of ksm pages.",
+"        -M  same as -m, but also dumps virtual addresses that mapping the",
+"            ksm pages.",
 "        -g  displays the enumerator value of all bits in the page structure's",
 "            \"flags\" field.",
 "     flags  when used with -g, translates all bits in this hexadecimal page",
@@ -5204,7 +5207,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 or -M, the address can be either a ksm stable",
+"            tree node address, a page's physical address, or a page pointer,",
+"            the information of the ksm page (if it is) is displayed.\n",
 "  All address arguments above must be expressed in hexadecimal format.",
 "\nEXAMPLES",
 "  Display memory usage information:\n",
@@ -5605,6 +5611,35 @@ char *help_kmem[] = {
 "      PG_slab            7  0000080",
 "      PG_head           14  0004000",
 "    %s>",
+"\n  Display information of ksm pages:\n",
+"    %s> kmem -m ffff88086f22eec0 ffff8803573964c0",
+"    STABLE_NODE     : ffff88083fc927e0",
+"    PAGE            : ffffea000e667998",
+"    PHYSICAL ADDRESS: 41d475000",
+"",
+"                 PID: 2967 MAPPING: 3",
+"",
+"    STABLE_NODE     : ffff88083fc84a10",
+"    PAGE            : ffffea000e3dd5d8",
+"    PHYSICAL ADDRESS: 411aad000",
+"",
+"                 PID: 2967 MAPPING: 7",
+"",
+"    STABLE_NODE     : ffff88041980dda8",
+"    PAGE            : ffffea000e335568",
+"    PHYSICAL ADDRESS: 40eaab000",
+"",
+"                 PID: 2967 MAPPING: 8",
+"",
+"    ......",
+"",
+"    STABLE_NODE     : ffff880841ea43f8",
+"    PAGE            : ffffea000f62de38",
+"    PHYSICAL ADDRESS: 465641000",
+"",
+"                 PID: 2967 MAPPING: 729",
+"                 PID: 3017 MAPPING: 499",
+"",
 NULL               
 };
 
diff --git a/memory.c b/memory.c
index 02a6de1..9623949 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,25 @@ 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;
+	int 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 = 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:PVomM")) != EOF) {
                 switch(c)
 		{
 		case 'V':
@@ -4206,6 +4220,18 @@ cmd_kmem(void)
 			gflag = 1;
 			break;
 
+		case 'm':
+			if (INVALID_MEMBER(stable_node_node))
+				option_not_supported(c);
+			mflag = 1;
+			break;
+
+		case 'M':
+			if (INVALID_MEMBER(stable_node_node))
+				option_not_supported(c);
+			Mflag = 1;
+			break;
+
 		default:
 			argerrs++;
 			break;
@@ -4216,7 +4242,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 + Mflag) > 1) {
 		error(INFO, "only one flag allowed!\n");
 		cmd_usage(pc->curcmd, SYNOPSIS);
 	} 
@@ -4224,6 +4251,15 @@ cmd_kmem(void)
 	if (sflag || Sflag || !(vt->flags & KMEM_CACHE_INIT))
 		kmem_cache_init();
 
+	if (mflag || 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 +4383,18 @@ cmd_kmem(void)
 			gflag++;
 		}
 
+		if (mflag || Mflag) {
+			meminfo.spec_addr = value[i];
+			meminfo.flags = ADDRESS_SPECIFIED;
+			if (Mflag)
+				meminfo.flags |= VERBOSE;
+			dump_ksm(&meminfo);
+			if (mflag)
+				mflag++;
+			if (Mflag)
+				Mflag++;
+		}
+
                 /* 
                  * no value arguments allowed! 
                  */
@@ -4358,7 +4406,7 @@ cmd_kmem(void)
 		}
 
         	if (!(sflag + Sflag + pflag + fflag + vflag + cflag + 
-		      lflag + Lflag + gflag)) {
+		      lflag + Lflag + gflag + mflag + Mflag)) {
 			meminfo.spec_addr = value[i];
                         meminfo.flags = ADDRESS_SPECIFIED;
                         if (meminfo.calls++)
@@ -4444,9 +4492,18 @@ cmd_kmem(void)
 	if (gflag == 1)
 		dump_page_flags(0);
 
+	if (mflag == 1)
+		dump_ksm(NULL);
+
+	if (Mflag == 1) {
+		meminfo.flags |= VERBOSE;
+		dump_ksm(&meminfo);
+	}
+
 	if (!(sflag + Sflag + pflag + fflag + Fflag + vflag + 
 	      Vflag + zflag + oflag + cflag + Cflag + iflag + 
-	      nflag + lflag + Lflag + gflag + meminfo.calls))
+	      nflag + lflag + Lflag + gflag + mflag + Mflag +
+	      meminfo.calls))
 		cmd_usage(pc->curcmd, SYNOPSIS);
 
 }
@@ -15799,6 +15856,146 @@ 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;
+	ulong page, address;
+
+	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 && mi->flags & ADDRESS_SPECIFIED) ? 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);
+		readmem(stable_node + OFFSET(stable_node_kpfn),
+			KVADDR, &kpfn, sizeof(ulong),
+			"stable_node kpfn", FAULT_ON_ERROR);
+		paddr = kpfn << PAGE_SHIFT;
+		phys_to_page(paddr, &page);
+
+		if (found == 0) {
+			if ((mi->memtype == KVADDR) &&
+			    (((mi->spec_addr & ~0x3) == stable_node) ||
+			     (mi->spec_addr == page)))
+				found = 1;
+			if ((mi->memtype == PHYSADDR) &&
+			    (mi->spec_addr == paddr))
+				found = 1;
+		}
+		if (found == 0)
+			continue;
+
+		fprintf(fp, "STABLE_NODE     : %lx\n", stable_node);
+		fprintf(fp, "PAGE            : %lx\n", page);
+		fprintf(fp, "PHYSICAL ADDRESS: %lx\n\n", paddr);
+
+		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);
+		};
+
+		for (i = 0; i < refs; i++) {
+			fprintf(fp, "             PID: %ld ", ref[i].pid);
+			fprintf(fp, "MAPPING: %d\n", ref[i].ref);
+
+			if (!(mi && mi->flags & VERBOSE))
+				continue;
+
+			fprintf(fp, "             VIRTUAL:\n");
+			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);
+				if (ref[i].mm == mm) {
+					readmem(rmap_item + OFFSET(rmap_item_address),
+						KVADDR, &address, sizeof(ulong),
+						"rmap_item address", FAULT_ON_ERROR);
+					fprintf(fp, "             %lx\n",
+						PAGEBASE(address));
+				}
+				readmem(next + OFFSET(hlist_node_next),
+					KVADDR, &next, sizeof(ulong),
+					"hlist_node next", FAULT_ON_ERROR);
+			}
+			fprintf(fp, "\n");
+		}
+		if (!(mi && mi->flags & VERBOSE))
+			fprintf(fp, "\n");
+		refs = 0;
+
+		if (found == 1)
+			break;
+	}
+
+	if (found == 0)
+		fprintf(fp, "address 0x%llx cannot specify a ksm stable tree 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