Also added Sergey in the CC list. Thanks On Sat, Oct 23, 2021 at 11:11 AM lijiang <lijiang@xxxxxxxxxx> wrote: > > On Tue, Oct 5, 2021 at 4:51 PM <crash-utility-request@xxxxxxxxxx> wrote: > > Date: Mon, 4 Oct 2021 20:15:36 +0300 > > From: Sergey Samoylenko <s.samoylenko@xxxxxxxxx> > > To: <crash-utility@xxxxxxxxxx> > > Cc: Sergey Samoylenko <s.samoylenko@xxxxxxxxx>, linux@xxxxxxxxx > > Subject: [PATCH] New sbitmap command > > Message-ID: <20211004171536.30971-1-s.samoylenko@xxxxxxxxx> > > Content-Type: text/plain > > > > Patch adds new 'sbitmap' command. This command dumps > > the contents of the sbitmap_queue structure and the used > > bits in the bitmap. Also, it shows the dump of a structure > > array associated with the sbitmap_queue. > > > > Signed-off-by: Sergey Samoylenko <s.samoylenko@xxxxxxxxx> > > --- > > Makefile | 7 +- > > defs.h | 2 + > > global_data.c | 1 + > > help.c | 89 ++++++++ > > sbitmap.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++++++ > > 5 files changed, 688 insertions(+), 2 deletions(-) > > create mode 100644 sbitmap.c > > > > Thank you for the patch,Sergey. It is very helpful for parsing > sbitmap. But I need some time to understand this patch, please be > patient. > > Thanks. > Lianbo > > diff --git a/Makefile b/Makefile > > index ece1306..c116177 100644 > > --- a/Makefile > > +++ b/Makefile > > @@ -72,7 +72,7 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \ > > xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \ > > xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c ipcs.c \ > > ramdump.c vmware_vmss.c vmware_guestdump.c \ > > - xen_dom0.c kaslr_helper.c > > + xen_dom0.c kaslr_helper.c sbitmap.c > > > > SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \ > > ${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \ > > @@ -92,7 +92,7 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \ > > xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \ > > xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o ipcs.o \ > > ramdump.o vmware_vmss.o vmware_guestdump.o \ > > - xen_dom0.o kaslr_helper.o > > + xen_dom0.o kaslr_helper.o sbitmap.o > > > > MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c memory_driver/README > > > > @@ -346,6 +346,9 @@ cmdline.o: ${GENERIC_HFILES} cmdline.c > > tools.o: ${GENERIC_HFILES} tools.c > > ${CC} -c ${CRASH_CFLAGS} tools.c ${WARNING_OPTIONS} ${WARNING_ERROR} > > > > +sbitmap.o: ${GENERIC_HFILES} sbitmap.c > > + ${CC} -c ${CRASH_CFLAGS} sbitmap.c ${WARNING_OPTIONS} ${WARNING_ERROR} > > + > > global_data.o: ${GENERIC_HFILES} global_data.c > > ${CC} -c ${CRASH_CFLAGS} global_data.c ${WARNING_OPTIONS} ${WARNING_ERROR} > > > > diff --git a/defs.h b/defs.h > > index eb1c71b..1fa5c21 100644 > > --- a/defs.h > > +++ b/defs.h > > @@ -4956,6 +4956,7 @@ void cmd_mach(void); /* main.c */ > > void cmd_help(void); /* help.c */ > > void cmd_test(void); /* test.c */ > > void cmd_ascii(void); /* tools.c */ > > +void cmd_sbitmap(void); /* sbitmap.c */ > > void cmd_bpf(void); /* bfp.c */ > > void cmd_set(void); /* tools.c */ > > void cmd_eval(void); /* tools.c */ > > @@ -5543,6 +5544,7 @@ void display_help_screen(char *); > > extern char *help_pointer[]; > > extern char *help_alias[]; > > extern char *help_ascii[]; > > +extern char *help_sbitmap[]; > > extern char *help_bpf[]; > > extern char *help_bt[]; > > extern char *help_btop[]; > > diff --git a/global_data.c b/global_data.c > > index a316d1c..55524e3 100644 > > --- a/global_data.c > > +++ b/global_data.c > > @@ -105,6 +105,7 @@ struct command_table_entry linux_command_table[] = { > > {"rd", cmd_rd, help_rd, MINIMAL}, > > {"repeat", cmd_repeat, help_repeat, 0}, > > {"runq", cmd_runq, help_runq, REFRESH_TASK_TABLE}, > > + {"sbitmap", cmd_sbitmap, help_sbitmap, 0}, > > {"search", cmd_search, help_search, 0}, > > {"set", cmd_set, help_set, REFRESH_TASK_TABLE | MINIMAL}, > > {"sig", cmd_sig, help_sig, REFRESH_TASK_TABLE}, > > diff --git a/help.c b/help.c > > index 6c262a3..b946745 100644 > > --- a/help.c > > +++ b/help.c > > @@ -967,6 +967,95 @@ char *help_ascii[] = { > > NULL > > }; > > > > +char *help_sbitmap[] = { > > +"sbitmap", > > +"sbitmap_queue struct contents", > > +"[-s struct[.member[,member]] -p address [-v]] address", > > +" This command dumps the contents of the sbitmap_queue structure and", > > +" the used bits in the bitmap. Also, it shows the dump of a structure", > > +" array associated with the sbitmap_queue.", > > +"", > > +" The arguments are as follows:", > > +"", > > +" -s struct - name of a C-code structure, that is stored in an array", > > +" sssociated with sbitmap_queue structure. Use the", > > +" \"struct.member\" format in order to display a particular", > > +" member of the structure. -s option requires -p option", > > +"", > > +" -p address - address of a structure array associated with sbitmap_queue", > > +" structure. The set bits in sbitmap are used for the index", > > +" in an associated array.", > > +"", > > +" -x - override default output format with hexadecimal format.", > > +"", > > +" -d - override default output format with decimal format.", > > +"", > > +" -v - By default, the sbitmap command shows only a used sbitmap", > > +" index and a structure address in the associated array.", > > +" This flag says to print of a formatted display of the", > > +" contents of a structure in an associated array. -v option", > > +" requires of -s.", > > +"", > > +"EXAMPLES", > > +"", > > +" Display the common sbitmap information:", > > +"", > > +" %s> sbitmap ffffffffc06b9420", > > +" depth = 256", > > +" busy = 15", > > +" cleared = 1", > > +" bits_per_word = 64", > > +" map_nr = 4", > > +" alloc_hint = {193, 78}", > > +" wake_batch = 8", > > +" wake_index = 0", > > +" ws_active = 0", > > +" ws = {", > > +" { .wait_cnt = 8, .wait = inactive },", > > +" { .wait_cnt = 8, .wait = inactive },", > > +" { .wait_cnt = 8, .wait = inactive },", > > +" { .wait_cnt = 8, .wait = inactive },", > > +" { .wait_cnt = 8, .wait = inactive },", > > +" { .wait_cnt = 8, .wait = inactive },", > > +" { .wait_cnt = 8, .wait = inactive },", > > +" { .wait_cnt = 8, .wait = inactive },", > > +" }", > > +" round_robin = 0", > > +" min_shallow_depth = 4294967295", > > +"", > > +" 00000000: 0000 0000 0000 0000 ffbf 0000 0000 0000", > > +" 00000010: 0000 0000 0000 0000 0000 0000 0000 0000", > > +"", > > +" Display the structure address is associated with sbitmap_queue:", > > +"", > > +" %s> sbitmap -s test_data -p ffff973422dac000 ffffffffc06b9420", > > +" 64: 0xffff973422dac200", > > +" 65: 0xffff973422dac208", > > +" 66: 0xffff973422dac210", > > +" ...", > > +"", > > +" Display a formatted content of a structures:", > > +"", > > +" %s> sbitmap -s test_data -p ffff973422dac000 -v ffffffffc06b9420", > > +" 64 (0xffff973422dac200):", > > +" struct test_data {", > > +" tag = 64,", > > +" cpu = 1", > > +" }", > > +" 65 (0xffff973422dac208):", > > +" struct test_data {", > > +" tag = 65,", > > +" cpu = 1", > > +" }", > > +" 66 (0xffff973422dac210):", > > +" struct test_data {", > > +" tag = 66,", > > +" cpu = 1", > > +" }", > > +" ...", > > +NULL > > +}; > > + > > char *help_quit[] = { > > "quit", > > "exit this session", > > diff --git a/sbitmap.c b/sbitmap.c > > new file mode 100644 > > index 0000000..71522f8 > > --- /dev/null > > +++ b/sbitmap.c > > @@ -0,0 +1,591 @@ > > +/* sbitmap.c - core analysis suite > > + * > > + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. > > + * Copyright (C) 2002-2020 David Anderson > > + * Copyright (C) 2002-2020 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 > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + */ > > + > > +#include "defs.h" > > +#include <stdbool.h> > > + > > +#define SBQ_WAIT_QUEUES 8 > > + > > +static inline unsigned int __const_hweight8(unsigned long w) > > +{ > > + return > > + (!!((w) & (1ULL << 0))) + > > + (!!((w) & (1ULL << 1))) + > > + (!!((w) & (1ULL << 2))) + > > + (!!((w) & (1ULL << 3))) + > > + (!!((w) & (1ULL << 4))) + > > + (!!((w) & (1ULL << 5))) + > > + (!!((w) & (1ULL << 6))) + > > + (!!((w) & (1ULL << 7))); > > +} > > + > > +#define __const_hweight16(w) (__const_hweight8(w) + __const_hweight8((w) >> 8)) > > +#define __const_hweight32(w) (__const_hweight16(w) + __const_hweight16((w) >> 16)) > > +#define __const_hweight64(w) (__const_hweight32(w) + __const_hweight32((w) >> 32)) > > + > > +#define hweight32(w) __const_hweight32(w) > > +#define hweight64(w) __const_hweight64(w) > > + > > +#define BIT(nr) (1UL << (nr)) > > + > > +/* sbitmap and sbitmap_word structs context */ > > +struct sbitmap_context { > > + unsigned sb_depth; > > + unsigned sb_shift; > > + unsigned sb_map_nr; > > + ulong sb_map_addr; > > + unsigned sb_map_size; > > + > > + int w_depth_off; > > + int w_word_off; > > + int w_cleared_off; > > +}; > > + > > +/* sbitmap_queue struct context */ > > +struct sbitmap_queue_context { > > + ulong sb_addr; > > + ulong alloc_hint; > > + unsigned int wake_batch; > > + int wake_index; > > + ulong ws_addr; > > + int ws_active; > > + bool round_robin; > > + unsigned int min_shallow_depth; > > + > > +}; > > + > > +struct sbitmap_data { > > +#define SD_FLAG_STRUCT_NAME (VERBOSE << 1) > > +#define SD_FLAG_STRUCT_ADDR (VERBOSE << 2) > > +#define SD_FLAG_STRUCT_MEMBER (VERBOSE << 3) > > + ulong flags; > > + int radix; > > + /* sbitmap_queue info */ > > + ulong addr; > > + /* data array info */ > > + char *data_name; > > + ulong data_addr; > > + > > + struct sbitmap_queue_context sqc; > > + struct sbitmap_context sc; > > +}; > > + > > +static inline unsigned long min(unsigned long a, unsigned long b) > > +{ > > + return (a < b) ? a : b; > > +} > > + > > +static void __readmem(ulong addr, void *buffer, size_t size) > > +{ > > + ulong flag = FAULT_ON_ERROR; > > + > > + if (!readmem(addr, KVADDR, buffer, size, "__readmem", flag)) > > + error(FATAL, "failed read memory: 0x%x\n", addr); > > +} > > + > > +static ulong __read_ulong(ulong addr) > > +{ > > + ulong value; > > + > > + __readmem(addr, &value, sizeof(value)); > > + return value; > > +} > > + > > +static long __struct_size(char *name) > > +{ > > + long size; > > + > > + size = STRUCT_SIZE(name); > > + if (size < 0) > > + error(FATAL, "Invalid struct size: %s\n", name); > > + > > + return size; > > +} > > + > > +static long __member_offset(char *name, char *member) > > +{ > > + long offset; > > + > > + offset = MEMBER_OFFSET(name, member); > > + if (offset == INVALID_OFFSET) > > + offset = ANON_MEMBER_OFFSET(name, member); > > + if (offset == INVALID_OFFSET) > > + error(FATAL, "Can't get offset of '%s.%s'\n", name, member); > > + > > + return offset; > > +} > > + > > +static unsigned long __last_word_mask(unsigned long nbits) > > +{ > > + return ~0UL >> (-(nbits) & (BITS_PER_LONG - 1)); > > +} > > + > > +static unsigned long bitmap_hweight_long(unsigned long w) > > +{ > > + return sizeof(w) == 4 ? hweight32(w) : hweight64(w); > > +} > > + > > +static unsigned long bitmap_weight(unsigned long bitmap, unsigned int bits) > > +{ > > + unsigned long w = 0; > > + > > + w += bitmap_hweight_long(bitmap); > > + if (bits % BITS_PER_LONG) > > + w += bitmap_hweight_long(bitmap & __last_word_mask(bits)); > > + > > + return w; > > +} > > + > > +static unsigned int __sbitmap_weight(const struct sbitmap_context *sc, bool set) > > +{ > > + unsigned int weight = 0; > > + ulong addr = sc->sb_map_addr; > > + unsigned long depth, word, cleared; > > + int i; > > + > > + for (i = 0; i < sc->sb_map_nr; i++) { > > + depth = __read_ulong(addr + sc->w_depth_off); > > + > > + if (set) { > > + word = __read_ulong(addr + sc->w_word_off); > > + weight += bitmap_weight(word, depth); > > + } else { > > + cleared = __read_ulong(addr + sc->w_cleared_off); > > + weight += bitmap_weight(cleared, depth); > > + } > > + > > + addr += sc->sb_map_size; > > + } > > + > > + return weight; > > +} > > + > > +static unsigned int sbitmap_weight(const struct sbitmap_context *sc) > > +{ > > + return __sbitmap_weight(sc, true); > > +} > > + > > +static unsigned int sbitmap_cleared(const struct sbitmap_context *sc) > > +{ > > + return __sbitmap_weight(sc, false); > > +} > > + > > +static void sbitmap_queue_show(const struct sbitmap_queue_context *sqc, > > + const struct sbitmap_context *sc) > > +{ > > + int cpus = get_cpus_possible(); > > + int sbq_wait_state_size, wait_cnt_off, wait_off, list_head_off; > > + bool first; > > + int i; > > + > > + fprintf(fp, "depth = %u\n", sc->sb_depth); > > + fprintf(fp, "busy = %u\n", sbitmap_weight(sc) - sbitmap_cleared(sc)); > > + fprintf(fp, "cleared = %u\n", sbitmap_cleared(sc)); > > + fprintf(fp, "bits_per_word = %u\n", 1U << sc->sb_shift); > > + fprintf(fp, "map_nr = %u\n", sc->sb_map_nr); > > + > > + fputs("alloc_hint = {", fp); > > + first = true; > > + for (i = 0; i < cpus; i++) { > > + if (!first) > > + fprintf(fp, ", "); > > + first = false; > > + > > + ulong ptr = kt->__per_cpu_offset[i] + sqc->alloc_hint; > > + fprintf(fp, "%lu", __read_ulong(ptr)); > > + } > > + fputs("}\n", fp); > > + > > + fprintf(fp, "wake_batch = %u\n", sqc->wake_batch); > > + fprintf(fp, "wake_index = %d\n", sqc->wake_index); > > + fprintf(fp, "ws_active = %d\n", sqc->ws_active); > > + > > + sbq_wait_state_size = __struct_size("sbq_wait_state"); > > + wait_cnt_off = __member_offset("sbq_wait_state", "wait_cnt"); > > + wait_off = __member_offset("sbq_wait_state", "wait"); > > + list_head_off = __member_offset("wait_queue_head", "head"); > > + > > + fputs("ws = {\n", fp); > > + for (i = 0; i < SBQ_WAIT_QUEUES; i++) { > > + ulong ws_addr = sqc->ws_addr + (sbq_wait_state_size * i); > > + struct kernel_list_head lh; > > + ulong wait_cnt_addr, list_head_addr; > > + ulong wait_cnt; > > + > > + wait_cnt_addr = ws_addr + wait_cnt_off; > > + __readmem(wait_cnt_addr, &wait_cnt, sizeof(wait_cnt)); > > + > > + list_head_addr = ws_addr + wait_off + list_head_off; > > + __readmem(list_head_addr, &lh, sizeof(lh)); > > + > > + fprintf(fp, "\t{ .wait_cnt = %lu, .wait = %s },\n", > > + wait_cnt, (lh.next == lh.prev) ? "inactive" : "active"); > > + } > > + fputs("}\n", fp); > > + > > + fprintf(fp, "round_robin = %d\n", sqc->round_robin); > > + fprintf(fp, "min_shallow_depth = %u\n", sqc->min_shallow_depth); > > +} > > + > > +static void sbitmap_emit_byte(unsigned int offset, uint8_t byte) > > +{ > > + if ((offset &0xf) == 0) { > > + if (offset != 0) > > + fputc('\n', fp); > > + fprintf(fp, "%08x:", offset); > > + } > > + if ((offset & 0x1) == 0) > > + fputc(' ', fp); > > + fprintf(fp, "%02x", byte); > > +} > > + > > +static void sbitmap_bitmap_show(const struct sbitmap_context *sc) > > +{ > > + uint8_t byte = 0; > > + unsigned int byte_bits = 0; > > + unsigned int offset = 0; > > + int i; > > + > > + for (i = 0; i < sc->sb_map_nr; i++) { > > + ulong addr = sc->sb_map_addr + (sc->sb_map_size * i); > > + unsigned long word = __read_ulong(addr + sc->w_word_off); > > + unsigned long cleared = __read_ulong(addr + sc->w_cleared_off); > > + unsigned long word_bits = __read_ulong(addr + sc->w_depth_off); > > + > > + word &= ~cleared; > > + > > + while (word_bits > 0) { > > + unsigned int bits = min(8 - byte_bits, word_bits); > > + > > + byte |= (word & (BIT(bits) - 1)) << byte_bits; > > + byte_bits += bits; > > + if (byte_bits == 8) { > > + sbitmap_emit_byte(offset, byte); > > + byte = 0; > > + byte_bits = 0; > > + offset++; > > + } > > + word >>= bits; > > + word_bits -= bits; > > + } > > + > > + } > > + if (byte_bits) { > > + sbitmap_emit_byte(offset, byte); > > + offset++; > > + } > > + if (offset) > > + fputc('\n', fp); > > +} > > + > > +static void sbitmap_queue_dump(const struct sbitmap_data *sd) > > +{ > > + sbitmap_queue_show(&sd->sqc, &sd->sc); > > + fputc('\n', fp); > > + sbitmap_bitmap_show(&sd->sc); > > +} > > + > > +static unsigned long sbitmap_find_next_bit(unsigned long word, > > + unsigned long size, unsigned long offset) > > +{ > > + if (size > BITS_PER_LONG) > > + error(FATAL, "%s: word size isn't correct\n", __func__); > > + > > + for (; offset < size; offset++) > > + if (word & (1UL << offset)) > > + return offset; > > + > > + return size; > > +} > > + > > +typedef bool (*sb_for_each_fn)(unsigned int, void *); > > + > > +static void __sbitmap_for_each_set(const struct sbitmap_context *sc, > > + unsigned int start, sb_for_each_fn fn, void *data) > > +{ > > + unsigned int index; > > + unsigned int nr; > > + unsigned int scanned = 0; > > + > > + if (start >= sc->sb_map_nr) > > + start = 0; > > + > > + index = start >> sc->sb_shift; > > + nr = start & ((1U << sc->sb_shift) - 1U); > > + > > + while (scanned < sc->sb_depth) { > > + unsigned long w_addr = sc->sb_map_addr + (sc->sb_map_size * index); > > + > > + unsigned long w_depth = __read_ulong(w_addr + sc->w_depth_off); > > + unsigned long w_word = __read_ulong(w_addr + sc->w_word_off); > > + unsigned long w_cleared = __read_ulong(w_addr + sc->w_cleared_off); > > + > > + unsigned long word; > > + unsigned int depth = min(w_depth - nr, sc->sb_depth - scanned); > > + > > + scanned += depth; > > + word = w_word & ~w_cleared; > > + if (!word) > > + goto next; > > + > > + /* > > + * On the first iteration of the outer loop, we need to add the > > + * bit offset back to the size of the word for find_next_bit(). > > + * On all other iterations, nr is zero, so this is a noop. > > + */ > > + depth += nr; > > + while (1) { > > + nr = sbitmap_find_next_bit(word, depth, nr); > > + if (nr >= depth) > > + break; > > + if (!fn((index << sc->sb_shift) + nr, data)) > > + return; > > + > > + nr++; > > + } > > +next: > > + nr = 0; > > + if (++index >= sc->sb_map_nr) > > + index = 0; > > + } > > +} > > + > > +static void sbitmap_for_each_set(const struct sbitmap_context *sc, > > + sb_for_each_fn fn, void *data) > > +{ > > + __sbitmap_for_each_set(sc, 0, fn, data); > > +} > > + > > +static void sbitmap_dump_struct_members(const char *s, ulong addr, unsigned radix) > > +{ > > + int i, argc; > > + char *p1, *p2; > > + char *structname, *members; > > + char *arglist[MAXARGS]; > > + > > + structname = GETBUF(strlen(s) + 1); > > + members = GETBUF(strlen(s) + 1); > > + > > + strcpy(structname, s); > > + p1 = strstr(structname, ".") + 1; > > + > > + p2 = strstr(s, ".") + 1; > > + strcpy(members, p2); > > + replace_string(members, ",", ' '); > > + argc = parse_line(members, arglist); > > + > > + for (i = 0; i < argc; i++) { > > + *p1 = NULLCHAR; > > + strcat(structname, arglist[i]); > > + dump_struct_member(structname, addr, radix); > > + } > > + > > + FREEBUF(structname); > > + FREEBUF(members); > > +} > > + > > +struct data_info { > > + ulong addr; > > + int size; > > + char *name; > > + unsigned radix; > > + bool verbose; > > + bool members; > > +}; > > + > > +static bool sbitmap_data_print(unsigned int idx, void *data) > > +{ > > + const struct data_info *d = data; > > + ulong addr = d->addr + (d->size * idx); > > + > > + if (d->verbose) { > > + fprintf(fp, "%d (0x%08lx):\n", idx, addr); > > + if (d->members) > > + sbitmap_dump_struct_members(d->name, addr, d->radix); > > + else > > + dump_struct(d->name, addr, d->radix); > > + } else > > + fprintf(fp, "%d: 0x%08lx\n", idx, addr); > > + > > + return true; > > +} > > + > > +static char *__get_struct_name(const char *s) > > +{ > > + char *name, *p; > > + > > + name = GETBUF(strlen(s) + 1); > > + strcpy(name, s); > > + > > + p = strstr(name, "."); > > + *p = NULLCHAR; > > + > > + return name; > > +} > > + > > +static void sbitmap_data_dump(const struct sbitmap_data *sd) > > +{ > > + struct data_info d = {0}; > > + > > + d.addr = sd->data_addr; > > + d.name = sd->data_name; > > + d.radix = sd->radix; > > + d.verbose = !!(sd->flags & VERBOSE); > > + d.members = !!(sd->flags & SD_FLAG_STRUCT_MEMBER); > > + > > + if (d.members) { > > + char *name = __get_struct_name(d.name); > > + d.size = __struct_size(name); > > + FREEBUF(name); > > + } else > > + d.size = __struct_size(d.name); > > + > > + sbitmap_for_each_set(&sd->sc, sbitmap_data_print, &d); > > +} > > + > > +static void load_sbitmap_queue_context(ulong addr, struct sbitmap_queue_context *sqc) > > +{ > > + char *sb_q = "sbitmap_queue"; > > + > > + sqc->sb_addr = addr + __member_offset(sb_q, "sb"); > > + __readmem(addr + __member_offset(sb_q, "alloc_hint"), &sqc->alloc_hint, sizeof(sqc->alloc_hint)); > > + __readmem(addr + __member_offset(sb_q, "wake_batch"), &sqc->wake_batch, sizeof(sqc->wake_batch)); > > + __readmem(addr + __member_offset(sb_q, "wake_index"), &sqc->wake_index, sizeof(sqc->wake_index)); > > + __readmem(addr + __member_offset(sb_q, "ws"), &sqc->ws_addr, sizeof(sqc->ws_addr)); > > + __readmem(addr + __member_offset(sb_q, "ws_active"), &sqc->ws_active, sizeof(sqc->ws_active)); > > + __readmem(addr + __member_offset(sb_q, "round_robin"), &sqc->round_robin, sizeof(sqc->round_robin)); > > + __readmem(addr + __member_offset(sb_q, "min_shallow_depth"), &sqc->min_shallow_depth, sizeof(sqc->min_shallow_depth)); > > +} > > + > > +static void load_sbitmap_context(ulong addr, struct sbitmap_context *sc) > > +{ > > + char *sb = "sbitmap"; > > + char *map = "sbitmap_word"; > > + > > + __readmem(addr + __member_offset(sb, "depth"), &sc->sb_depth, sizeof(sc->sb_depth)); > > + __readmem(addr + __member_offset(sb, "shift"), &sc->sb_shift, sizeof(sc->sb_shift)); > > + __readmem(addr + __member_offset(sb, "map_nr"), &sc->sb_map_nr, sizeof(sc->sb_map_nr)); > > + __readmem(addr + __member_offset(sb, "map"), &sc->sb_map_addr, sizeof(sc->sb_map_addr)); > > + sc->sb_map_size = __struct_size(map); > > + sc->w_depth_off = __member_offset(map, "depth"); > > + sc->w_word_off = __member_offset(map, "word"); > > + sc->w_cleared_off = __member_offset(map, "cleared"); > > +} > > + > > +void cmd_sbitmap(void) > > +{ > > + struct sbitmap_data sd = {0}; > > + int c; > > + > > + while ((c = getopt(argcnt, args, "s:p:xdv")) != EOF) { > > + switch (c) { > > + case 's': > > + if (sd.flags & SD_FLAG_STRUCT_NAME) > > + error(FATAL, "-s option (%s) already entered\n", sd.data_name); > > + > > + sd.data_name = optarg; > > + sd.flags |= SD_FLAG_STRUCT_NAME; > > + > > + break; > > + > > + case 'p': > > + if (sd.flags & SD_FLAG_STRUCT_ADDR) > > + error(FATAL, "-m option (0x%lx) already entered\n", sd.data_addr); > > + else if (!IS_A_NUMBER(optarg)) > > + error(FATAL, "invalid -m option: %s\n", optarg); > > + > > + sd.data_addr = htol(optarg, FAULT_ON_ERROR, NULL); > > + if (!IS_KVADDR(sd.data_addr)) > > + error(FATAL, "invalid kernel virtual address: %s\n", optarg); > > + sd.flags |= SD_FLAG_STRUCT_ADDR; > > + > > + break; > > + > > + case 'v': > > + sd.flags |= VERBOSE; > > + break; > > + > > + case 'x': > > + if (sd.radix == 10) > > + error(FATAL, "-d and -x are mutually exclusive\n"); > > + sd.radix = 16; > > + break; > > + > > + case 'd': > > + if (sd.radix == 16) > > + error(FATAL, "-d and -x are mutually exclusive\n"); > > + sd.radix = 10; > > + break; > > + > > + default: > > + argerrs++; > > + break; > > + } > > + } > > + > > + if (argerrs) > > + cmd_usage(pc->curcmd, SYNOPSIS); > > + > > + if (!args[optind]) { > > + error(INFO, "command argument is required\n"); > > + cmd_usage(pc->curcmd, SYNOPSIS); > > + } else if (args[optind] && args[optind + 1]) { > > + error(INFO, "too many arguments\n"); > > + cmd_usage(pc->curcmd, SYNOPSIS); > > + } else if (!IS_A_NUMBER(args[optind])) { > > + error(FATAL, "invalid command argument: %s\n", args[optind]); > > + } > > + > > + sd.addr = htol(args[optind], FAULT_ON_ERROR, NULL); > > + if (!IS_KVADDR(sd.addr)) > > + error(FATAL, "invalid kernel virtual address: %s\n", args[optind]); > > + > > + if ((sd.flags & SD_FLAG_STRUCT_NAME) && !(sd.flags & SD_FLAG_STRUCT_ADDR)) { > > + error(INFO, "-s option requires -m option"); > > + cmd_usage(pc->curcmd, SYNOPSIS); > > + } else if ((sd.flags & SD_FLAG_STRUCT_ADDR) && !(sd.flags & SD_FLAG_STRUCT_NAME)) { > > + error(FATAL, "-m option is used with -s option only\n"); > > + cmd_usage(pc->curcmd, SYNOPSIS); > > + } > > + > > + if (sd.flags & SD_FLAG_STRUCT_NAME) { > > + bool error_flag = false; > > + > > + if (count_chars(sd.data_name, '.') > 0) > > + sd.flags |= SD_FLAG_STRUCT_MEMBER; > > + > > + if (sd.flags & SD_FLAG_STRUCT_MEMBER) { > > + char *data_name = __get_struct_name(sd.data_name); > > + if (!STRUCT_EXISTS(data_name)) > > + error_flag = true; > > + FREEBUF(data_name); > > + } else { > > + if (!STRUCT_EXISTS(sd.data_name)) > > + error_flag = true; > > + } > > + if (error_flag) > > + error(FATAL, "invalid data structure reference: %s\n", sd.data_name); > > + } > > + > > + load_sbitmap_queue_context(sd.addr, &sd.sqc); > > + load_sbitmap_context(sd.sqc.sb_addr, &sd.sc); > > + > > + if (sd.flags & SD_FLAG_STRUCT_NAME) > > + sbitmap_data_dump(&sd); > > + else > > + sbitmap_queue_dump(&sd); > > +} > > -- > > 2.25.1 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://listman.redhat.com/mailman/listinfo/crash-utility