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(a)cn.fujitsu.com)
0001-make-rbtree-manipulation-functions-global.patch
Because this patch also uses rb_tree operations.
Signed-off-by: Zhang Yanfei <zhangyanfei(a)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