[Crash-utility] [PATCH] New sbitmap command

HAGIO KAZUHITO(萩尾 一仁) k-hagio-ab at nec.com
Thu Nov 11 05:33:20 UTC 2021


Hi Sergey,

sorry for the late reply.

-----Original Message-----
> 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.

Thank you very much for working on this, we needed to support the sbitmap
structure especially to improve blk-mq support.  So we will use these
functionalities also on other command later.

I have a request.

Could you please modify the patch to follow crash's coding practices? i.e.
- to keep and dump needed offsets and sizes, use offset_table, size_table and
OFFSET(), SIZE() respectively.
- to show what's read (not just "__readmem") on an error, use the type
argument of readmem() correctly.
- to reduce the number of readmem(), use GETBUF() and ULONG() etc.

These will make the code redundant somewhat, but make it easier to debug
offset/address-related issues and make it easier to update the code with
our usual way.
I would like to keep error messages and debugging/fixing processes unchanged
as far as we can, because this will reduce our maintenance cost. e.g. there
is no need to update our crash testing tools, which detects error messages.
If once we accept an irregular case, another irregular patch may be posted,
it's not preferable to have various coding styles.

Another thing I found is that it looks like the current patch cannot display
structures if the array associated with sbitmap_queue is an array of the
pointers to the structures, but we can support it later.

Thanks,
Kazu

> 
> 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
> 
> 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 at redhat.com
> https://listman.redhat.com/mailman/listinfo/crash-utility





More information about the Crash-utility mailing list