[PATCH] Rewrite radix tree traverse
by OGAWA Hirofumi
Now, radix tree traverse is broken for kernel v4.9. Furthermore, there
are similar functions in filesys.c and tools.c.
So, to fix it, this rewrites radix tree traverse with callback based
function to support all current usages with one function. New API is
do_radix_tree_traverse() that controlled by "struct radix_tree_ops".
radix_tree_ops.entry - called for each radix tree entry (exclude internal)
radix_tree_ops.radix - when error happened, dump struct by this radix
radix_tree_ops.private - user pointer that passing to radix_tree_ops.entry
Changes lines are 275 insertions, 368 deletions.
---
defs.h | 19 +--
filesys.c | 266 +++++++------------------------------------------------
kernel.c | 59 ++++++++----
symbols.c | 6 +
tools.c | 292 +++++++++++++++++++++++++++++++++++++------------------------
5 files changed, 275 insertions(+), 367 deletions(-)
diff -puN tools.c~radix-tree-fix tools.c
--- crash-64/tools.c~radix-tree-fix 2017-01-30 10:25:04.511971087 +0900
+++ crash-64-hirofumi/tools.c 2017-01-31 23:51:40.051399318 +0900
@@ -4091,161 +4091,231 @@ static ulong RADIX_TREE_MAP_SHIFT = UNIN
static ulong RADIX_TREE_MAP_SIZE = UNINITIALIZED;
static ulong RADIX_TREE_MAP_MASK = UNINITIALIZED;
-int
-do_rdtree(struct tree_data *td)
+#define RADIX_TREE_ENTRY_MASK 3UL
+#define RADIX_TREE_INTERNAL_NODE 1UL
+
+static void do_radix_tree_iter(ulong node, uint height, char *path,
+ ulong index, struct radix_tree_ops *ops)
{
- long nlen;
+ uint off;
+
+ for (off = 0; off < RADIX_TREE_MAP_SIZE; off++) {
+ ulong slot;
+ ulong shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
+
+ readmem(node + OFFSET(radix_tree_node_slots) +
+ sizeof(void *) * off, KVADDR, &slot, sizeof(void *),
+ "radix_tree_node.slot[off]", FAULT_ON_ERROR);
+ if (!slot)
+ continue;
+
+ if (slot & RADIX_TREE_INTERNAL_NODE)
+ slot &= ~RADIX_TREE_INTERNAL_NODE;
+
+ if (height == 1)
+ ops->entry(node, slot, path, index | off, ops->private);
+ else {
+ ulong child_index = index | (off << shift);
+ char child_path[BUFSIZE];
+ sprintf(child_path, "%s/%ld", path, off);
+ do_radix_tree_iter(slot, height - 1,
+ child_path, child_index, ops);
+ }
+ }
+}
+
+int do_radix_tree_traverse(ulong ptr, int is_root, struct radix_tree_ops *ops)
+{
+ static ulong max_height = UNINITIALIZED;
ulong node_p;
- uint print_radix, height;
- char pos[BUFSIZE];
+ long nlen;
+ uint height, is_internal;
+ char path[BUFSIZE];
if (!VALID_STRUCT(radix_tree_root) || !VALID_STRUCT(radix_tree_node) ||
- !VALID_MEMBER(radix_tree_root_height) ||
- !VALID_MEMBER(radix_tree_root_rnode) ||
- !VALID_MEMBER(radix_tree_node_slots) ||
- !ARRAY_LENGTH(height_to_maxindex))
+ ((!VALID_MEMBER(radix_tree_root_height) ||
+ !VALID_MEMBER(radix_tree_root_rnode) ||
+ !VALID_MEMBER(radix_tree_node_slots) ||
+ !ARRAY_LENGTH(height_to_maxindex)) &&
+ (!VALID_MEMBER(radix_tree_root_rnode) ||
+ !VALID_MEMBER(radix_tree_node_shift) ||
+ !VALID_MEMBER(radix_tree_node_slots) ||
+ !ARRAY_LENGTH(height_to_maxnodes))))
error(FATAL, "radix trees do not exist or have changed "
"their format\n");
if (RADIX_TREE_MAP_SHIFT == UNINITIALIZED) {
if (!(nlen = MEMBER_SIZE("radix_tree_node", "slots")))
- error(FATAL, "cannot determine length of "
+ error(FATAL, "cannot determine length of "
"radix_tree_node.slots[] array\n");
nlen /= sizeof(void *);
RADIX_TREE_MAP_SHIFT = ffsl(nlen) - 1;
RADIX_TREE_MAP_SIZE = (1UL << RADIX_TREE_MAP_SHIFT);
RADIX_TREE_MAP_MASK = (RADIX_TREE_MAP_SIZE-1);
- }
- if (td->flags & TREE_STRUCT_RADIX_10)
- print_radix = 10;
- else if (td->flags & TREE_STRUCT_RADIX_16)
- print_radix = 16;
- else
- print_radix = 0;
+ if (ARRAY_LENGTH(height_to_maxindex))
+ max_height = ARRAY_LENGTH(height_to_maxindex);
+ else
+ max_height = ARRAY_LENGTH(height_to_maxnodes);
+ }
- if (td->flags & TREE_NODE_POINTER) {
- node_p = td->start;
+ height = 0;
+ if (!is_root) {
+ node_p = ptr;
- if (node_p & 1)
- node_p &= ~1;
+ if (node_p & RADIX_TREE_INTERNAL_NODE)
+ node_p &= ~RADIX_TREE_INTERNAL_NODE;
if (VALID_MEMBER(radix_tree_node_height)) {
readmem(node_p + OFFSET(radix_tree_node_height), KVADDR,
&height, sizeof(uint), "radix_tree_node height",
FAULT_ON_ERROR);
-
- if (height > ARRAY_LENGTH(height_to_maxindex)) {
- fprintf(fp, "radix_tree_node at %lx\n", node_p);
- dump_struct("radix_tree_node", node_p, print_radix);
- error(FATAL, "height %d is greater than "
- "height_to_maxindex[] index %ld\n",
- height, ARRAY_LENGTH(height_to_maxindex));
- }
- } else
+ } else if (VALID_MEMBER(radix_tree_node_shift)) {
+ unsigned char shift;
+ readmem(node_p + OFFSET(radix_tree_node_shift), KVADDR,
+ &shift, sizeof(shift), "radix_tree_node shift",
+ FAULT_ON_ERROR);
+ height = (shift / RADIX_TREE_MAP_SHIFT) + 1;
+ } else
error(FATAL, "-N option is not supported or applicable"
" for radix trees on this architecture or kernel\n");
+ if (height > max_height)
+ goto error_height;
} else {
- readmem(td->start + OFFSET(radix_tree_root_height), KVADDR, &height,
- sizeof(uint), "radix_tree_root height", FAULT_ON_ERROR);
-
- if (height > ARRAY_LENGTH(height_to_maxindex)) {
- fprintf(fp, "radix_tree_root at %lx\n", td->start);
- dump_struct("radix_tree_root", (ulong)td->start, print_radix);
- error(FATAL, "height %d is greater than "
- "height_to_maxindex[] index %ld\n",
- height, ARRAY_LENGTH(height_to_maxindex));
+ if (VALID_MEMBER(radix_tree_root_height)) {
+ readmem(ptr + OFFSET(radix_tree_root_height), KVADDR, &height,
+ sizeof(uint), "radix_tree_root height", FAULT_ON_ERROR);
}
- readmem(td->start + OFFSET(radix_tree_root_rnode), KVADDR, &node_p,
+ readmem(ptr + OFFSET(radix_tree_root_rnode), KVADDR, &node_p,
sizeof(void *), "radix_tree_root rnode", FAULT_ON_ERROR);
+ is_internal = (node_p & RADIX_TREE_INTERNAL_NODE);
+ if (node_p & RADIX_TREE_INTERNAL_NODE)
+ node_p &= ~RADIX_TREE_INTERNAL_NODE;
+
+ if (is_internal && VALID_MEMBER(radix_tree_node_shift)) {
+ unsigned char shift;
+ readmem(node_p + OFFSET(radix_tree_node_shift), KVADDR, &shift,
+ sizeof(shift), "radix_tree_node shift", FAULT_ON_ERROR);
+ height = (shift / RADIX_TREE_MAP_SHIFT) + 1;
+ }
+
+ if (height > max_height) {
+ node_p = ptr;
+ goto error_height;
+ }
}
- if (node_p & 1)
- node_p &= ~1;
+ if (CRASHDEBUG(1)) {
+ fprintf(fp, "radix_tree_node.slots[%ld]\n",
+ RADIX_TREE_MAP_SIZE);
+ fprintf(fp, "max_height %d: ", max_height);
+ fprintf(fp, "\n");
+ fprintf(fp, "pointer at %lx (is_root? %s):\n",
+ node_p, is_root ? "yes" : "no");
+ if (is_root)
+ dump_struct("radix_tree_root", ptr, RADIX(ops->radix));
+ else
+ dump_struct("radix_tree_node", node_p, RADIX(ops->radix));
+ }
- sprintf(pos, "root");
+ if (height == 0) {
+ strcpy(path, "direct");
+ ops->entry(node_p, node_p, path, 0, ops->private);
+ } else {
+ strcpy(path, "root");
+ do_radix_tree_iter(node_p, height, path, 0, ops);
+ }
- rdtree_iteration(node_p, td, pos, -1, height);
+ return 0;
- return td->count;
+error_height:
+ fprintf(fp, "radix_tree_node at %lx\n", node_p);
+ dump_struct("radix_tree_node", node_p, RADIX(ops->radix));
+ error(FATAL, "height %d is greater than "
+ "maximum radix tree height index %ld\n",
+ height, max_height);
+ return -1;
}
-void
-rdtree_iteration(ulong node_p, struct tree_data *td, char *ppos, ulong indexnum, uint height)
+static void do_rdtree_entry(ulong node, ulong slot, const char *path,
+ ulong index, void *private)
{
- ulong slot;
- int i, index;
- uint print_radix;
- char pos[BUFSIZE];
+ struct tree_data *td = private;
static struct req_entry **e = NULL;
+ uint print_radix;
+ int i;
- if (indexnum != -1)
- sprintf(pos, "%s/%ld", ppos, indexnum);
- else
- sprintf(pos, "%s", ppos);
+ if (!td->count && td->structname_args) {
+ /*
+ * Retrieve all members' info only once (count == 0)
+ * After last iteration all memory will be freed up
+ */
+ e = (struct req_entry **)GETBUF(sizeof(*e) * td->structname_args);
+ for (i = 0; i < td->structname_args; i++)
+ e[i] = fill_member_offsets(td->structname[i]);
+ }
- for (index = 0; index < RADIX_TREE_MAP_SIZE; index++) {
- readmem((ulong)node_p + OFFSET(radix_tree_node_slots) +
- sizeof(void *) * index, KVADDR, &slot, sizeof(void *),
- "radix_tree_node.slot[index]", FAULT_ON_ERROR);
- if (!slot)
- continue;
- if (height == 1) {
- if (!td->count && td->structname_args) {
- /*
- * Retrieve all members' info only once (count == 0)
- * After last iteration all memory will be freed up
- */
- e = (struct req_entry **)GETBUF(sizeof(*e) *
- td->structname_args);
- for (i = 0; i < td->structname_args; i++)
- e[i] = fill_member_offsets(td->structname[i]);
- }
+ if (hq_enter(slot))
+ td->count++;
+ else
+ error(FATAL,
+ "\nduplicate tree entry: radix_tree_node: %lx slots[%d]: %lx\n",
+ node, index, slot);
+
+ if (td->flags & VERBOSE)
+ fprintf(fp, "%lx\n", slot);
+
+ if (td->flags & TREE_POSITION_DISPLAY) {
+ fprintf(fp, " position: %s/%d\n",
+ path, index & RADIX_TREE_MAP_MASK);
+ }
- if (hq_enter(slot))
- td->count++;
- else
- error(FATAL,
- "\nduplicate tree entry: radix_tree_node: %lx slots[%d]: %lx\n",
- node_p, index, slot);
-
- if (td->flags & VERBOSE)
- fprintf(fp, "%lx\n",slot);
-
- if (td->flags & TREE_POSITION_DISPLAY)
- fprintf(fp, " position: %s/%d\n", pos, index);
-
- if (td->structname) {
- if (td->flags & TREE_STRUCT_RADIX_10)
- print_radix = 10;
- else if (td->flags & TREE_STRUCT_RADIX_16)
- print_radix = 16;
- else
- print_radix = 0;
-
- for (i = 0; i < td->structname_args; i++) {
- switch(count_chars(td->structname[i], '.'))
- {
- case 0:
- dump_struct(td->structname[i],
- slot, print_radix);
- break;
- default:
- if (td->flags & TREE_PARSE_MEMBER)
- dump_struct_members_for_tree(td, i,
- slot);
- else if (td->flags & TREE_READ_MEMBER)
- dump_struct_members_fast(e[i], print_radix, slot);
- break;
- }
- }
+ if (td->structname) {
+ if (td->flags & TREE_STRUCT_RADIX_10)
+ print_radix = 10;
+ else if (td->flags & TREE_STRUCT_RADIX_16)
+ print_radix = 16;
+ else
+ print_radix = 0;
+
+ for (i = 0; i < td->structname_args; i++) {
+ switch (count_chars(td->structname[i], '.')) {
+ case 0:
+ dump_struct(td->structname[i], slot, print_radix);
+ break;
+ default:
+ if (td->flags & TREE_PARSE_MEMBER)
+ dump_struct_members_for_tree(td, i, slot);
+ else if (td->flags & TREE_READ_MEMBER)
+ dump_struct_members_fast(e[i], print_radix, slot);
+ break;
}
- } else
- rdtree_iteration(slot, td, pos, index, height-1);
+ }
}
}
+int do_rdtree(struct tree_data *td)
+{
+ struct radix_tree_ops ops = {
+ .entry = do_rdtree_entry,
+ .private = td,
+ };
+ int is_root = !(td->flags & TREE_NODE_POINTER);
+ uint print_radix;
+
+ if (td->flags & TREE_STRUCT_RADIX_10)
+ ops.radix = 10;
+ else if (td->flags & TREE_STRUCT_RADIX_16)
+ ops.radix = 16;
+ else
+ ops.radix = 0;
+
+ do_radix_tree_traverse(td->start, is_root, &ops);
+
+ return 0;
+}
+
int
do_rbtree(struct tree_data *td)
{
diff -puN defs.h~radix-tree-fix defs.h
--- crash-64/defs.h~radix-tree-fix 2017-01-30 10:25:04.512971092 +0900
+++ crash-64-hirofumi/defs.h 2017-01-30 10:25:04.516971115 +0900
@@ -1879,6 +1879,7 @@ struct offset_table {
long super_block_s_fs_info;
long rq_timestamp;
long radix_tree_node_height;
+ long radix_tree_node_shift;
long rb_root_rb_node;
long rb_node_rb_left;
long rb_node_rb_right;
@@ -2149,6 +2150,7 @@ struct array_table {
int free_area_DIMENSION;
int prio_array_queue;
int height_to_maxindex;
+ int height_to_maxnodes;
int pid_hash;
int kmem_cache_node;
int kmem_cache_cpu_slab;
@@ -4803,6 +4805,13 @@ char *shift_string_right(char *, int);
int bracketed(char *, char *, int);
void backspace(int);
int do_list(struct list_data *);
+struct radix_tree_ops {
+ void (*entry)(ulong node, ulong slot, const char *path,
+ ulong index, void *private);
+ uint radix;
+ void *private;
+};
+int do_radix_tree_traverse(ulong ptr, int is_root, struct radix_tree_ops *ops);
int do_rdtree(struct tree_data *);
int do_rbtree(struct tree_data *);
int retrieve_list(ulong *, int);
@@ -5081,16 +5090,6 @@ char *fill_inode_cache(ulong);
void clear_inode_cache(void);
int monitor_memory(long *, long *, long *, long *);
int is_readable(char *);
-#define RADIX_TREE_COUNT (1)
-#define RADIX_TREE_SEARCH (2)
-#define RADIX_TREE_DUMP (3)
-#define RADIX_TREE_GATHER (4)
-#define RADIX_TREE_DUMP_CB (5)
-struct radix_tree_pair {
- ulong index;
- void *value;
-};
-ulong do_radix_tree(ulong, int, struct radix_tree_pair *);
int file_dump(ulong, ulong, ulong, int, int);
#define DUMP_FULL_NAME 0x1
#define DUMP_INODE_ONLY 0x2
diff -puN filesys.c~radix-tree-fix filesys.c
--- crash-64/filesys.c~radix-tree-fix 2017-01-30 10:25:04.513971098 +0900
+++ crash-64-hirofumi/filesys.c 2017-01-30 10:28:51.501266260 +0900
@@ -2080,14 +2080,25 @@ vfs_init(void)
if (!(ft->inode_cache = (char *)malloc(SIZE(inode)*INODE_CACHE)))
error(FATAL, "cannot malloc inode cache\n");
- if (symbol_exists("height_to_maxindex")) {
+ if (symbol_exists("height_to_maxindex") ||
+ symbol_exists("height_to_maxnodes")) {
+ int newver = symbol_exists("height_to_maxnodes");
int tmp ATTRIBUTE_UNUSED;
- if (LKCD_KERNTYPES())
- ARRAY_LENGTH_INIT_ALT(tmp, "height_to_maxindex",
- "radix_tree_preload.nodes", NULL, 0);
- else
- ARRAY_LENGTH_INIT(tmp, height_to_maxindex,
- "height_to_maxindex", NULL, 0);
+ if (!newver) {
+ if (LKCD_KERNTYPES())
+ ARRAY_LENGTH_INIT_ALT(tmp, "height_to_maxindex",
+ "radix_tree_preload.nodes", NULL, 0);
+ else
+ ARRAY_LENGTH_INIT(tmp, height_to_maxindex,
+ "height_to_maxindex", NULL, 0);
+ } else {
+ if (LKCD_KERNTYPES())
+ ARRAY_LENGTH_INIT_ALT(tmp, "height_to_maxnodes",
+ "radix_tree_preload.nodes", NULL, 0);
+ else
+ ARRAY_LENGTH_INIT(tmp, height_to_maxnodes,
+ "height_to_maxnodes", NULL, 0);
+ }
STRUCT_SIZE_INIT(radix_tree_root, "radix_tree_root");
STRUCT_SIZE_INIT(radix_tree_node, "radix_tree_node");
MEMBER_OFFSET_INIT(radix_tree_root_height,
@@ -2098,6 +2109,8 @@ vfs_init(void)
"radix_tree_node","slots");
MEMBER_OFFSET_INIT(radix_tree_node_height,
"radix_tree_node","height");
+ MEMBER_OFFSET_INIT(radix_tree_node_shift,
+ "radix_tree_node","shift");
}
MEMBER_OFFSET_INIT(rb_root_rb_node,
"rb_root","rb_node");
@@ -2190,12 +2203,25 @@ get_inode_nrpages(ulong i_mapping)
return nrpages;
}
+static void dump_inode_rdtree_entry(ulong node, ulong slot, const char *path,
+ ulong index, void *private)
+{
+ ulong *count = private;
+ (*count)++;
+ dump_inode_page(slot);
+}
+
static void
dump_inode_page_cache_info(ulong inode)
{
+ ulong count = 0;
+ struct radix_tree_ops ops = {
+ .entry = dump_inode_rdtree_entry,
+ .radix = 16,
+ .private = &count,
+ };
char *inode_buf;
- ulong i_mapping, nrpages, root_rnode, count;
- struct radix_tree_pair rtp;
+ ulong i_mapping, nrpages, root_rnode;
char header[BUFSIZE];
char buf1[BUFSIZE];
char buf2[BUFSIZE];
@@ -2220,10 +2246,7 @@ dump_inode_page_cache_info(ulong inode)
MKSTR(nrpages)));
root_rnode = i_mapping + OFFSET(address_space_page_tree);
- rtp.index = 0;
- rtp.value = (void *)&dump_inode_page;
-
- count = do_radix_tree(root_rnode, RADIX_TREE_DUMP_CB, &rtp);
+ do_radix_tree_traverse(root_rnode, 1, &ops);
if (count != nrpages)
error(INFO, "page_tree count: %ld nrpages: %ld\n",
@@ -3969,223 +3992,6 @@ cleanup_memory_driver(void)
return errors ? FALSE : TRUE;
}
-
-/*
- * Use the kernel's radix_tree_lookup() function as a template to dump
- * a radix tree's entries.
- */
-
-ulong RADIX_TREE_MAP_SHIFT = UNINITIALIZED;
-ulong RADIX_TREE_MAP_SIZE = UNINITIALIZED;
-ulong RADIX_TREE_MAP_MASK = UNINITIALIZED;
-
-/*
- * do_radix_tree argument usage:
- *
- * root: Address of a radix_tree_root structure
- *
- * flag: RADIX_TREE_COUNT - Return the number of entries in the tree.
- * RADIX_TREE_SEARCH - Search for an entry at rtp->index; if found,
- * store the entry in rtp->value and return a count of 1; otherwise
- * return a count of 0.
- * RADIX_TREE_DUMP - Dump all existing index/value pairs.
- * RADIX_TREE_GATHER - Store all existing index/value pairs in the
- * passed-in array of radix_tree_pair structs starting at rtp,
- * returning the count of entries stored; the caller can/should
- * limit the number of returned entries by putting the array size
- * (max count) in the rtp->index field of the first structure
- * in the passed-in array.
- * RADIX_TREE_DUMP_CB - Similar with RADIX_TREE_DUMP, but for each
- * radix tree entry, a user defined callback at rtp->value will
- * be invoked.
- *
- * rtp: Unused by RADIX_TREE_COUNT and RADIX_TREE_DUMP.
- * A pointer to a radix_tree_pair structure for RADIX_TREE_SEARCH.
- * A pointer to an array of radix_tree_pair structures for
- * RADIX_TREE_GATHER; the dimension (max count) of the array may
- * be stored in the index field of the first structure to avoid
- * any chance of an overrun.
- * For RADIX_TREE_DUMP_CB, the rtp->value must be initialized as a
- * callback function. The callback prototype must be: int (*)(ulong);
- */
-ulong
-do_radix_tree(ulong root, int flag, struct radix_tree_pair *rtp)
-{
- int i, ilen, height;
- long nlen;
- ulong index, maxindex, count, maxcount;
- long *height_to_maxindex;
- char *radix_tree_root_buf;
- struct radix_tree_pair *r;
- ulong root_rnode;
- void *ret;
- int (*cb)(ulong) = NULL;
-
- count = 0;
-
- if (!VALID_STRUCT(radix_tree_root) || !VALID_STRUCT(radix_tree_node) ||
- !VALID_MEMBER(radix_tree_root_height) ||
- !VALID_MEMBER(radix_tree_root_rnode) ||
- !VALID_MEMBER(radix_tree_node_slots) ||
- !ARRAY_LENGTH(height_to_maxindex))
- error(FATAL,
- "radix trees do not exist (or have changed their format)\n");
-
- if (RADIX_TREE_MAP_SHIFT == UNINITIALIZED) {
- if (!(nlen = MEMBER_SIZE("radix_tree_node", "slots")))
- error(FATAL, "cannot determine length of "
- "radix_tree_node.slots[] array\n");
- nlen /= sizeof(void *);
- RADIX_TREE_MAP_SHIFT = ffsl(nlen) - 1;
- RADIX_TREE_MAP_SIZE = (1UL << RADIX_TREE_MAP_SHIFT);
- RADIX_TREE_MAP_MASK = (RADIX_TREE_MAP_SIZE-1);
- }
-
- ilen = ARRAY_LENGTH(height_to_maxindex);
- height_to_maxindex = (long *)GETBUF(ilen * sizeof(long));
- readmem(symbol_value("height_to_maxindex"), KVADDR,
- height_to_maxindex, ilen*sizeof(long),
- "height_to_maxindex array", FAULT_ON_ERROR);
-
- if (CRASHDEBUG(1)) {
- fprintf(fp, "radix_tree_node.slots[%ld]\n",
- RADIX_TREE_MAP_SIZE);
- fprintf(fp, "height_to_maxindex[%d]: ", ilen);
- for (i = 0; i < ilen; i++)
- fprintf(fp, "%lu ", height_to_maxindex[i]);
- fprintf(fp, "\n");
- fprintf(fp, "radix_tree_root at %lx:\n", root);
- dump_struct("radix_tree_root", (ulong)root, RADIX(16));
- }
-
- radix_tree_root_buf = GETBUF(SIZE(radix_tree_root));
- readmem(root, KVADDR, radix_tree_root_buf, SIZE(radix_tree_root),
- "radix_tree_root", FAULT_ON_ERROR);
- height = UINT(radix_tree_root_buf + OFFSET(radix_tree_root_height));
-
- if ((height < 0) || (height > ilen)) {
- error(INFO, "height_to_maxindex[] index: %ld\n", ilen);
- fprintf(fp, "invalid height in radix_tree_root at %lx:\n", root);
- dump_struct("radix_tree_root", (ulong)root, RADIX(16));
- return 0;
- }
-
- maxindex = height_to_maxindex[height];
- FREEBUF(height_to_maxindex);
- FREEBUF(radix_tree_root_buf);
-
- root_rnode = root + OFFSET(radix_tree_root_rnode);
-
- switch (flag)
- {
- case RADIX_TREE_COUNT:
- for (index = count = 0; index <= maxindex; index++) {
- if (radix_tree_lookup(root_rnode, index, height))
- count++;
- }
- break;
-
- case RADIX_TREE_SEARCH:
- count = 0;
- if (rtp->index > maxindex)
- break;
-
- if ((ret = radix_tree_lookup(root_rnode, rtp->index, height))) {
- rtp->value = ret;
- count++;
- }
- break;
-
- case RADIX_TREE_DUMP:
- for (index = count = 0; index <= maxindex; index++) {
- if ((ret =
- radix_tree_lookup(root_rnode, index, height))) {
- fprintf(fp, "[%ld] %lx\n", index, (ulong)ret);
- count++;
- }
- }
- break;
-
- case RADIX_TREE_GATHER:
- if (!(maxcount = rtp->index))
- maxcount = (ulong)(-1); /* caller beware */
-
- for (index = count = 0, r = rtp; index <= maxindex; index++) {
- if ((ret =
- radix_tree_lookup(root_rnode, index, height))) {
- r->index = index;
- r->value = ret;
- count++;
- if (--maxcount <= 0)
- break;
- r++;
- }
- }
- break;
-
- case RADIX_TREE_DUMP_CB:
- if (rtp->value == NULL) {
- error(FATAL, "do_radix_tree: need set callback function");
- return -EINVAL;
- }
- cb = (int (*)(ulong))rtp->value;
- for (index = count = 0; index <= maxindex; index++) {
- if ((ret =
- radix_tree_lookup(root_rnode, index, height))) {
- /* Caller defined operation */
- if (!cb((ulong)ret)) {
- error(FATAL, "do_radix_tree: callback "
- "operation failed: entry: %ld item: %lx\n",
- count, (ulong)ret);
- }
- count++;
- }
- }
- break;
-
- default:
- error(FATAL, "do_radix_tree: invalid flag: %lx\n", flag);
- }
-
- return count;
-}
-
-static void *
-radix_tree_lookup(ulong root_rnode, ulong index, int height)
-{
- unsigned int shift;
- ulong rnode;
- ulong *slots;
-
- shift = (height-1) * RADIX_TREE_MAP_SHIFT;
-
- readmem(root_rnode, KVADDR, &rnode, sizeof(void *),
- "radix_tree_root rnode", FAULT_ON_ERROR);
-
- if (rnode & 1)
- rnode &= ~1;
-
- slots = (ulong *)GETBUF(sizeof(void *) * RADIX_TREE_MAP_SIZE);
-
- while (height > 0) {
- if (rnode == 0)
- break;
-
- readmem((ulong)rnode+OFFSET(radix_tree_node_slots), KVADDR,
- &slots[0], sizeof(void *) * RADIX_TREE_MAP_SIZE,
- "radix_tree_node.slots array", FAULT_ON_ERROR);
-
- rnode = slots[((index >> shift) & RADIX_TREE_MAP_MASK)];
-
- shift -= RADIX_TREE_MAP_SHIFT;
- height--;
- }
-
- FREEBUF(slots);
-
- return (void *)rnode;
-}
-
int
is_readable(char *filename)
{
diff -puN symbols.c~radix-tree-fix symbols.c
--- crash-64/symbols.c~radix-tree-fix 2017-01-30 10:25:04.513971098 +0900
+++ crash-64-hirofumi/symbols.c 2017-01-30 10:25:04.517971121 +0900
@@ -8369,6 +8369,8 @@ builtin_array_length(char *s, int len, i
lenptr = &array_table.prio_array_queue;
else if (STREQ(s, "height_to_maxindex"))
lenptr = &array_table.height_to_maxindex;
+ else if (STREQ(s, "height_to_maxnodes"))
+ lenptr = &array_table.height_to_maxnodes;
else if (STREQ(s, "pid_hash"))
lenptr = &array_table.pid_hash;
else if (STREQ(s, "free_area")) {
@@ -9771,6 +9773,8 @@ dump_offset_table(char *spec, ulong make
OFFSET(radix_tree_node_slots));
fprintf(fp, " radix_tree_node_height: %ld\n",
OFFSET(radix_tree_node_height));
+ fprintf(fp, " radix_tree_node_shift: %ld\n",
+ OFFSET(radix_tree_node_shift));
fprintf(fp, " rb_root_rb_node: %ld\n",
OFFSET(rb_root_rb_node));
@@ -10406,6 +10410,8 @@ dump_offset_table(char *spec, ulong make
get_array_length("prio_array.queue", NULL, SIZE(list_head)));
fprintf(fp, " height_to_maxindex: %d\n",
ARRAY_LENGTH(height_to_maxindex));
+ fprintf(fp, " height_to_maxnodes: %d\n",
+ ARRAY_LENGTH(height_to_maxnodes));
fprintf(fp, " pid_hash: %d\n",
ARRAY_LENGTH(pid_hash));
fprintf(fp, " kmem_cache_node: %d\n",
diff -puN kernel.c~radix-tree-fix kernel.c
--- crash-64/kernel.c~radix-tree-fix 2017-01-30 10:25:04.514971103 +0900
+++ crash-64-hirofumi/kernel.c 2017-01-30 10:25:04.518971126 +0900
@@ -6218,16 +6218,34 @@ cmd_irq(void)
}
}
+struct irq_desc_tree_info {
+ ulong count;
+ struct {
+ ulong node;
+ ulong index;
+ } *descs;
+ uint pos;
+};
+static void irq_desc_tree_entry(ulong node, ulong slot, const char *path,
+ ulong index, void *private)
+{
+ struct irq_desc_tree_info *info = private;
+ info->count++;
+ if (info->descs) {
+ info->descs[info->pos].node = slot;
+ info->descs[info->pos].index = index;
+ info->pos++;
+ }
+}
+
static ulong
get_irq_desc_addr(int irq)
{
int c;
- ulong cnt, addr, ptr;
+ ulong addr, ptr;
long len;
- struct radix_tree_pair *rtp;
addr = 0;
- rtp = NULL;
if (!VALID_STRUCT(irq_desc_t))
error(FATAL, "cannot determine size of irq_desc_t\n");
@@ -6247,31 +6265,40 @@ get_irq_desc_addr(int irq)
sizeof(void *), "irq_desc_ptrs entry",
FAULT_ON_ERROR);
} else if (kt->flags & IRQ_DESC_TREE) {
+ struct irq_desc_tree_info info;
+ struct radix_tree_ops ops = {
+ .entry = irq_desc_tree_entry,
+ .radix = 16,
+ .private = &info,
+ };
+
if (kt->highest_irq && (irq > kt->highest_irq))
return addr;
- cnt = do_radix_tree(symbol_value("irq_desc_tree"),
- RADIX_TREE_COUNT, NULL);
- len = sizeof(struct radix_tree_pair) * (cnt+1);
- rtp = (struct radix_tree_pair *)GETBUF(len);
- rtp[0].index = cnt;
- cnt = do_radix_tree(symbol_value("irq_desc_tree"),
- RADIX_TREE_GATHER, rtp);
+ info.count = 0;
+ info.descs = NULL;
+ do_radix_tree_traverse(symbol_value("irq_desc_tree"), 1, &ops);
+ len = sizeof(*info.descs) * (info.count + 1);
+ info.count = 0;
+ info.descs = (void *)GETBUF(len);
+ info.pos = 0;
+ do_radix_tree_traverse(symbol_value("irq_desc_tree"), 1, &ops);
if (kt->highest_irq == 0)
- kt->highest_irq = rtp[cnt-1].index;
+ kt->highest_irq = info.descs[info.count - 1].index;
- for (c = 0; c < cnt; c++) {
- if (rtp[c].index == irq) {
+ for (c = 0; c < info.count; c++) {
+ if (info.descs[c].index == irq) {
if (CRASHDEBUG(1))
fprintf(fp, "index: %ld value: %lx\n",
- rtp[c].index, (ulong)rtp[c].value);
- addr = (ulong)rtp[c].value;
+ info.descs[c].index,
+ info.descs[c].node);
+ addr = info.descs[c].node;
break;
}
}
- FREEBUF(rtp);
+ FREEBUF(info.descs);
} else {
error(FATAL,
"neither irq_desc, _irq_desc, irq_desc_ptrs "
_
--
OGAWA Hirofumi <hirofumi(a)mail.parknet.co.jp>
7 years, 9 months
[PATCH] Fix for "kmem <addr>" for kernels configured with CONFIG_SLUB and SLAB_RED_ZONE.
by OGAWA Hirofumi
If SLAB_RED_ZONE is enabled, slub adds guard zone of sizeof(void *)
onto head of slab page (red zone padding of left of object) on v4.6 or
later.
Without this fix, like following SUPERBLK and [allocate addr] has
difference.
crash> mount
MOUNT SUPERBLK TYPE DEVNAME DIRNAME
ffff88013ae58040 ffff88013ac35698 rootfs rootfs /
[...]
crash> kmem ffff88013ac35698
CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE
ffff88013ac05bc0 kmalloc-4096 4096 118 126 18 32k
SLAB MEMORY NODE TOTAL ALLOCATED FREE
ffffea0004eb0c00 ffff88013ac30000 0 7 7 0
FREE / [ALLOCATED]
[ffff88013ac35690]
[...]
---
defs.h | 1 +
memory.c | 8 ++++++++
symbols.c | 2 ++
3 files changed, 11 insertions(+)
diff -puN memory.c~slub-red_zone-fix memory.c
--- crash-64/memory.c~slub-red_zone-fix 2017-01-30 10:21:12.123644726 +0900
+++ crash-64-hirofumi/memory.c 2017-01-30 10:21:12.127644748 +0900
@@ -723,6 +723,7 @@ vm_init(void)
MEMBER_OFFSET_INIT(kmem_cache_node, "kmem_cache", "node");
MEMBER_OFFSET_INIT(kmem_cache_cpu_slab, "kmem_cache", "cpu_slab");
MEMBER_OFFSET_INIT(kmem_cache_list, "kmem_cache", "list");
+ MEMBER_OFFSET_INIT(kmem_cache_red_left_pad, "kmem_cache", "red_left_pad");
MEMBER_OFFSET_INIT(kmem_cache_name, "kmem_cache", "name");
MEMBER_OFFSET_INIT(kmem_cache_flags, "kmem_cache", "flags");
MEMBER_OFFSET_INIT(kmem_cache_cpu_freelist, "kmem_cache_cpu", "freelist");
@@ -18442,6 +18443,13 @@ do_slab_slub(struct meminfo *si, int ver
fprintf(fp, "< SLUB: free list END (%d found) >\n", i);
}
+ if (VALID_MEMBER(kmem_cache_red_left_pad)) {
+#define SLAB_RED_ZONE 0x00000400UL
+ ulong flags = ULONG(si->cache_buf + OFFSET(kmem_cache_flags));
+ ulong red_left_pad = ULONG(si->cache_buf + OFFSET(kmem_cache_red_left_pad));
+ if (flags & SLAB_RED_ZONE)
+ vaddr += red_left_pad;
+ }
for (p = vaddr; p < vaddr + objects * si->size; p += si->size) {
hq_open();
is_free = FALSE;
diff -puN defs.h~slub-red_zone-fix defs.h
--- crash-64/defs.h~slub-red_zone-fix 2017-01-30 10:21:12.124644731 +0900
+++ crash-64-hirofumi/defs.h 2017-02-01 00:11:33.445552457 +0900
@@ -1696,6 +1696,7 @@ struct offset_table {
long kmem_cache_align;
long kmem_cache_name;
long kmem_cache_list;
+ long kmem_cache_red_left_pad;
long kmem_cache_node;
long kmem_cache_cpu_slab;
long page_inuse;
diff -puN symbols.c~slub-red_zone-fix symbols.c
--- crash-64/symbols.c~slub-red_zone-fix 2017-01-30 10:21:12.124644731 +0900
+++ crash-64-hirofumi/symbols.c 2017-02-01 00:11:33.446552463 +0900
@@ -9330,6 +9330,8 @@ dump_offset_table(char *spec, ulong make
OFFSET(kmem_cache_name));
fprintf(fp, " kmem_cache_list: %ld\n",
OFFSET(kmem_cache_list));
+ fprintf(fp, " kmem_cache_red_left_pad: %ld\n",
+ OFFSET(kmem_cache_red_left_pad));
fprintf(fp, " kmem_cache_node: %ld\n",
OFFSET(kmem_cache_node));
fprintf(fp, " kmem_cache_cpu_slab: %ld\n",
_
--
OGAWA Hirofumi <hirofumi(a)mail.parknet.co.jp>
7 years, 10 months
[PATCH] ppc64: fix 'bt' command for vmcore captured with fadump.
by Hari Bathini
Without this patch, backtraces of active tasks maybe be of the form
"#0 [c0000000700b3a90] (null) at c0000000700b3b50 (unreliable)" for
kernel dumps captured with fadump. Trying to use ptregs saved for
active tasks before falling back to stack-search method. Also, getting
rid of warnings like "‘is_hugepage’ declared inline after being called".
Signed-off-by: Hari Bathini <hbathini(a)linux.vnet.ibm.com>
---
diskdump.c | 22 ++++++++++++++++++++++
ppc64.c | 58 +++++++++++++++++++++++++++++-----------------------------
2 files changed, 51 insertions(+), 29 deletions(-)
diff --git a/diskdump.c b/diskdump.c
index 48667ad..c080084 100644
--- a/diskdump.c
+++ b/diskdump.c
@@ -1368,6 +1368,28 @@ get_diskdump_regs_ppc64(struct bt_info *bt, ulong *eip, ulong *esp)
{
if ((bt->task == tt->panic_task) && DISKDUMP_VALID())
bt->machdep = &dd->sub_header->elf_regs;
+ else if (KDUMP_CMPRS_VALID() &&
+ (bt->task == tt->panic_task ||
+ (is_task_active(bt->task) && dd->num_prstatus_notes > 1))) {
+ int cpu;
+ Elf64_Nhdr *note;
+ size_t len;
+
+ cpu = bt->tc->processor;
+ if (dd->nt_prstatus_percpu[cpu] == NULL) {
+ if(CRASHDEBUG(1))
+ error(INFO,
+ "registers not collected for cpu %d\n",
+ cpu);
+ } else {
+ note = (Elf64_Nhdr *)
+ dd->nt_prstatus_percpu[cpu];
+ len = sizeof(Elf64_Nhdr);
+ len = roundup(len + note->n_namesz, 4);
+ bt->machdep = (void *)((char *)note + len +
+ MEMBER_OFFSET("elf_prstatus", "pr_reg"));
+ }
+ }
machdep->get_stack_frame(bt, eip, esp);
}
diff --git a/ppc64.c b/ppc64.c
index 8e93979..98ac559 100644
--- a/ppc64.c
+++ b/ppc64.c
@@ -65,19 +65,6 @@ static ulong pgd_page_vaddr_l4(ulong pgd);
static ulong pud_page_vaddr_l4(ulong pud);
static ulong pmd_page_vaddr_l4(ulong pmd);
-static inline uint get_ptetype(ulong pte)
-{
- uint pte_type = 0; /* 0: regular entry; 1: huge pte; 2: huge pd */
-
- if (is_hugepage(pte))
- pte_type = 1;
- else if (!(machdep->flags & RADIX_MMU) &&
- (PAGESIZE() != PPC64_64K_PAGE_SIZE) && is_hugepd(pte))
- pte_type = 2;
-
- return pte_type;
-}
-
static inline int is_hugepage(ulong pte)
{
if ((machdep->flags & BOOK3E) ||
@@ -128,6 +115,19 @@ static inline int is_hugepd(ulong pte)
}
}
+static inline uint get_ptetype(ulong pte)
+{
+ uint pte_type = 0; /* 0: regular entry; 1: huge pte; 2: huge pd */
+
+ if (is_hugepage(pte))
+ pte_type = 1;
+ else if (!(machdep->flags & RADIX_MMU) &&
+ (PAGESIZE() != PPC64_64K_PAGE_SIZE) && is_hugepd(pte))
+ pte_type = 2;
+
+ return pte_type;
+}
+
static inline ulong hugepage_dir(ulong pte)
{
if ((machdep->flags & BOOK3E) ||
@@ -2222,21 +2222,11 @@ ppc64_print_eframe(char *efrm_str, struct ppc64_pt_regs *regs,
* get SP and IP from the saved ptregs.
*/
static int
-ppc64_kdump_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp)
+ppc64_regs_stack_frame(struct bt_info *bt_in, struct ppc64_pt_regs *pt_regs,
+ ulong *nip, ulong *ksp)
{
- struct ppc64_pt_regs *pt_regs;
unsigned long unip;
- pt_regs = (struct ppc64_pt_regs *)bt_in->machdep;
- if (!pt_regs || !pt_regs->gpr[1]) {
- /*
- * Not collected regs. May be the corresponding CPU not
- * responded to an IPI.
- */
- fprintf(fp, "%0lx: GPR1 register value (SP) was not saved\n",
- bt_in->task);
- return FALSE;
- }
*ksp = pt_regs->gpr[1];
if (IS_KVADDR(*ksp)) {
readmem(*ksp+16, KVADDR, &unip, sizeof(ulong), "Regs NIP value",
@@ -2292,10 +2282,20 @@ ppc64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp)
struct syment *sp;
/*
- * For the kdump vmcore, Use SP and IP values that are saved in ptregs.
- */
- if (pc->flags & KDUMP)
- return ppc64_kdump_stack_frame(bt_in, nip, ksp);
+ * Use SP and IP values that are saved in ptregs.
+ */
+ pt_regs = (struct ppc64_pt_regs *)bt_in->machdep;
+ if (!pt_regs || !pt_regs->gpr[1]) {
+ /*
+ * Not collected regs. May be the corresponding CPU did not
+ * respond to an IPI.
+ */
+ if (CRASHDEBUG(1))
+ fprintf(fp, "%0lx: GPR1(SP) register value not saved\n",
+ bt_in->task);
+ } else
+ return ppc64_regs_stack_frame(bt_in, pt_regs, nip, ksp);
+
bt = &bt_local;
BCOPY(bt_in, bt, sizeof(struct bt_info));
7 years, 10 months
[PATCH v2] ppc64: fix 'bt' command for vmcore captured with fadump.
by Hari Bathini
Without this patch, backtraces of active tasks maybe be of the form
"#0 [c0000000700b3a90] (null) at c0000000700b3b50 (unreliable)" for
kernel dumps captured with fadump. This patch uses the ptregs saved
for active tasks before falling back to stack-search method.
Signed-off-by: Hari Bathini <hbathini(a)linux.vnet.ibm.com>
---
Changes from v1:
* Ensured that bt output doesn't change for active tasks for kdump and
panic task for kdump & fadump while fixing the output for active tasks
in case of fadump.
diskdump.c | 22 ++++++++++
ppc64.c | 134 +++++++++++++++++++++---------------------------------------
2 files changed, 68 insertions(+), 88 deletions(-)
diff --git a/diskdump.c b/diskdump.c
index 48667ad..c080084 100644
--- a/diskdump.c
+++ b/diskdump.c
@@ -1368,6 +1368,28 @@ get_diskdump_regs_ppc64(struct bt_info *bt, ulong *eip, ulong *esp)
{
if ((bt->task == tt->panic_task) && DISKDUMP_VALID())
bt->machdep = &dd->sub_header->elf_regs;
+ else if (KDUMP_CMPRS_VALID() &&
+ (bt->task == tt->panic_task ||
+ (is_task_active(bt->task) && dd->num_prstatus_notes > 1))) {
+ int cpu;
+ Elf64_Nhdr *note;
+ size_t len;
+
+ cpu = bt->tc->processor;
+ if (dd->nt_prstatus_percpu[cpu] == NULL) {
+ if(CRASHDEBUG(1))
+ error(INFO,
+ "registers not collected for cpu %d\n",
+ cpu);
+ } else {
+ note = (Elf64_Nhdr *)
+ dd->nt_prstatus_percpu[cpu];
+ len = sizeof(Elf64_Nhdr);
+ len = roundup(len + note->n_namesz, 4);
+ bt->machdep = (void *)((char *)note + len +
+ MEMBER_OFFSET("elf_prstatus", "pr_reg"));
+ }
+ }
machdep->get_stack_frame(bt, eip, esp);
}
diff --git a/ppc64.c b/ppc64.c
index 8e93979..970b2a1 100644
--- a/ppc64.c
+++ b/ppc64.c
@@ -65,19 +65,6 @@ static ulong pgd_page_vaddr_l4(ulong pgd);
static ulong pud_page_vaddr_l4(ulong pud);
static ulong pmd_page_vaddr_l4(ulong pmd);
-static inline uint get_ptetype(ulong pte)
-{
- uint pte_type = 0; /* 0: regular entry; 1: huge pte; 2: huge pd */
-
- if (is_hugepage(pte))
- pte_type = 1;
- else if (!(machdep->flags & RADIX_MMU) &&
- (PAGESIZE() != PPC64_64K_PAGE_SIZE) && is_hugepd(pte))
- pte_type = 2;
-
- return pte_type;
-}
-
static inline int is_hugepage(ulong pte)
{
if ((machdep->flags & BOOK3E) ||
@@ -128,6 +115,19 @@ static inline int is_hugepd(ulong pte)
}
}
+static inline uint get_ptetype(ulong pte)
+{
+ uint pte_type = 0; /* 0: regular entry; 1: huge pte; 2: huge pd */
+
+ if (is_hugepage(pte))
+ pte_type = 1;
+ else if (!(machdep->flags & RADIX_MMU) &&
+ (PAGESIZE() != PPC64_64K_PAGE_SIZE) && is_hugepd(pte))
+ pte_type = 2;
+
+ return pte_type;
+}
+
static inline ulong hugepage_dir(ulong pte)
{
if ((machdep->flags & BOOK3E) ||
@@ -2219,60 +2219,6 @@ ppc64_print_eframe(char *efrm_str, struct ppc64_pt_regs *regs,
}
/*
- * get SP and IP from the saved ptregs.
- */
-static int
-ppc64_kdump_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp)
-{
- struct ppc64_pt_regs *pt_regs;
- unsigned long unip;
-
- pt_regs = (struct ppc64_pt_regs *)bt_in->machdep;
- if (!pt_regs || !pt_regs->gpr[1]) {
- /*
- * Not collected regs. May be the corresponding CPU not
- * responded to an IPI.
- */
- fprintf(fp, "%0lx: GPR1 register value (SP) was not saved\n",
- bt_in->task);
- return FALSE;
- }
- *ksp = pt_regs->gpr[1];
- if (IS_KVADDR(*ksp)) {
- readmem(*ksp+16, KVADDR, &unip, sizeof(ulong), "Regs NIP value",
- FAULT_ON_ERROR);
- *nip = unip;
- } else {
- if (IN_TASK_VMA(bt_in->task, *ksp))
- fprintf(fp, "%0lx: Task is running in user space\n",
- bt_in->task);
- else
- fprintf(fp, "%0lx: Invalid Stack Pointer %0lx\n",
- bt_in->task, *ksp);
- *nip = pt_regs->nip;
- }
-
- if (bt_in->flags &&
- ((BT_TEXT_SYMBOLS|BT_TEXT_SYMBOLS_PRINT|BT_TEXT_SYMBOLS_NOPRINT)))
- return TRUE;
-
- /*
- * Print the collected regs for the active task
- */
- ppc64_print_regs(pt_regs);
- if (!IS_KVADDR(*ksp))
- return FALSE;
-
- fprintf(fp, " NIP [%016lx] %s\n", pt_regs->nip,
- closest_symbol(pt_regs->nip));
- if (unip != pt_regs->link)
- fprintf(fp, " LR [%016lx] %s\n", pt_regs->link,
- closest_symbol(pt_regs->link));
-
- return TRUE;
-}
-
-/*
* Get the starting point for the active cpus in a diskdump/netdump.
*/
static int
@@ -2291,25 +2237,14 @@ ppc64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp)
struct ppc64_pt_regs *pt_regs;
struct syment *sp;
- /*
- * For the kdump vmcore, Use SP and IP values that are saved in ptregs.
- */
- if (pc->flags & KDUMP)
- return ppc64_kdump_stack_frame(bt_in, nip, ksp);
-
bt = &bt_local;
BCOPY(bt_in, bt, sizeof(struct bt_info));
ms = machdep->machspec;
- ur_nip = ur_ksp = 0;
-
- panic_task = tt->panic_task == bt->task ? TRUE : FALSE;
+ panic_task = tt->panic_task == bt->task ? TRUE : FALSE;
check_hardirq = check_softirq = tt->flags & IRQSTACKS ? TRUE : FALSE;
- if (panic_task && bt->machdep) {
- pt_regs = (struct ppc64_pt_regs *)bt->machdep;
- ur_nip = pt_regs->nip;
- ur_ksp = pt_regs->gpr[1];
- } else if (bt->task != tt->panic_task) {
+
+ if (bt->task != tt->panic_task) {
char cpu_frozen = FALSE;
/*
* Determine whether the CPU responded to an IPI.
@@ -2428,15 +2363,38 @@ retry:
alter_stackbuf(bt);
check_intrstack = FALSE;
goto retry;
- }
+ }
+
/*
- * We didn't find what we were looking for, so just use what was
- * passed in the ELF header.
+ * We didn't find what we were looking for, so try to use
+ * the SP and IP values saved in ptregs.
*/
- if (ur_nip && ur_ksp) {
- *nip = ur_nip;
- *ksp = ur_ksp;
- return TRUE;
+ pt_regs = (struct ppc64_pt_regs *)bt_in->machdep;
+ if (!pt_regs || !pt_regs->gpr[1]) {
+ /*
+ * Not collected regs. May be the corresponding CPU did not
+ * respond to an IPI.
+ */
+ if (CRASHDEBUG(1))
+ fprintf(fp, "%0lx: GPR1(SP) register value not saved\n",
+ bt_in->task);
+ } else {
+ *ksp = pt_regs->gpr[1];
+ if (IS_KVADDR(*ksp)) {
+ readmem(*ksp+16, KVADDR, nip, sizeof(ulong),
+ "Regs NIP value", FAULT_ON_ERROR);
+ return TRUE;
+ } else {
+ if (IN_TASK_VMA(bt_in->task, *ksp))
+ fprintf(fp, "%0lx: Task is running in user space\n",
+ bt_in->task);
+ else
+ fprintf(fp, "%0lx: Invalid Stack Pointer %0lx\n",
+ bt_in->task, *ksp);
+ *nip = pt_regs->nip;
+ ppc64_print_regs(pt_regs);
+ return FALSE;
+ }
}
console("ppc64_get_dumpfile_stack_frame: cannot find SP for panic task\n");
7 years, 10 months
[PATCH] correct a mistake of reading kimage_voffset
by zhizhou.zh@gmail.com
From: Zhizhou Zhang <zhizhouzhang(a)asrmicro.com>
kernel defines VMCOREINFO_NUMBER as follow. so we should use atol rather than
htol to get value of kimage_voffset.
#define VMCOREINFO_NUMBER(name) \
vmcoreinfo_append_str("NUMBER(%s)=%ld\n", #name, (long)name)
Signed-off-by: Zhizhou Zhang <zhizhouzhang(a)asrmicro.com>
---
arm64.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arm64.c b/arm64.c
index 6eaf96d..f79f0a5 100644
--- a/arm64.c
+++ b/arm64.c
@@ -119,7 +119,7 @@ arm64_init(int when)
if (!ms->kimage_voffset &&
(string = pc->read_vmcoreinfo("NUMBER(kimage_voffset)"))) {
- ms->kimage_voffset = htol(string, QUIET, NULL);
+ ms->kimage_voffset = atol(string);
free(string);
}
--
1.9.1
7 years, 10 months
[PATCH V2 0/2] Fix for global and module taint flags changes in kernel
by Pratyush Anand
v4.10-rc1 has simplified global and module taint flags handling. This
patchset caters corresponding modifications for crash utility.
v1->v2:
- changed as per comments from Dave Andersan for v1 patches.
- unnecessary checks removed
- also fixes for module taint flags changes now
Pratyush Anand (2):
Fix show_kernel_taints() for kernel version > 4.9
Fix show_module_taint() for kernel version > 4.9
defs.h | 2 +
kernel.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
symbols.c | 3 ++
3 files changed, 161 insertions(+)
--
2.7.4
7 years, 10 months
[PATCH] arm64: fix a backtracing for CONFIG_THREAD_INFO_IN_TASK kernel
by AKASHI Takahiro
Since v4.10, arm64 kernel supports CONFIG_THREAD_INFO_IN_TASK.
This means that bt->tc->thread_info is no longer equal to the base
address of the task's stack.
This patch fixes this issue.
Signed-off-by: AKASHI Takahiro <takahiro.akashi(a)linaro.org>
---
arm64.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/arm64.c b/arm64.c
index e4d497e..2b17081 100644
--- a/arm64.c
+++ b/arm64.c
@@ -2447,7 +2447,7 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
(*ptr < ms->crash_kexec_end) &&
INSTACK(*(ptr - 1), bt)) {
bt->bptr = ((ulong)(ptr - 1) - (ulong)base)
- + bt->tc->thread_info;
+ + task_to_stackbase(bt->tc->task);
if (CRASHDEBUG(1))
fprintf(fp, "%lx: %lx (crash_kexec)\n", bt->bptr, *ptr);
return TRUE;
@@ -2456,20 +2456,22 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
(*ptr < ms->crash_save_cpu_end) &&
INSTACK(*(ptr - 1), bt)) {
bt->bptr = ((ulong)(ptr - 1) - (ulong)base)
- + bt->tc->thread_info;
+ + task_to_stackbase(bt->tc->task);
if (CRASHDEBUG(1))
fprintf(fp, "%lx: %lx (crash_save_cpu)\n", bt->bptr, *ptr);
return TRUE;
}
} else {
if ((*ptr >= ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
- bt->bptr = ((ulong)ptr - (ulong)base) + bt->tc->thread_info;
+ bt->bptr = ((ulong)ptr - (ulong)base)
+ + task_to_stackbase(bt->tc->task);
if (CRASHDEBUG(1))
fprintf(fp, "%lx: %lx (crash_kexec)\n", bt->bptr, *ptr);
return TRUE;
}
if ((*ptr >= ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
- bt->bptr = ((ulong)ptr - (ulong)base) + bt->tc->thread_info;
+ bt->bptr = ((ulong)ptr - (ulong)base)
+ + task_to_stackbase(bt->tc->task);
if (CRASHDEBUG(1))
fprintf(fp, "%lx: %lx (crash_save_cpu)\n", bt->bptr, *ptr);
return TRUE;
--
2.11.0
7 years, 10 months
[PATCH] Fix show_kernel_taints() for kernel version > 4.9
by Pratyush Anand
Following kernel commit removed "struct tnt".
commit 7fd8329ba502ef76dd91db561c7aed696b2c7720
Author: Petr Mladek <pmladek(a)suse.com>
Date: Wed Sep 21 13:47:22 2016 +0200
taint/module: Clean up global and module taint flags handling
Now "struct taint_flag" has tainted character information.
Without this patch we see following error on a kernel version v4.10-rc1.
crash: invalid structure size: tnt
FILE: kernel.c LINE: 10459 FUNCTION: show_kernel_taints()
[./crash] error trace: 4cb49c => 4c7cd0 => 50f4e0 => 50f464
50f464: SIZE_verify.part.29+72
50f4e0: store_module_kallsyms_v1.part.30+0
4c7cd0: show_kernel_taints+352
4cb49c: is_livepatch+44
Signed-off-by: Pratyush Anand <panand(a)redhat.com>
---
defs.h | 1 +
kernel.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 67 insertions(+)
diff --git a/defs.h b/defs.h
index 31a4dc490ed4..0c25d5aa4afd 100644
--- a/defs.h
+++ b/defs.h
@@ -2117,6 +2117,7 @@ struct size_table { /* stash of commonly-used sizes */
long hrtimer_clock_base;
long hrtimer_base;
long tnt;
+ long taint_flag;
long trace_print_flags;
long task_struct_flags;
long timer_base;
diff --git a/kernel.c b/kernel.c
index bdd0d05eed97..31917176e8c9 100644
--- a/kernel.c
+++ b/kernel.c
@@ -10416,6 +10416,67 @@ dump_variable_length_record(void)
}
static void
+show_kernel_taints_v4_10(char *buf, int verbose)
+{
+ int i, bx;
+ char tnt_true, tnt_false;
+ int tnts_len;
+ ulong tnts_addr;
+ ulong tainted_mask, *tainted_mask_ptr;
+ int tainted;
+ struct syment *sp;
+
+ if (!VALID_STRUCT(taint_flag)) {
+ STRUCT_SIZE_INIT(taint_flag, "taint_flag");
+ MEMBER_OFFSET_INIT(tnt_true, "taint_flag", "true");
+ MEMBER_OFFSET_INIT(tnt_false, "taint_flag", "false");
+ }
+
+ if (VALID_STRUCT(taint_flag) && (sp = symbol_search("taint_flags"))) {
+ tnts_len = get_array_length("taint_flags", NULL, 0);
+ tnts_addr = sp->value;
+ } else
+ tnts_addr = tnts_len = 0;
+
+ bx = 0;
+ buf[0] = '\0';
+
+ tainted_mask = tainted = 0;
+
+ if (kernel_symbol_exists("tainted_mask")) {
+ get_symbol_data("tainted_mask", sizeof(ulong), &tainted_mask);
+ tainted_mask_ptr = &tainted_mask;
+ } else if (kernel_symbol_exists("tainted")) {
+ get_symbol_data("tainted", sizeof(int), &tainted);
+ if (verbose)
+ fprintf(fp, "TAINTED: %x\n", tainted);
+ return;
+ } else if (verbose)
+ option_not_supported('t');
+
+ for (i = 0; i < (tnts_len * SIZE(taint_flag)); i += SIZE(taint_flag)) {
+ if (NUM_IN_BITMAP(tainted_mask_ptr, i)) {
+ readmem((tnts_addr + i) + OFFSET(tnt_true),
+ KVADDR, &tnt_true, sizeof(char),
+ "tnt true", FAULT_ON_ERROR);
+ buf[bx++] = tnt_true;
+ } else {
+ readmem((tnts_addr + i) + OFFSET(tnt_false),
+ KVADDR, &tnt_false, sizeof(char),
+ "tnt false", FAULT_ON_ERROR);
+ if (tnt_false != ' ' && tnt_false != '-' &&
+ tnt_false != 'G')
+ buf[bx++] = tnt_false;
+ }
+ }
+
+ buf[bx++] = '\0';
+
+ if (verbose)
+ fprintf(fp, "TAINTED_MASK: %lx %s\n", tainted_mask, buf);
+}
+
+static void
show_kernel_taints(char *buf, int verbose)
{
int i, bx;
@@ -10427,6 +10488,11 @@ show_kernel_taints(char *buf, int verbose)
int tainted;
struct syment *sp;
+ if (THIS_KERNEL_VERSION > LINUX(4,9,0)) {
+ show_kernel_taints_v4_10(buf, verbose);
+ return;
+ }
+
if (!VALID_STRUCT(tnt)) {
STRUCT_SIZE_INIT(tnt, "tnt");
MEMBER_OFFSET_INIT(tnt_bit, "tnt", "bit");
--
2.7.4
7 years, 10 months