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@xxxxxxxxxxxxxx) 0001-make-rbtree-manipulation-functions-global.patch Because this patch also uses rb_tree operations. Signed-off-by: Zhang Yanfei <zhangyanfei@xxxxxxxxxxxxxx> --- 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 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility