[Crash-utility] [PATCH] New sbitmap command
lijiang
lijiang at redhat.com
Mon Oct 25 08:39:55 UTC 2021
Also added Sergey in the CC list.
Thanks
On Sat, Oct 23, 2021 at 11:11 AM lijiang <lijiang at redhat.com> wrote:
>
> On Tue, Oct 5, 2021 at 4:51 PM <crash-utility-request at redhat.com> wrote:
> > Date: Mon, 4 Oct 2021 20:15:36 +0300
> > From: Sergey Samoylenko <s.samoylenko at yadro.com>
> > To: <crash-utility at redhat.com>
> > Cc: Sergey Samoylenko <s.samoylenko at yadro.com>, linux at yadro.com
> > Subject: [Crash-utility] [PATCH] New sbitmap command
> > Message-ID: <20211004171536.30971-1-s.samoylenko at yadro.com>
> > 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 at yadro.com>
> > ---
> > 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
More information about the Crash-utility
mailing list