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(a)cn.fujitsu.com)
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(a)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
--
Crash-utility mailing list
Crash-utility(a)redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility