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@xxxxxxxxxx> --- 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 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility