First phase of support for the XArray facility. The added support is

similar to that of radix trees, but introduces completely separate
functions, structures and #defines.  None of the applicable radix
tree users in the crash utility have been switched over, so this
phase does not introduce any functional changes.
(asmadeus@codewreck.org, anderson@redhat.com)
This commit is contained in:
Dave Anderson 2018-11-12 15:59:30 -05:00
parent f701ecad0f
commit 3b05002917
5 changed files with 302 additions and 2 deletions

25
defs.h
View File

@ -2058,6 +2058,9 @@ struct offset_table { /* stash of commonly-used offsets */
long bus_type_p;
long device_private_device;
long device_private_knode_bus;
long xarray_xa_head;
long xa_node_slots;
long xa_node_shift;
};
struct size_table { /* stash of commonly-used sizes */
@ -2213,6 +2216,8 @@ struct size_table { /* stash of commonly-used sizes */
long bpf_prog_aux;
long bpf_map;
long bpf_insn;
long xarray;
long xa_node;
};
struct array_table {
@ -4988,6 +4993,13 @@ struct radix_tree_ops {
void *private;
};
int do_radix_tree_traverse(ulong ptr, int is_root, struct radix_tree_ops *ops);
struct xarray_ops {
void (*entry)(ulong node, ulong slot, const char *path,
ulong index, void *private);
uint radix;
void *private;
};
int do_xarray_traverse(ulong ptr, int is_root, struct xarray_ops *ops);
int do_rdtree(struct tree_data *);
int do_rbtree(struct tree_data *);
int retrieve_list(ulong *, int);
@ -5285,6 +5297,19 @@ ulong do_radix_tree(ulong, int, struct radix_tree_pair *);
#define RADIX_TREE_ENTRY_MASK 3UL
#define RADIX_TREE_EXCEPTIONAL_ENTRY 2
#define XARRAY_COUNT (1)
#define XARRAY_SEARCH (2)
#define XARRAY_DUMP (3)
#define XARRAY_GATHER (4)
#define XARRAY_DUMP_CB (5)
struct xarray_pair {
ulong index;
void *value;
};
ulong do_xarray(ulong, int, struct xarray_pair *);
#define XARRAY_TAG_MASK (3UL)
#define XARRAY_TAG_INTERNAL (2UL)
int file_dump(ulong, ulong, ulong, int, int);
#define DUMP_FULL_NAME 0x1
#define DUMP_INODE_ONLY 0x2

143
filesys.c
View File

@ -4129,6 +4129,149 @@ do_radix_tree(ulong root, int flag, struct radix_tree_pair *rtp)
return info.count;
}
struct do_xarray_info {
ulong maxcount;
ulong count;
void *data;
};
static void do_xarray_count(ulong node, ulong slot, const char *path,
ulong index, void *private)
{
struct do_xarray_info *info = private;
info->count++;
}
static void do_xarray_search(ulong node, ulong slot, const char *path,
ulong index, void *private)
{
struct do_xarray_info *info = private;
struct xarray_pair *xp = info->data;
if (xp->index == index) {
xp->value = (void *)slot;
info->count = 1;
}
}
static void do_xarray_dump(ulong node, ulong slot, const char *path,
ulong index, void *private)
{
struct do_xarray_info *info = private;
fprintf(fp, "[%ld] %lx\n", index, slot);
info->count++;
}
static void do_xarray_gather(ulong node, ulong slot, const char *path,
ulong index, void *private)
{
struct do_xarray_info *info = private;
struct xarray_pair *xp = info->data;
if (info->maxcount) {
xp[info->count].index = index;
xp[info->count].value = (void *)slot;
info->count++;
info->maxcount--;
}
}
static void do_xarray_dump_cb(ulong node, ulong slot, const char *path,
ulong index, void *private)
{
struct do_xarray_info *info = private;
struct xarray_pair *xp = info->data;
int (*cb)(ulong) = xp->value;
/* Caller defined operation */
if (!cb(slot)) {
if (slot & XARRAY_TAG_MASK) {
if (CRASHDEBUG(0))
error(INFO, "entry has XARRAY_TAG_MASK bits set: %lx\n", slot);
return;
}
error(FATAL, "do_xarray: callback "
"operation failed: entry: %ld item: %lx\n",
info->count, slot);
}
info->count++;
}
/*
* do_xarray argument usage:
*
* root: Address of a xarray structure
*
* flag: XARRAY_COUNT - Return the number of entries in the tree.
* XARRAY_SEARCH - Search for an entry at xp->index; if found,
* store the entry in xp->value and return a count of 1; otherwise
* return a count of 0.
* XARRY_DUMP - Dump all existing index/value pairs.
* XARRAY_GATHER - Store all existing index/value pairs in the
* passed-in array of xarray_pair structs starting at xp,
* 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 xp->index field of the first structure
* in the passed-in array.
* XARRAY_DUMP_CB - Similar with XARRAY_DUMP, but for each
* xarray entry, a user defined callback at xp->value will
* be invoked.
*
* xp: Unused by XARRAY_COUNT and XARRAY_DUMP.
* A pointer to a xarray_pair structure for XARRAY_SEARCH.
* A pointer to an array of xarray_pair structures for
* XARRAY_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 XARRAY_DUMP_CB, the rtp->value must be initialized as a
* callback function. The callback prototype must be: int (*)(ulong);
*/
ulong
do_xarray(ulong root, int flag, struct xarray_pair *xp)
{
struct do_xarray_info info = {
.count = 0,
.data = xp,
};
struct xarray_ops ops = {
.radix = 16,
.private = &info,
};
switch (flag)
{
case XARRAY_COUNT:
ops.entry = do_xarray_count;
break;
case XARRAY_SEARCH:
ops.entry = do_xarray_search;
break;
case XARRAY_DUMP:
ops.entry = do_xarray_dump;
break;
case XARRAY_GATHER:
if (!(info.maxcount = xp->index))
info.maxcount = (ulong)(-1); /* caller beware */
ops.entry = do_xarray_gather;
break;
case XARRAY_DUMP_CB:
if (xp->value == NULL) {
error(FATAL, "do_xarray: no callback function specified");
return -EINVAL;
}
ops.entry = do_xarray_dump_cb;
break;
default:
error(FATAL, "do_xarray: invalid flag: %lx\n", flag);
}
do_xarray_traverse(root, 1, &ops);
return info.count;
}
int
is_readable(char *filename)
{

View File

@ -10374,6 +10374,13 @@ dump_offset_table(char *spec, ulong makestruct)
fprintf(fp, " user_struct_uid: %ld\n",
OFFSET(user_struct_uid));
fprintf(fp, " xarray_xa_head: %ld\n",
OFFSET(xarray_xa_head));
fprintf(fp, " xa_node_slots: %ld\n",
OFFSET(xa_node_slots));
fprintf(fp, " xa_node_shift: %ld\n",
OFFSET(xa_node_shift));
fprintf(fp, "\n size_table:\n");
fprintf(fp, " page: %ld\n", SIZE(page));
fprintf(fp, " page_flags: %ld\n", SIZE(page_flags));
@ -10627,6 +10634,11 @@ dump_offset_table(char *spec, ulong makestruct)
SIZE(bpf_map));
fprintf(fp, " bpf_insn: %ld\n",
SIZE(bpf_insn));
fprintf(fp, " xarray: %ld\n",
SIZE(xarray));
fprintf(fp, " xa_node: %ld\n",
SIZE(xa_node));
fprintf(fp, "\n array_table:\n");
/*

6
task.c
View File

@ -485,6 +485,12 @@ task_init(void)
"radix_tree_node","height");
MEMBER_OFFSET_INIT(radix_tree_node_shift,
"radix_tree_node","shift");
} else {
STRUCT_SIZE_INIT(xarray, "xarray");
STRUCT_SIZE_INIT(xa_node, "xa_node");
MEMBER_OFFSET_INIT(xarray_xa_head, "xarray","xa_head");
MEMBER_OFFSET_INIT(xa_node_slots, "xa_node","slots");
MEMBER_OFFSET_INIT(xa_node_shift, "xa_node","shift");
}
if (symbol_exists("pidhash") && symbol_exists("pid_hash") &&

118
tools.c
View File

@ -1,8 +1,8 @@
/* tools.c - core analysis suite
*
* Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
* Copyright (C) 2002-2017 David Anderson
* Copyright (C) 2002-2017 Red Hat, Inc. All rights reserved.
* Copyright (C) 2002-2018 David Anderson
* Copyright (C) 2002-2018 Red Hat, Inc. All rights reserved.
*
* 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
@ -4564,6 +4564,120 @@ error_height:
return -1;
}
static ulong XA_CHUNK_SHIFT = UNINITIALIZED;
static ulong XA_CHUNK_SIZE = UNINITIALIZED;
static ulong XA_CHUNK_MASK = UNINITIALIZED;
static void
do_xarray_iter(ulong node, uint height, char *path,
ulong index, struct xarray_ops *ops)
{
uint off;
if (!hq_enter(node))
error(FATAL,
"\nduplicate tree node: %lx\n", node);
for (off = 0; off < XA_CHUNK_SIZE; off++) {
ulong slot;
ulong shift = (height - 1) * XA_CHUNK_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 & XARRAY_TAG_MASK) == XARRAY_TAG_INTERNAL)
slot &= ~XARRAY_TAG_INTERNAL;
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_xarray_iter(slot, height - 1,
child_path, child_index, ops);
}
}
}
int
do_xarray_traverse(ulong ptr, int is_root, struct xarray_ops *ops)
{
ulong node_p;
long nlen;
uint height, is_internal;
unsigned char shift;
char path[BUFSIZE];
if (!VALID_STRUCT(xarray) || !VALID_STRUCT(xa_node) ||
!VALID_MEMBER(xarray_xa_head) ||
!VALID_MEMBER(xa_node_slots) ||
!VALID_MEMBER(xa_node_shift))
error(FATAL,
"xarray facility does not exist or has changed its format\n");
if (XA_CHUNK_SHIFT == UNINITIALIZED) {
if ((nlen = MEMBER_SIZE("xa_node", "slots")) <= 0)
error(FATAL, "cannot determine length of xa_node.slots[] array\n");
nlen /= sizeof(void *);
XA_CHUNK_SHIFT = ffsl(nlen) - 1;
XA_CHUNK_SIZE = (1UL << XA_CHUNK_SHIFT);
XA_CHUNK_MASK = (XA_CHUNK_SIZE-1);
}
height = 0;
if (!is_root) {
node_p = ptr;
if ((node_p & XARRAY_TAG_MASK) == XARRAY_TAG_INTERNAL)
node_p &= ~XARRAY_TAG_MASK;
if (VALID_MEMBER(xa_node_shift)) {
readmem(node_p + OFFSET(xa_node_shift), KVADDR,
&shift, sizeof(shift), "xa_node shift",
FAULT_ON_ERROR);
height = (shift / XA_CHUNK_SHIFT) + 1;
} else
error(FATAL, "-N option is not supported or applicable"
" for xarrays on this architecture or kernel\n");
} else {
readmem(ptr + OFFSET(xarray_xa_head), KVADDR, &node_p,
sizeof(void *), "xarray xa_head", FAULT_ON_ERROR);
is_internal = ((node_p & XARRAY_TAG_MASK) == XARRAY_TAG_INTERNAL);
if (node_p & XARRAY_TAG_MASK)
node_p &= ~XARRAY_TAG_MASK;
if (is_internal && VALID_MEMBER(xa_node_shift)) {
readmem(node_p + OFFSET(xa_node_shift), KVADDR, &shift,
sizeof(shift), "xa_node shift", FAULT_ON_ERROR);
height = (shift / XA_CHUNK_SHIFT) + 1;
}
}
if (CRASHDEBUG(1)) {
fprintf(fp, "xa_node.slots[%ld]\n", XA_CHUNK_SIZE);
fprintf(fp, "pointer at %lx (is_root? %s):\n",
node_p, is_root ? "yes" : "no");
if (is_root)
dump_struct("xarray", ptr, RADIX(ops->radix));
else
dump_struct("xa_node", node_p, RADIX(ops->radix));
}
if (height == 0) {
strcpy(path, "direct");
ops->entry(node_p, node_p, path, 0, ops->private);
} else {
strcpy(path, "root");
do_xarray_iter(node_p, height, path, 0, ops);
}
return 0;
}
static void do_rdtree_entry(ulong node, ulong slot, const char *path,
ulong index, void *private)
{