From 3d313aaf5d9fedd91e81ac596fe407614dd57de1 Mon Sep 17 00:00:00 2001 From: Qiao Nuohan Date: Wed, 11 Jun 2014 10:01:21 +0800 Subject: [PATCH] Fix ksm.c Because of the following kernel patch, 'root_stable_tree' and 'struct stable_node' are changed. ef53d16cded7f89b3843b7a96970dab897843ea5 90bd6fd31c8097ee4ddcb74b7e08363134863de5 4146d2d673e8d6abf9b30a5b5dd8cd95f29632eb Another two change are listed below. 1. add mm_struct's address for the task. ksm displayed ksm page's messages like below PAGE: ffffea000451f180 STABLE_NODE: ffff88004866b6c0 PHYSICAL ADDRESS: 1147c6000 PID: 1318 MAPPINGS: 7707 PID: 1297 MAPPINGS: 4965 Now, MM item is added to show the mm_struct's address related to task, like below PAGE: ffffea000451f180 STABLE_NODE: ffff88004866b6c0 PHYSICAL ADDRESS: 1147c6000 PID: 1318 MAPPINGS: 7707 MM: ffff88007f8abe80 PID: 1297 MAPPINGS: 4965 MM: ffff88007f8aa580 2. the task that uses ksm pages may have exited. this patch will change to show the exited task's "MAPPINGS" and "MM" like below PAGE: ffffea000292ca40 STABLE_NODE: ffff88009fe8e9c0 PHYSICAL ADDRESS: a4b29000 PID: - MAPPINGS: 1 MM: ffff880115f28000 PID: - MAPPINGS: 1 MM: ffff8800cdd7a580 task has exited, so PID is "-" Signed-off-by: Qiao Nuohan --- extensions/ksm.c | 289 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 192 insertions(+), 97 deletions(-) diff --git a/extensions/ksm.c b/extensions/ksm.c index ce02318..ef97c92 100644 --- a/extensions/ksm.c +++ b/extensions/ksm.c @@ -1,6 +1,7 @@ /* - * Copyright (C) 2013 FUJITSU LIMITED + * Copyright (C) 2013-2014 FUJITSU LIMITED * Author: Zhang Yanfei + * Signed-off-by: Qiao Nuohan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +23,7 @@ void cmd_ksm(void); char *help_ksm[]; static struct command_table_entry command_table[] = { - { "ksm", cmd_ksm, help_ksm, 0}, + { "ksm", cmd_ksm, help_ksm, 0}, { NULL }, }; @@ -35,7 +36,8 @@ struct ksm_offset_table { long rmap_item_hlist; } ksm_offset_table; -#define KSM_ASSIGN_OFFSET(X) (ksm_offset_table.X) +#define KSM_ASSIGN_OFFSET(X) (ksm_offset_table.X) +#define KSM_INVALID_MEMBER(X) (ksm_offset_table.X == INVALID_OFFSET) #define KSM_MEMBER_OFFSET_INIT(X, Y, Z) (KSM_ASSIGN_OFFSET(X) = MEMBER_OFFSET(Y, Z)) #define KSM_ANON_MEMBER_OFFSET_INIT(X, Y, Z) (KSM_ASSIGN_OFFSET(X) = ANON_MEMBER_OFFSET(Y, Z)) #define KSM_OFFSET(X) (OFFSET_verify(ksm_offset_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X)) @@ -50,27 +52,30 @@ struct page_ref { ulong mm; ulong pid; int ref; + struct page_ref *next; }; static void dump_ksm(struct meminfo *); void __attribute__((constructor)) ksm_init(void) /* Register the command set. */ -{ +{ if (STRUCT_EXISTS("stable_node")) { KSM_MEMBER_OFFSET_INIT(stable_node_node, "stable_node", "node"); + if (KSM_INVALID_MEMBER(stable_node_node)) + KSM_ANON_MEMBER_OFFSET_INIT(stable_node_node, "stable_node", "node"); + KSM_MEMBER_OFFSET_INIT(stable_node_hlist, "stable_node", "hlist"); KSM_MEMBER_OFFSET_INIT(stable_node_kpfn, "stable_node", "kpfn"); - KSM_MEMBER_OFFSET_INIT(stable_node_node, "stable_node", "node"); KSM_MEMBER_OFFSET_INIT(rmap_item_mm, "rmap_item", "mm"); KSM_MEMBER_OFFSET_INIT(rmap_item_address, "rmap_item", "address"); KSM_ANON_MEMBER_OFFSET_INIT(rmap_item_hlist, "rmap_item", "hlist"); } else - error(FATAL, "ksm_init: stable_node does not exist\n"); + error(FATAL, "ksm_init: stable_node does not exist\n"); register_extension(command_table); } - + void __attribute__((destructor)) ksm_fini(void) { } @@ -139,15 +144,17 @@ cmd_ksm(void) } char *help_ksm[] = { - "ksm", + "ksm", "kernel samepage merging (KSM) information", - "[-v] [[-p] address ...]", - + "[-v] [[-p] address ...]", + " This command displays information about all KSM pages currently", " in use. For each KSM page, the display includes its stable_node", - " address, its page struct address, its physical address, the TGID/PID", - " for each task that is using the page, and the number of mappings in", - " the task's address space for the page.", + " address, its page struct address, its physical address, the TGID/PID", + " for each task that is using the page, the number of mappings in the", + " task's address space for the page, and the mm_struct address of the", + " task. If pid is '-', the task has exited and the ksm page has not", + " been removed.", " ", " -v also dump each virtual address in a PID's virtual address", " space that maps the KSM page.", @@ -159,88 +166,129 @@ char *help_ksm[] = { "\nEXAMPLE", " Display information about all KSM pages:\n", " %s> ksm", -// " STABLE_NODE : ffff8806248c2d80", -// " PAGE : ffffea000ae7f6a8", -// " PHYSICAL ADDRESS: 31db43000", - " PAGE: ffffea000ae7f6a8", - " STABLE_NODE: ffff8806248c2d80", - " PHYSICAL ADDRESS: 31db43000", - " PID: 2205 MAPPINGS: 2", + " PAGE: ffffea000451f180", + " STABLE_NODE: ffff88004866b6c0", + " PHYSICAL ADDRESS: 1147c6000", + " PID: 1318 MAPPINGS: 7707 MM: ffff88007f8abe80", + " PID: 1297 MAPPINGS: 4965 MM: ffff88007f8aa580", "", -// " STABLE_NODE : ffff880624aa57b8", -// " PAGE : ffffea000ae800f0", -// " PHYSICAL ADDRESS: 31db72000", - " PAGE: ffffea000ae800f0", - " STABLE_NODE: ffff880624aa57b8", - " PHYSICAL ADDRESS: 31db72000", - " PID: 2205 MAPPINGS: 2", + " PAGE: ffffea0003413c40", + " STABLE_NODE: ffff880117bfbfc0", + " PHYSICAL ADDRESS: d04f1000", + " PID: 1297 MAPPINGS: 1 MM: ffff88007f8aa580", + " PID: 1318 MAPPINGS: 1 MM: ffff88007f8abe80", "", -// " STABLE_NODE : ffff8806248c2dd0", -// " PAGE : ffffea000ae7f8d8", -// " PHYSICAL ADDRESS: 31db4d000", - " PAGE: ffffea000ae7f8d8", - " STABLE_NODE: ffff8806248c2dd0", - " PHYSICAL ADDRESS: 31db4d000", - " PID: 2205 MAPPINGS: 2", + " PAGE: ffffea00021e9880", + " STABLE_NODE: ffff880054ee1f30", + " PHYSICAL ADDRESS: 87a62000", + " PID: 1297 MAPPINGS: 2 MM: ffff88007f8aa580", " ...", "", " Display all information about the KSM page whose physical", - " address is 0x626e60000:\n", - " %s> ksm -v 626e60000", - " PAGE: ffffea0015882500", - " STABLE_NODE: ffff88028b2af3d0", - " PHYSICAL ADDRESS: 626e60000", - " PID: 2603 MAPPINGS: 8", + " address is 0xffffea000168cd00:\n", + " %s> ksm -v ffffea000168cd00", + " PAGE: ffffea000168cd00", + " STABLE_NODE: ffff88007153ce10", + " PHYSICAL ADDRESS: 5a334000", + " PID: 1297 MAPPINGS: 4 MM: ffff88007f8aa580", " VIRTUAL:", - " 7ff46bcb4000", - " 7ff46bcad000", - " 7ff46bc9f000", - " 7ff46bc7c000", - " 7ff46bc6e000", - " 7ff46bc67000", - " 7ff46bc60000", - " 7ff46bc59000", + " 7f8cb91f9000", + " 7f8cb8f28000", + " 7f8cb7abf000", + " 7f8cb79c7000", + "", + " PID: 1318 MAPPINGS: 4 MM: ffff88007f8abe80", + " VIRTUAL:", + " 7f7ca0703000", + " 7f7c9f15e000", + " 7f7c9ef8f000", + " 7f7c9e96b000", NULL }; +/* + * find the page_ref whose mm is same as mm + */ +static struct page_ref * +find_match_ref(struct page_ref *ref_list, ulong mm) +{ + struct page_ref *next_ref = ref_list; + + while (next_ref) { + if (next_ref->mm == mm) { + break; + } else { + next_ref = next_ref->next; + } + } + + return next_ref; +} /* - * dump_ksm() displays information of ksm pages. + * get the pid of the task that mm_struct belongs to, if not find, + * return (ulong)-1 */ +static ulong +find_pid(ulong mm) +{ + struct task_context *tc; + int i; + ulong pid = -1; + + tc = FIRST_CONTEXT(); + for (i = 0; i < RUNNING_TASKS(); i++, tc++) { + if (tc->mm_struct == mm) { + pid = tc->pid; + break; + } + } + + return pid; +} + static void -dump_ksm(struct meminfo *mi) +add_to_ref_list(struct page_ref **ref_list_ptr, struct page_ref *ref) { - ulong root_stable_tree, stable_node, kpfn; + ref->next = *ref_list_ptr; + *ref_list_ptr = ref; +} + +static void +clean_ref_list(struct page_ref *ref_list) +{ + struct page_ref *tmp_ref, *next_ref; + + tmp_ref = ref_list; + + while (tmp_ref) { + next_ref = tmp_ref->next; + FREEBUF(tmp_ref); + tmp_ref = next_ref; + } +} + +/* + * dump the ksm pages from the stable tree + */ +static void +dump_stable_tree(struct meminfo *mi, struct rb_root *root) +{ + ulong 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; + int found; + struct page_ref *ref_list; 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 - KSM_OFFSET(stable_node_node); if (CRASHDEBUG(1)) fprintf(fp, " stable_node = %lx\n", stable_node); - readmem(stable_node + KSM_OFFSET(stable_node_hlist), - KVADDR, &first, sizeof(ulong), - "stable_node hlist", FAULT_ON_ERROR); readmem(stable_node + KSM_OFFSET(stable_node_kpfn), KVADDR, &kpfn, sizeof(ulong), "stable_node kpfn", FAULT_ON_ERROR); @@ -259,10 +307,6 @@ dump_ksm(struct meminfo *mi) 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); - fprintf(fp, " PAGE: %lx\n", page); fprintf(fp, " STABLE_NODE: %lx\n", stable_node); fprintf(fp, "PHYSICAL ADDRESS: %lx\n", paddr); @@ -272,41 +316,51 @@ dump_ksm(struct meminfo *mi) "stable_node hlist", FAULT_ON_ERROR); next = first; + ref_list = NULL; + struct page_ref *tmp_ref = NULL; + while (next) { rmap_item = next - KSM_OFFSET(rmap_item_hlist); readmem(rmap_item + KSM_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; - } + //get the page_ref whose mm is equal to rmap_item's mm + tmp_ref = find_match_ref(ref_list, mm); + if (tmp_ref) { + tmp_ref->ref += 1; + } else { + //create a new page_ref + tmp_ref = (struct page_ref *)GETBUF( + sizeof(struct page_ref)); + tmp_ref->mm = mm; + tmp_ref->pid = find_pid(mm); + tmp_ref->ref = 1; + + add_to_ref_list(&ref_list, tmp_ref); } -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, " MAPPINGS: %d\n", ref[i].ref); + tmp_ref = ref_list; + while (tmp_ref) { + if (tmp_ref->pid == (ulong)-1) { + /* + * the task has exited, but the ksm pages has + * not been cleared yet. + */ + fprintf(fp, " PID: - "); + } else { + fprintf(fp, " PID: %ld ", tmp_ref->pid); + } + fprintf(fp, " MAPPINGS: %d ", tmp_ref->ref); + fprintf(fp, " MM: %lx\n", tmp_ref->mm); if (!(mi && mi->flags & VERBOSE)) - continue; + goto next_ref; fprintf(fp, " VIRTUAL:\n"); next = first; @@ -315,7 +369,7 @@ next: readmem(rmap_item + KSM_OFFSET(rmap_item_mm), KVADDR, &mm, sizeof(ulong), "rmap_item mm", FAULT_ON_ERROR); - if (ref[i].mm == mm) { + if (tmp_ref->mm == mm) { readmem(rmap_item + KSM_OFFSET(rmap_item_address), KVADDR, &address, sizeof(ulong), "rmap_item address", FAULT_ON_ERROR); @@ -327,10 +381,16 @@ next: "hlist_node next", FAULT_ON_ERROR); } fprintf(fp, "\n"); + +next_ref: + tmp_ref = tmp_ref->next; } + + //clear all page_ref + clean_ref_list(ref_list); + if (!(mi && mi->flags & VERBOSE)) fprintf(fp, "\n"); - refs = 0; if (found == 1) break; @@ -339,6 +399,41 @@ next: if (found == 0) fprintf(fp, "address 0x%llx cannot specify a ksm stable tree node\n", mi->spec_addr); +} - FREEBUF(ref); +/* + * dump_ksm() displays information of ksm pages. + */ +static void +dump_ksm(struct meminfo *mi) +{ + ulong root_stable_tree_ptr; + ulong ksm_nr_node_ids_ptr; + int ksm_nr_node_ids; + struct rb_root *root; + int i; + + if (!symbol_exists("root_stable_tree")) { + error(INFO, "cannot determine ksm stable tree address from root_stable_tree\n"); + return; + } + root_stable_tree_ptr = symbol_value("root_stable_tree"); + + if (symbol_exists("ksm_nr_node_ids")) { + //root_stable_tree_ptr is an array of stable tree root + ksm_nr_node_ids_ptr = symbol_value("ksm_nr_node_ids"); + readmem(ksm_nr_node_ids_ptr, KVADDR, &ksm_nr_node_ids, + sizeof(ksm_nr_node_ids), "ksm_nr_node_ids", + FAULT_ON_ERROR); + + readmem(root_stable_tree_ptr, KVADDR, &root, sizeof(ulong), + "first stable tree root", FAULT_ON_ERROR); + + for (i = 0; i < ksm_nr_node_ids; i++) { + dump_stable_tree(mi, root + i); + } + } else { + root = (struct rb_root *)root_stable_tree_ptr; + dump_stable_tree(mi, root); + } } -- 1.8.5.3