----- 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@xxxxxxxxxxxxxx) > 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@xxxxxxxxxxxxxx> > --- > 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@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/crash-utility > -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility