mirror of
https://github.com/crash-utility/crash
synced 2025-02-23 08:56:48 +00:00
Fix for the "tree -t radix", "irq", and "files -p" command options
in Linux 4.6 and later kernels due to upstream changes in the radix tree facility. Without the patch, the commands will fail with the message "radix trees do not exist or have changed their format". (hirofumi@mail.parknet.co.jp)
This commit is contained in:
parent
b5292a8b41
commit
880574406d
9
defs.h
9
defs.h
@ -1978,6 +1978,7 @@ struct offset_table { /* stash of commonly-used offsets */
|
||||
long blk_mq_ctx_rq_completed;
|
||||
long task_struct_stack;
|
||||
long tnt_mod;
|
||||
long radix_tree_node_shift;
|
||||
};
|
||||
|
||||
struct size_table { /* stash of commonly-used sizes */
|
||||
@ -2152,6 +2153,7 @@ struct array_table {
|
||||
int kmem_cache_node;
|
||||
int kmem_cache_cpu_slab;
|
||||
int rt_prio_array_queue;
|
||||
int height_to_maxnodes;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -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);
|
||||
|
259
filesys.c
259
filesys.c
@ -46,7 +46,6 @@ static int insmod_memory_driver_module(void);
|
||||
static int get_memory_driver_dev(dev_t *);
|
||||
static int memory_driver_init(void);
|
||||
static int create_memory_device(dev_t);
|
||||
static void *radix_tree_lookup(ulong, ulong, int);
|
||||
static int match_file_string(char *, char *, char *);
|
||||
static ulong get_root_vfsmount(char *);
|
||||
static void check_live_arch_mismatch(void);
|
||||
@ -2080,14 +2079,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 +2108,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");
|
||||
@ -3969,15 +3981,64 @@ cleanup_memory_driver(void)
|
||||
return errors ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
struct do_radix_tree_info {
|
||||
ulong maxcount;
|
||||
ulong count;
|
||||
void *data;
|
||||
};
|
||||
static void do_radix_tree_count(ulong node, ulong slot, const char *path,
|
||||
ulong index, void *private)
|
||||
{
|
||||
struct do_radix_tree_info *info = private;
|
||||
info->count++;
|
||||
}
|
||||
static void do_radix_tree_search(ulong node, ulong slot, const char *path,
|
||||
ulong index, void *private)
|
||||
{
|
||||
struct do_radix_tree_info *info = private;
|
||||
struct radix_tree_pair *rtp = info->data;
|
||||
|
||||
/*
|
||||
* Use the kernel's radix_tree_lookup() function as a template to dump
|
||||
* a radix tree's entries.
|
||||
*/
|
||||
if (rtp->index == index) {
|
||||
rtp->value = (void *)slot;
|
||||
info->count = 1;
|
||||
}
|
||||
}
|
||||
static void do_radix_tree_dump(ulong node, ulong slot, const char *path,
|
||||
ulong index, void *private)
|
||||
{
|
||||
struct do_radix_tree_info *info = private;
|
||||
fprintf(fp, "[%ld] %lx\n", index, slot);
|
||||
info->count++;
|
||||
}
|
||||
static void do_radix_tree_gather(ulong node, ulong slot, const char *path,
|
||||
ulong index, void *private)
|
||||
{
|
||||
struct do_radix_tree_info *info = private;
|
||||
struct radix_tree_pair *rtp = info->data;
|
||||
|
||||
ulong RADIX_TREE_MAP_SHIFT = UNINITIALIZED;
|
||||
ulong RADIX_TREE_MAP_SIZE = UNINITIALIZED;
|
||||
ulong RADIX_TREE_MAP_MASK = UNINITIALIZED;
|
||||
if (info->maxcount) {
|
||||
rtp[info->count].index = index;
|
||||
rtp[info->count].value = (void *)slot;
|
||||
|
||||
info->count++;
|
||||
info->maxcount--;
|
||||
}
|
||||
}
|
||||
static void do_radix_tree_dump_cb(ulong node, ulong slot, const char *path,
|
||||
ulong index, void *private)
|
||||
{
|
||||
struct do_radix_tree_info *info = private;
|
||||
struct radix_tree_pair *rtp = info->data;
|
||||
int (*cb)(ulong) = rtp->value;
|
||||
|
||||
/* Caller defined operation */
|
||||
if (!cb(slot)) {
|
||||
error(FATAL, "do_radix_tree: callback "
|
||||
"operation failed: entry: %ld item: %lx\n",
|
||||
info->count, slot);
|
||||
}
|
||||
info->count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* do_radix_tree argument usage:
|
||||
@ -4011,116 +4072,39 @@ ulong RADIX_TREE_MAP_MASK = UNINITIALIZED;
|
||||
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);
|
||||
struct do_radix_tree_info info = {
|
||||
.count = 0,
|
||||
.data = rtp,
|
||||
};
|
||||
struct radix_tree_ops ops = {
|
||||
.radix = 16,
|
||||
.private = &info,
|
||||
};
|
||||
|
||||
switch (flag)
|
||||
{
|
||||
case RADIX_TREE_COUNT:
|
||||
for (index = count = 0; index <= maxindex; index++) {
|
||||
if (radix_tree_lookup(root_rnode, index, height))
|
||||
count++;
|
||||
}
|
||||
ops.entry = do_radix_tree_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++;
|
||||
}
|
||||
/*
|
||||
* FIXME: do_radix_tree_traverse() traverses whole
|
||||
* radix tree, not binary search. So this search is
|
||||
* not efficient.
|
||||
*/
|
||||
ops.entry = do_radix_tree_search;
|
||||
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++;
|
||||
}
|
||||
}
|
||||
ops.entry = do_radix_tree_dump;
|
||||
break;
|
||||
|
||||
case RADIX_TREE_GATHER:
|
||||
if (!(maxcount = rtp->index))
|
||||
maxcount = (ulong)(-1); /* caller beware */
|
||||
if (!(info.maxcount = rtp->index))
|
||||
info.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++;
|
||||
}
|
||||
}
|
||||
ops.entry = do_radix_tree_gather;
|
||||
break;
|
||||
|
||||
case RADIX_TREE_DUMP_CB:
|
||||
@ -4128,62 +4112,15 @@ do_radix_tree(ulong root, int flag, struct radix_tree_pair *rtp)
|
||||
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++;
|
||||
}
|
||||
}
|
||||
ops.entry = do_radix_tree_dump_cb;
|
||||
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;
|
||||
do_radix_tree_traverse(root, 1, &ops);
|
||||
return info.count;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -8369,6 +8369,8 @@ builtin_array_length(char *s, int len, int *two_dim)
|
||||
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")) {
|
||||
@ -9769,6 +9771,8 @@ dump_offset_table(char *spec, ulong makestruct)
|
||||
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));
|
||||
@ -10404,6 +10408,8 @@ dump_offset_table(char *spec, ulong makestruct)
|
||||
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",
|
||||
|
297
tools.c
297
tools.c
@ -25,7 +25,6 @@ static void dealloc_hq_entry(struct hq_entry *);
|
||||
static void show_options(void);
|
||||
static void dump_struct_members(struct list_data *, int, ulong);
|
||||
static void rbtree_iteration(ulong, struct tree_data *, char *);
|
||||
static void rdtree_iteration(ulong, struct tree_data *, char *, ulong, uint);
|
||||
static void dump_struct_members_for_tree(struct tree_data *, int, ulong);
|
||||
|
||||
struct req_entry {
|
||||
@ -4091,159 +4090,227 @@ static ulong RADIX_TREE_MAP_SHIFT = UNINITIALIZED;
|
||||
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/%d", 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;
|
||||
unsigned char shift;
|
||||
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 (ARRAY_LENGTH(height_to_maxindex))
|
||||
max_height = ARRAY_LENGTH(height_to_maxindex);
|
||||
else
|
||||
max_height = ARRAY_LENGTH(height_to_maxnodes);
|
||||
}
|
||||
|
||||
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;
|
||||
height = 0;
|
||||
if (!is_root) {
|
||||
node_p = ptr;
|
||||
|
||||
if (td->flags & TREE_NODE_POINTER) {
|
||||
node_p = td->start;
|
||||
|
||||
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)) {
|
||||
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)) {
|
||||
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 %ld: ", 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);
|
||||
|
||||
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_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
rdtree_iteration(slot, td, pos, index, 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/%ld\n",
|
||||
path, index & RADIX_TREE_MAP_MASK);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user