Expand dump-functions for excluding user/unused memory (This is rebase commit for merging to development)

This commit is contained in:
Katsuya Horigome
2017-08-02 10:29:10 +09:00
committed by Ken Sato
parent 325082a571
commit a05b6e1ba8
171 changed files with 11516 additions and 1615 deletions

View File

@@ -65,8 +65,10 @@ extern void rb_erase(struct rb_node *, struct rb_root *);
/* Find logical next and previous nodes in a tree */
extern struct rb_node *rb_next(const struct rb_node *);
extern struct rb_node *rb_next_safe(const struct rb_node *);
extern struct rb_node *rb_prev(const struct rb_node *);
extern struct rb_node *rb_first(const struct rb_root *);
extern struct rb_node *rb_first_safe(const struct rb_root *);
extern struct rb_node *rb_last(const struct rb_root *);
/* Postorder iteration - always visit the parent after its children */

View File

@@ -48,6 +48,8 @@
#define ekprintf(...) do { kprintf(__VA_ARGS__); } while (0)
#endif
#define DUMP_LEVEL_USER_UNUSED_EXCLUDE 24
int osnum = 0;
extern struct ihk_kmsg_buf kmsg_buf;
@@ -426,12 +428,26 @@ int main(void)
{
char *ptr;
int mode = 0;
char *key_dump_level = "dump_level=";
unsigned int dump_level = DUMP_LEVEL_USER_UNUSED_EXCLUDE;
ptr = find_command_line("ksyslogd=");
if (ptr) {
mode = ptr[9] - 0x30;
if (mode < 0 || mode > 2) mode = 0;
}
ptr = find_command_line(key_dump_level);
if (ptr) {
ptr += strlen(key_dump_level);
dump_level = 0;
while (('0' <= *ptr) && (*ptr <= '9')) {
dump_level *= 10;
dump_level += *ptr++ - '0';
}
}
ihk_mc_set_dump_level(dump_level);
kmsg_init(mode);
kputs("IHK/McKernel started.\n");

View File

@@ -41,6 +41,7 @@
#include <rusage.h>
#include <syscall.h>
#include <profile.h>
#include <process.h>
#include <limits.h>
#include <sysfs.h>
@@ -114,6 +115,38 @@ struct pagealloc_track_entry {
ihk_spinlock_t addr_list_lock;
};
struct page_table {
pte_t entry[PT_ENTRIES];
};
struct ihk_dump_page {
unsigned long start;
unsigned long map_count;
unsigned long map[0];
};
struct ihk_dump_page_set {
volatile unsigned int completion_flag;
unsigned int count;
unsigned long page_size;
unsigned long phy_page;
};
struct dump_pase_info {
struct ihk_dump_page_set *dump_page_set;
struct ihk_dump_page *dump_pages;
};
#define IHK_DUMP_PAGE_SET_INCOMPLETE 0
#define IHK_DUMP_PAGE_SET_COMPLETED 1
#define DUMP_LEVEL_ALL 0
#define DUMP_LEVEL_USER_UNUSED_EXCLUDE 24
/** Get the index in the map array */
#define MAP_INDEX(n) ((n) >> 6)
/** Get the bit number in a map element */
#define MAP_BIT(n) ((n) & 0x3f)
void pagealloc_track_init(void)
{
if (!pagealloc_track_initialized) {
@@ -2241,3 +2274,211 @@ int is_mckernel_memory(unsigned long phys)
}
#endif /* IHK_RBTREE_ALLOCATOR */
#endif /* POSTK_DEBUG_TEMP_FIX_52 */
void ihk_mc_query_mem_areas(void){
int cpu_id;
struct ihk_dump_page_set *dump_page_set;
struct dump_pase_info dump_pase_info;
/* Performed only for CPU 0 */
cpu_id = ihk_mc_get_processor_id();
if (0 != cpu_id)
return;
dump_page_set = ihk_mc_get_dump_page_set();
if (DUMP_LEVEL_USER_UNUSED_EXCLUDE == ihk_mc_get_dump_level()) {
if (dump_page_set->count) {
dump_pase_info.dump_page_set = dump_page_set;
dump_pase_info.dump_pages = ihk_mc_get_dump_page();
/* Get user page information */
ihk_mc_query_mem_user_page((void *)&dump_pase_info);
/* Get unused page information */
ihk_mc_query_mem_free_page((void *)&dump_pase_info);
}
}
dump_page_set->completion_flag = IHK_DUMP_PAGE_SET_COMPLETED;
return;
}
void ihk_mc_query_mem_user_page(void *dump_pase_info) {
struct resource_set *rset = cpu_local_var(resource_set);
struct process_hash *phash = rset->process_hash;
struct process *p;
struct process_vm *vm;
int i;
for (i=0; i<HASH_SIZE; i++) {
list_for_each_entry(p, &phash->list[i], hash_list){
vm = p->vm;
if (vm) {
if(vm->address_space->page_table) {
visit_pte_range_safe(vm->address_space->page_table, 0,
(void *)USER_END, 0, 0,
&ihk_mc_get_mem_user_page, (void *)dump_pase_info);
}
}
}
}
return;
}
void ihk_mc_query_mem_free_page(void *dump_pase_info) {
struct free_chunk *chunk;
struct rb_node *node;
struct rb_root *free_chunks;
unsigned long phy_start, map_start, map_end, free_pages, free_page_cnt, map_size, set_size, k;
int i, j;
struct ihk_dump_page_set *dump_page_set;
struct ihk_dump_page *dump_page;
struct dump_pase_info *dump_pase_in;
unsigned long chunk_addr, chunk_size;
dump_pase_in = (struct dump_pase_info *)dump_pase_info;
dump_page_set = dump_pase_in->dump_page_set;
/* Search all NUMA nodes */
for (i = 0; i < ihk_mc_get_nr_numa_nodes(); i++) {
free_chunks = &memory_nodes[i].free_chunks;
free_pages = memory_nodes[i].nr_free_pages;
/* rb-tree search */
for (free_page_cnt = 0, node = rb_first_safe(free_chunks); node; free_page_cnt++, node = rb_next_safe(node)) {
if (free_page_cnt >= free_pages)
break;
/* Get chunk information */
chunk = container_of(node, struct free_chunk, node);
dump_page = dump_pase_in->dump_pages;
chunk_addr = chunk->addr;
chunk_size = chunk->size;
for (j = 0; j < dump_page_set->count; j++) {
if (j) {
dump_page = (struct ihk_dump_page *)((char *)dump_page + ((dump_page->map_count * sizeof(unsigned long)) + sizeof(struct ihk_dump_page)));
}
phy_start = dump_page->start;
map_size = (dump_page->map_count << (PAGE_SHIFT+6));
if ((chunk_addr >= phy_start)
&& ((phy_start + map_size) >= chunk_addr)) {
/* Set free page to page map */
map_start = (chunk_addr - phy_start) >> PAGE_SHIFT;
if ((phy_start + map_size) < (chunk_addr + chunk_size)) {
set_size = map_size - (chunk_addr - phy_start);
map_end = (map_start + (set_size >> PAGE_SHIFT));
chunk_addr += set_size;
chunk_size -= set_size;
} else {
map_end = (map_start + (chunk_size >> PAGE_SHIFT));
}
for (k = map_start; k < map_end; k++) {
if (MAP_INDEX(k) >= dump_page->map_count) {
kprintf("%s:free page is out of range(max:%d): %ld (map_start:0x%lx, map_end:0x%lx) k(0x%lx)\n", __FUNCTION__, dump_page->map_count, MAP_INDEX(k), map_start, map_end, k);
break;
}
dump_page->map[MAP_INDEX(k)] &= ~(1UL << MAP_BIT(k));
}
}
}
}
}
return;
}
int ihk_mc_chk_page_address(pte_t mem_addr){
int i, numa_id;;
unsigned long start, end;
/* Search all NUMA nodes */
for (i = 0; i < ihk_mc_get_nr_memory_chunks(); i++) {
ihk_mc_get_memory_chunk(i, &start, &end, &numa_id);
if ((mem_addr >= start) && (end >= mem_addr))
return 0;
}
return -1;
}
int ihk_mc_get_mem_user_page(void *arg0, page_table_t pt, pte_t *ptep, void *pgaddr, int pgshift)
{
struct ihk_dump_page_set *dump_page_set;
int i;
unsigned long j, phy_start, phys, map_start, map_end, map_size, set_size;
struct ihk_dump_page *dump_page;
struct dump_pase_info *dump_pase_in;
unsigned long chunk_addr, chunk_size;
if (((*ptep) & PTATTR_ACTIVE) && ((*ptep) & PTATTR_USER)) {
phys = pte_get_phys(ptep);
/* Confirm accessible address */
if (-1 != ihk_mc_chk_page_address(phys)) {
dump_pase_in = (struct dump_pase_info *)arg0;
dump_page_set = dump_pase_in->dump_page_set;
dump_page = dump_pase_in->dump_pages;
chunk_addr = phys;
chunk_size = (1UL << pgshift);
for (i = 0; i < dump_page_set->count; i++) {
if (i) {
dump_page = (struct ihk_dump_page *)((char *)dump_page + ((dump_page->map_count * sizeof(unsigned long)) + sizeof(struct ihk_dump_page)));
}
phy_start = dump_page->start;
map_size = (dump_page->map_count << (PAGE_SHIFT+6));
if ((chunk_addr >= phy_start)
&& ((phy_start + map_size) >= chunk_addr)) {
/* Set user page to page map */
map_start = (chunk_addr - phy_start) >> PAGE_SHIFT;
if ((phy_start + map_size) < (chunk_addr + chunk_size)) {
set_size = map_size - (chunk_addr - phy_start);
map_end = (map_start + (set_size >> PAGE_SHIFT));
chunk_addr += set_size;
chunk_size -= set_size;
} else {
map_end = (map_start + (chunk_size >> PAGE_SHIFT));
}
for (j = map_start; j < map_end; j++) {
if (MAP_INDEX(j) >= dump_page->map_count) {
kprintf("%s:user page is out of range(max:%d): %ld (map_start:0x%lx, map_end:0x%lx) j(0x%lx)\n", __FUNCTION__, dump_page->map_count, MAP_INDEX(j), map_start, map_end, j);
break;
}
dump_page->map[MAP_INDEX(j)] &= ~(1UL << MAP_BIT(j));
}
}
}
}
}
return 0;
}

View File

@@ -25,6 +25,9 @@
#define EXPORT_SYMBOL(x)
extern int ihk_mc_chk_page_address(unsigned long mem_addr);
extern unsigned long virt_to_phys(void *v);
/*
* red-black trees properties: http://en.wikipedia.org/wiki/Rbtree
*
@@ -429,6 +432,32 @@ struct rb_node *rb_first(const struct rb_root *root)
}
EXPORT_SYMBOL(rb_first);
struct rb_node *rb_first_safe(const struct rb_root *root)
{
struct rb_node *n;
unsigned long phys;
n = root->rb_node;
if (!n)
return NULL;
phys = virt_to_phys(n);
if (-1 == ihk_mc_chk_page_address(phys))
return NULL;
while (n->rb_left) {
n = n->rb_left;
if (!n)
return NULL;
phys = virt_to_phys(n);
if (-1 == ihk_mc_chk_page_address(phys))
return NULL;
}
return n;
}
EXPORT_SYMBOL(rb_first_safe);
struct rb_node *rb_last(const struct rb_root *root)
{
struct rb_node *n;
@@ -474,6 +503,58 @@ struct rb_node *rb_next(const struct rb_node *node)
}
EXPORT_SYMBOL(rb_next);
struct rb_node *rb_next_safe(const struct rb_node *node)
{
struct rb_node *parent;
struct rb_node *chk_node;
unsigned long phys;
if (RB_EMPTY_NODE(node))
return NULL;
/*
* If we have a right-hand child, go down and then left as far
* as we can.
*/
if (node->rb_right) {
node = node->rb_right;
if(!node)
return NULL;
chk_node = (struct rb_node *)node;
phys = virt_to_phys(chk_node);
if (-1 == ihk_mc_chk_page_address(phys))
return NULL;
while (node->rb_left) {
node=node->rb_left;
if(!node)
return NULL;
chk_node = (struct rb_node *)node;
phys = virt_to_phys(chk_node);
if (-1 == ihk_mc_chk_page_address(phys))
return NULL;
}
return (struct rb_node *)node;
}
/*
* No right-hand children. Everything down and left is smaller than us,
* so any 'next' node must be in the general direction of our parent.
* Go up the tree; any time the ancestor is a right-hand child of its
* parent, keep going up. First time it's a left-hand child of its
* parent, said parent is our 'next' node.
*/
while ((parent = rb_parent(node)) && node == parent->rb_right)
node = parent;
return parent;
}
EXPORT_SYMBOL(rb_next_safe);
struct rb_node *rb_prev(const struct rb_node *node)
{
struct rb_node *parent;