Add a new do_list_no_hash() function which is similar to do_list() but
without the hash_table overhead and without the LIST_ALLOCATE.
This function will be useful for faster and lower overhead list
enumeration, especially for the "list" command.
Signed-off-by: Dave Wysochanski <dwysocha(a)redhat.com>
---
defs.h | 1 +
tools.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 190 insertions(+)
diff --git a/defs.h b/defs.h
index b05aecc..3ab295a 100644
--- a/defs.h
+++ b/defs.h
@@ -4944,6 +4944,7 @@ char *shift_string_right(char *, int);
int bracketed(char *, char *, int);
void backspace(int);
int do_list(struct list_data *);
+int do_list_no_hash(struct list_data *);
struct radix_tree_ops {
void (*entry)(ulong node, ulong slot, const char *path,
ulong index, void *private);
diff --git a/tools.c b/tools.c
index 1a83643..a642d60 100644
--- a/tools.c
+++ b/tools.c
@@ -3863,6 +3863,195 @@ do_list(struct list_data *ld)
}
/*
+ * Similar to do_list() but without the hash_table or LIST_ALLOCATE.
+ * Useful for the 'list' command and other callers needing faster list
+ * enumeration.
+ */
+int
+do_list_no_hash(struct list_data *ld)
+{
+ ulong next, last, first, offset;
+ ulong searchfor, readflag;
+ int i, count, others;
+ unsigned int radix;
+ struct req_entry **e = NULL;
+
+ if (CRASHDEBUG(1)) {
+ others = 0;
+ console(" flags: %lx (", ld->flags);
+ if (ld->flags & VERBOSE)
+ console("%sVERBOSE", others++ ? "|" : "");
+ if (ld->flags & LIST_OFFSET_ENTERED)
+ console("%sLIST_OFFSET_ENTERED", others++ ? "|" : "");
+ if (ld->flags & LIST_START_ENTERED)
+ console("%sLIST_START_ENTERED", others++ ? "|" : "");
+ if (ld->flags & LIST_HEAD_FORMAT)
+ console("%sLIST_HEAD_FORMAT", others++ ? "|" : "");
+ if (ld->flags & LIST_HEAD_POINTER)
+ console("%sLIST_HEAD_POINTER", others++ ? "|" : "");
+ if (ld->flags & RETURN_ON_DUPLICATE)
+ console("%sRETURN_ON_DUPLICATE", others++ ? "|" : "");
+ if (ld->flags & RETURN_ON_LIST_ERROR)
+ console("%sRETURN_ON_LIST_ERROR", others++ ? "|" : "");
+ if (ld->flags & RETURN_ON_LIST_ERROR)
+ console("%sRETURN_ON_LIST_ERROR", others++ ? "|" : "");
+ if (ld->flags & LIST_STRUCT_RADIX_10)
+ console("%sLIST_STRUCT_RADIX_10", others++ ? "|" : "");
+ if (ld->flags & LIST_STRUCT_RADIX_16)
+ console("%sLIST_STRUCT_RADIX_16", others++ ? "|" : "");
+ if (ld->flags & LIST_ALLOCATE)
+ console("%sLIST_ALLOCATE", others++ ? "|" : "");
+ if (ld->flags & LIST_CALLBACK)
+ console("%sLIST_CALLBACK", others++ ? "|" : "");
+ if (ld->flags & CALLBACK_RETURN)
+ console("%sCALLBACK_RETURN", others++ ? "|" : "");
+ console(")\n");
+ console(" start: %lx\n", ld->start);
+ console(" member_offset: %ld\n", ld->member_offset);
+ console(" list_head_offset: %ld\n", ld->list_head_offset);
+ console(" end: %lx\n", ld->end);
+ console(" searchfor: %lx\n", ld->searchfor);
+ console(" structname_args: %lx\n", ld->structname_args);
+ if (!ld->structname_args)
+ console(" structname: (unused)\n");
+ for (i = 0; i < ld->structname_args; i++)
+ console(" structname[%d]: %s\n", i, ld->structname[i]);
+ console(" header: %s\n", ld->header);
+ console(" list_ptr: %lx\n", (ulong)ld->list_ptr);
+ console(" callback_func: %lx\n", (ulong)ld->callback_func);
+ console(" callback_data: %lx\n", (ulong)ld->callback_data);
+ console("struct_list_offset: %lx\n", ld->struct_list_offset);
+ }
+
+ count = 0;
+ searchfor = ld->searchfor;
+ ld->searchfor = 0;
+ if (ld->flags & LIST_STRUCT_RADIX_10)
+ radix = 10;
+ else if (ld->flags & LIST_STRUCT_RADIX_16)
+ radix = 16;
+ else
+ radix = 0;
+ next = ld->start;
+
+ readflag = ld->flags & RETURN_ON_LIST_ERROR ?
+ (RETURN_ON_ERROR|QUIET) : FAULT_ON_ERROR;
+
+ if (!readmem(next + ld->member_offset, KVADDR, &first, sizeof(void *),
+ "first list entry", readflag)) {
+ error(INFO, "\ninvalid list entry: %lx\n", next);
+ return -1;
+ }
+
+ if (ld->header)
+ fprintf(fp, "%s", ld->header);
+
+ offset = ld->list_head_offset + ld->struct_list_offset;
+
+ if (ld->structname && (ld->flags & LIST_READ_MEMBER)) {
+ e = (struct req_entry **)GETBUF(sizeof(*e) * ld->structname_args);
+ for (i = 0; i < ld->structname_args; i++)
+ e[i] = fill_member_offsets(ld->structname[i]);
+ }
+
+ while (1) {
+ if (ld->flags & VERBOSE) {
+ fprintf(fp, "%lx\n", next - ld->list_head_offset);
+
+ if (ld->structname) {
+ for (i = 0; i < ld->structname_args; i++) {
+ switch (count_chars(ld->structname[i], '.'))
+ {
+ case 0:
+ dump_struct(ld->structname[i],
+ next - offset, radix);
+ break;
+ default:
+ if (ld->flags & LIST_PARSE_MEMBER)
+ dump_struct_members(ld, i, next);
+ else if (ld->flags & LIST_READ_MEMBER)
+ dump_struct_members_fast(e[i],
+ radix, next - offset);
+ break;
+ }
+ }
+ }
+ }
+
+ if (next && 0) { /* FIXME - duplicate detection */
+ if (ld->flags &
+ (RETURN_ON_DUPLICATE|RETURN_ON_LIST_ERROR)) {
+ error(INFO, "\nduplicate list entry: %lx\n",
+ next);
+ return -1;
+ }
+ error(FATAL, "\nduplicate list entry: %lx\n", next);
+ }
+
+ if ((searchfor == next) ||
+ (searchfor == (next - ld->list_head_offset)))
+ ld->searchfor = searchfor;
+
+ count++;
+ last = next;
+
+ if ((ld->flags & LIST_CALLBACK) &&
+ ld->callback_func((void *)(next - ld->list_head_offset),
+ ld->callback_data) && (ld->flags & CALLBACK_RETURN))
+ break;
+
+ if (!readmem(next + ld->member_offset, KVADDR, &next,
+ sizeof(void *), "list entry", readflag)) {
+ error(INFO, "\ninvalid list entry: %lx\n", next);
+ return -1;
+ }
+
+ if (next == 0) {
+ if (ld->flags & LIST_HEAD_FORMAT) {
+ error(INFO, "\ninvalid list entry: 0\n");
+ return -1;
+ }
+ if (CRASHDEBUG(1))
+ console("do_list end: next:%lx\n", next);
+ break;
+ }
+
+ if (next == ld->end) {
+ if (CRASHDEBUG(1))
+ console("do_list end: next:%lx == end:%lx\n",
+ next, ld->end);
+ break;
+ }
+
+ if (next == ld->start) {
+ if (CRASHDEBUG(1))
+ console("do_list end: next:%lx == start:%lx\n",
+ next, ld->start);
+ break;
+ }
+
+ if (next == last) {
+ if (CRASHDEBUG(1))
+ console("do_list end: next:%lx == last:%lx\n",
+ next, last);
+ break;
+ }
+
+ if ((next == first) && (count != 1)) {
+ if (CRASHDEBUG(1))
+ console("do_list end: next:%lx == first:%lx (count %d)\n",
+ next, last, count);
+ break;
+ }
+ }
+
+ if (CRASHDEBUG(1))
+ console("do_list count: %d\n", count);
+
+ return count;
+}
+
+/*
* Issue a dump_struct_member() call for one or more structure
* members. Multiple members are passed in a comma-separated
* list using the the format:
--
1.8.3.1