Hi Kazu,
Thank you for supporting me with my first patch to crash.
04.02.2022 4:52, HAGIO KAZUHITO(萩尾 一仁) пишет:
Hi Sergey,
-----Original Message-----
> Patch adds new 'sbitmapq' 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.
>
> v1 -> v2:
> - Update the help page (Lianbo)
> - Use crash interfaces (offset_table, size_table, GETBUF()
> and etc.) for reduce the number of readmem() (Kazu)
Thank you for the update, the patch looks nice and clean!
I have two slight questions inline with "Question:".
As for the others, I've changed the code at my end and been testing,
so I can post it when the questions are solved.
> Signed-off-by: Sergey Samoylenko <s.samoylenko(a)yadro.com>
> ---
> Makefile | 7 +-
> defs.h | 59 +++++
> global_data.c | 1 +
> help.c | 108 ++++++++
> sbitmap.c | 664 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 837 insertions(+), 2 deletions(-)
> create mode 100644 sbitmap.c
>
> diff --git a/Makefile b/Makefile
> index 4fd8b78..a381c5f 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
>
> @@ -341,6 +341,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 b63741c..d407025 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -18,6 +18,7 @@
>
> #ifndef GDB_COMMON
>
> +#include <stdbool.h>
> #include <stdio.h>
> #include <stdarg.h>
> #include <stdint.h>
> @@ -2146,6 +2147,23 @@ struct offset_table { /* stash of
commonly-used offsets */
> long wait_queue_entry_private;
> long wait_queue_head_head;
> long wait_queue_entry_entry;
> + long sbitmap_word_depth;
> + long sbitmap_word_word;
> + long sbitmap_word_cleared;
> + long sbitmap_depth;
> + long sbitmap_shift;
> + long sbitmap_map_nr;
> + long sbitmap_map;
> + long sbitmap_queue_sb;
> + long sbitmap_queue_alloc_hint;
> + long sbitmap_queue_wake_batch;
> + long sbitmap_queue_wake_index;
> + long sbitmap_queue_ws;
> + long sbitmap_queue_ws_active;
> + long sbitmap_queue_round_robin;
> + long sbitmap_queue_min_shallow_depth;
> + long sbq_wait_state_wait_cnt;
> + long sbq_wait_state_wait;
> };
>
> struct size_table { /* stash of commonly-used sizes */
> @@ -2310,6 +2328,10 @@ struct size_table { /* stash of commonly-used sizes
*/
> long prb_desc;
> long wait_queue_entry;
> long task_struct_state;
> + long sbitmap_word;
> + long sbitmap;
> + long sbitmap_queue;
> + long sbq_wait_state;
> };
The corresponding entries are needed in "help -o" output.
--- a/symbols.c
+++ b/symbols.c
@@ -10690,6 +10690,24 @@ dump_offset_table(char *spec, ulong makestruct)
fprintf(fp, " uts_namespace_name: %ld\n",
OFFSET(uts_namespace_name));
+ fprintf(fp, " sbitmap_word_depth: %ld\n",
OFFSET(sbitmap_word_depth));
+ fprintf(fp, " sbitmap_word_word: %ld\n",
OFFSET(sbitmap_word_word));
+ fprintf(fp, " sbitmap_word_cleared: %ld\n",
OFFSET(sbitmap_word_cleared));
+ fprintf(fp, " sbitmap_depth: %ld\n",
OFFSET(sbitmap_depth));
+ fprintf(fp, " sbitmap_shift: %ld\n",
OFFSET(sbitmap_shift));
+ fprintf(fp, " sbitmap_map_nr: %ld\n",
OFFSET(sbitmap_map_nr));
+ fprintf(fp, " sbitmap_map: %ld\n",
OFFSET(sbitmap_map));
+ fprintf(fp, " sbitmap_queue_sb: %ld\n",
OFFSET(sbitmap_queue_sb));
+ fprintf(fp, " sbitmap_queue_alloc_hint: %ld\n",
OFFSET(sbitmap_queue_alloc_hint));
+ fprintf(fp, " sbitmap_queue_wake_batch: %ld\n",
OFFSET(sbitmap_queue_wake_batch));
+ fprintf(fp, " sbitmap_queue_wake_index: %ld\n",
OFFSET(sbitmap_queue_wake_index));
+ fprintf(fp, " sbitmap_queue_ws: %ld\n",
OFFSET(sbitmap_queue_ws));
+ fprintf(fp, " sbitmap_queue_ws_active: %ld\n",
OFFSET(sbitmap_queue_ws_active));
+ fprintf(fp, " sbitmap_queue_round_robin: %ld\n",
OFFSET(sbitmap_queue_round_robin));
+ fprintf(fp, "sbitmap_queue_min_shallow_depth: %ld\n",
OFFSET(sbitmap_queue_min_shallow_depth));
+ fprintf(fp, " sbq_wait_state_wait_cnt: %ld\n",
OFFSET(sbq_wait_state_wait_cnt));
+ fprintf(fp, " sbq_wait_state_wait: %ld\n",
OFFSET(sbq_wait_state_wait));
+
fprintf(fp, "\n size_table:\n");
fprintf(fp, " page: %ld\n", SIZE(page));
fprintf(fp, " page_flags: %ld\n",
SIZE(page_flags));
@@ -10955,6 +10973,10 @@ dump_offset_table(char *spec, ulong makestruct)
fprintf(fp, " printk_ringbuffer: %ld\n",
SIZE(printk_ringbuffer));
fprintf(fp, " prb_desc: %ld\n", SIZE(prb_desc));
+ fprintf(fp, " sbitmap_word: %ld\n",
SIZE(sbitmap_word));
+ fprintf(fp, " sbitmap: %ld\n", SIZE(sbitmap));
+ fprintf(fp, " sbitmap_queue: %ld\n",
SIZE(sbitmap_queue));
+ fprintf(fp, " sbq_wait_state: %ld\n",
SIZE(sbq_wait_state));
fprintf(fp, "\n array_table:\n");
/*
Didn't notice this output. Thanks, added.
> struct array_table {
> @@ -2436,6 +2458,7 @@ DEF_LOADER(ushort);
> DEF_LOADER(short);
> typedef void *pointer_t;
> DEF_LOADER(pointer_t);
> +DEF_LOADER(bool);
>
> #define LOADER(TYPE) load_##TYPE
>
> @@ -2449,6 +2472,7 @@ DEF_LOADER(pointer_t);
> #define SHORT(ADDR) LOADER(short) ((char *)(ADDR))
> #define UCHAR(ADDR) *((unsigned char *)((char *)(ADDR)))
> #define VOID_PTR(ADDR) ((void *) (LOADER(pointer_t) ((char *)(ADDR))))
> +#define BOOL(ADDR) LOADER(bool) ((char *)(ADDR)))
>
> #else
>
> @@ -2462,6 +2486,7 @@ DEF_LOADER(pointer_t);
> #define SHORT(ADDR) *((short *)((char *)(ADDR)))
> #define UCHAR(ADDR) *((unsigned char *)((char *)(ADDR)))
> #define VOID_PTR(ADDR) *((void **)((char *)(ADDR)))
> +#define BOOL(ADDR) *((bool *)((char *)(ADDR)))
>
> #endif /* NEED_ALIGNED_MEM_ACCESS */
>
> @@ -4962,6 +4987,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_sbitmapq(void); /* sbitmap.c */
> void cmd_bpf(void); /* bfp.c */
> void cmd_set(void); /* tools.c */
> void cmd_eval(void); /* tools.c */
> @@ -5575,6 +5601,7 @@ extern char *help_rd[];
> extern char *help_repeat[];
> extern char *help_runq[];
> extern char *help_ipcs[];
> +extern char *help_sbitmapq[];
> extern char *help_search[];
> extern char *help_set[];
> extern char *help_sig[];
> @@ -5844,6 +5871,38 @@ void devdump_info(void *, ulonglong, FILE *);
> void ipcs_init(void);
> ulong idr_find(ulong, int);
>
> +/*
> + * sbitmap.c
> + */
> +/* sbitmap helpers */
> +struct sbitmap_context {
> + unsigned depth;
> + unsigned shift;
> + unsigned map_nr;
> + ulong map_addr;
> +};
> +
> +typedef bool (*sbitmap_for_each_fn)(unsigned int idx, void *p);
> +
> +void sbitmap_for_each_set(const struct sbitmap_context *sc,
> + sbitmap_for_each_fn fn, void *data);
> +void sbitmap_context_load(ulong addr, struct sbitmap_context *sc);
> +
> +/* sbitmap_queue helpers */
> +typedef bool (*sbitmapq_for_each_fn)(unsigned int idx, ulong addr, void *p);
> +
> +struct sbitmapq_ops {
> + /* array params associated with the bitmap */
> + ulong addr;
> + ulong size;
> + /* callback params */
> + sbitmapq_for_each_fn fn;
> + void *p;
> +};
> +
> +void sbitmapq_init(void);
> +void sbitmapq_for_each_set(ulong addr, struct sbitmapq_ops *ops);
> +
> #ifdef ARM
> void arm_init(int);
> void arm_dump_machdep_table(ulong);
> diff --git a/global_data.c b/global_data.c
> index a316d1c..f9bb7d0 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},
> + {"sbitmapq", cmd_sbitmapq, help_sbitmapq, 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 04a7eff..d151f2e 100644
> --- a/help.c
> +++ b/help.c
> @@ -962,6 +962,114 @@ char *help_ascii[] = {
> NULL
> };
>
> +char *help_sbitmapq[] = {
> +"sbitmapq",
> +"sbitmap_queue struct contents",
> +"[-s struct[.member[,member]] -p address [-v]] address",
> +" The 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",
s/sssociated/associated/
> +" \"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 a formatted display of the",
> +" contents of a structure in an associated array. -v
option",
> +" requires of -s.",
I'd like to change these to the crash style like this:
" -s struct name of a C-code structure, that is stored in an array",
" associated 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 a formatted display of the",
" contents of a structure in an associated array. -v option",
" requires of -s.",
> +"",
> +"EXAMPLES",
> +"",
> +" All examples are shown on the base of Linux Target system whit iSCSI",
s/whit/with/
Fixed help and typos.
> +" transport.",
> +"",
> +" Display the common sbitmap information for target session:",
> +"",
> +" %s> struct -oh se_session 0xc0000000e118c760 | grep
sbitmap_queue",
> +" [c0000000e118c808] struct sbitmap_queue sess_tag_pool;",
> +" %s>",
> +" %s> sbitmapq c0000000e118c808",
> +" depth = 136",
> +" busy = 4",
> +" cleared = 26",
> +" bits_per_word = 32",
> +" map_nr = 5",
> +" alloc_hint = {74, 36, 123, 101}",
> +" 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 0030 0000 0000 0000",
> +" 00000010: 00",
> +"",
> +" Display the addresses of structure are associated with",
> +" sbitmap_queue (for iscsi it is 'iscsi_cmd' structure):",
> +"",
> +" %s> struct se_session 0xc0000000e118c760 | grep sess_cmd_map",
> +" sess_cmd_map = 0xc0000000671c0000,",
> +" %s>",
> +" %s> sbitmapq -s iscsi_cmd -p 0xc0000000671c0000
c0000000e118c808",
> +" 76: 0xc0000000671d5600",
> +" 77: 0xc0000000671d5a80",
> +"",
> +
> +" Dump of formatted content of structures:",
> +"",
> +" %s> sbitmapq -s iscsi_cmd -p 0xc0000000671c0000 -v
c0000000e118c808",
> +" 76 (0xc0000000671d5600):",
> +" struct iscsi_cmd {",
> +" dataout_timer_flags = 0,",
> +" dataout_timeout_retries = 0 '\\000',",
> +" error_recovery_count = 0 '\\000',",
> +" deferred_i_state = ISTATE_NO_STATE,",
> +" i_state = ISTATE_SENT_STATUS,",
> +" ...",
> +" first_data_sg = 0xc0000000e306b080,",
> +" first_data_sg_off = 0,",
> +" kmapped_nents = 1,",
> +" sense_reason = 0",
> +" }",
> +" 77 (0xc0000000671d5a80):",
> +" struct iscsi_cmd {",
> +" dataout_timer_flags = 0,",
> +" dataout_timeout_retries = 0 '\\000',",
> +" error_recovery_count = 0 '\\000',",
> +" deferred_i_state = ISTATE_NO_STATE,",
> +" i_state = ISTATE_NEW_CMD,",
> +" ...",
> +" first_data_sg = 0x0,",
> +" first_data_sg_off = 0,",
> +" kmapped_nents = 0,",
> +" sense_reason = 0",
> +" }",
> +NULL
> +};
> +
> char *help_quit[] = {
> "quit",
> "exit this session",
> diff --git a/sbitmap.c b/sbitmap.c
> new file mode 100644
> index 0000000..5343a88
> --- /dev/null
> +++ b/sbitmap.c
> @@ -0,0 +1,664 @@
> +/* 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.
Question:
Would you like to change these copyright notices to yours?
If you have a proper one, please let me know.
e.g. in crash_target.c:
* Copyright (c) 2021 VMware, Inc.
Fixed copyright.
> + *
> + * 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"
> +
> +#define SBQ_WAIT_QUEUES 8
> +
> +/* 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 sbitmapq_data {
> +#define SBITMAPQ_DATA_FLAG_STRUCT_NAME (VERBOSE << 1)
> +#define SBITMAPQ_DATA_FLAG_STRUCT_ADDR (VERBOSE << 2)
> +#define SBITMAPQ_DATA_FLAG_STRUCT_MEMBER (VERBOSE << 3)
> + ulong flags;
> + int radix;
> + /* sbitmap_queue info */
> + ulong addr;
> + /* data array info */
> + ulong data_addr;
> + char *data_name;
> + int data_size;
> +};
> +
> +#define SB_FLAG_INIT 0x01
> +
> +static uint sb_flags = 0;
> +
> +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))
> +
> +static inline unsigned long min(unsigned long a, unsigned long b)
> +{
> + return (a < b) ? a : b;
> +}
> +
> +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)
> +{
> + const ulong sbitmap_word_size = SIZE(sbitmap_word);
> + const ulong w_depth_off = OFFSET(sbitmap_word_depth);
> + const ulong w_word_off = OFFSET(sbitmap_word_word);
> + const ulong w_cleared_off = OFFSET(sbitmap_word_cleared);
> +
> + unsigned int weight = 0;
> + ulong addr = sc->map_addr;
> + ulong depth, word, cleared;
> + char *sbitmap_word_buf;
> + int i;
> +
> + sbitmap_word_buf = GETBUF(sbitmap_word_size);
> +
> + for (i = 0; i < sc->map_nr; i++) {
> + readmem(addr, KVADDR, sbitmap_word_buf, sbitmap_word_size,
"sbitmap_word",
> FAULT_ON_ERROR);
> +
> + depth = ULONG(sbitmap_word_buf + w_depth_off);
> +
> + if (set) {
> + word = ULONG(sbitmap_word_buf + w_word_off);
> + weight += bitmap_weight(word, depth);
> + } else {
> + cleared = ULONG(sbitmap_word_buf + w_cleared_off);
> + weight += bitmap_weight(cleared, depth);
> + }
> +
> + addr += sbitmap_word_size;
> + }
> +
> + FREEBUF(sbitmap_word_buf);
> +
> + 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_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)
> +{
> + const ulong sbitmap_word_size = SIZE(sbitmap_word);
> + const ulong w_depth_off = OFFSET(sbitmap_word_depth);
> + const ulong w_word_off = OFFSET(sbitmap_word_word);
> + const ulong w_cleared_off = OFFSET(sbitmap_word_cleared);
> +
> + uint8_t byte = 0;
> + unsigned int byte_bits = 0;
> + unsigned int offset = 0;
> + ulong addr = sc->map_addr;
> + char *sbitmap_word_buf;
> + int i;
> +
> + sbitmap_word_buf = GETBUF(sbitmap_word_size);
> +
> + for (i = 0; i < sc->map_nr; i++) {
> + unsigned long word, cleared, word_bits;
> +
> + readmem(addr, KVADDR, sbitmap_word_buf, sbitmap_word_size,
"sbitmap_word",
> FAULT_ON_ERROR);
> +
> + word = ULONG(sbitmap_word_buf + w_word_off);
> + cleared = ULONG(sbitmap_word_buf + w_cleared_off);
> + word_bits = ULONG(sbitmap_word_buf + 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;
> + }
> +
> + addr += sbitmap_word_size;
> + }
> + if (byte_bits) {
> + sbitmap_emit_byte(offset, byte);
> + offset++;
> + }
> + if (offset)
> + fputc('\n', fp);
> +
> + FREEBUF(sbitmap_word_buf);
> +}
> +
> +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;
> +}
> +
> +static void __sbitmap_for_each_set(const struct sbitmap_context *sc,
> + unsigned int start, sbitmap_for_each_fn fn, void *data)
> +{
> + const ulong sbitmap_word_size = SIZE(sbitmap_word);
> + const ulong w_depth_off = OFFSET(sbitmap_word_depth);
> + const ulong w_word_off = OFFSET(sbitmap_word_word);
> + const ulong w_cleared_off = OFFSET(sbitmap_word_cleared);
> +
> + unsigned int index;
> + unsigned int nr;
> + unsigned int scanned = 0;
> + char *sbitmap_word_buf;
> +
> + sbitmap_word_buf = GETBUF(sbitmap_word_size);
> +
> + if (start >= sc->map_nr)
> + start = 0;
Question: Is "(start >= sc->depth)" correct here? Currently start is
always zero, though.
I have a plan to add range options to dump data attached to
the
sbitmap_queue.
It will allow me to go through the bitmap from any index, not only first.
> +
> + index = start >> sc->shift;
> + nr = start & ((1U << sc->shift) - 1U);
> +
> + while (scanned < sc->depth) {
> + unsigned long w_addr = sc->map_addr + (sbitmap_word_size * index);
> + unsigned long w_depth, w_word, w_cleared;
> + unsigned long word, depth;
> +
> + readmem(w_addr, KVADDR, sbitmap_word_buf, sbitmap_word_size,
"sbitmap_word",
> FAULT_ON_ERROR);
> +
> + w_depth = ULONG(sbitmap_word_buf + w_depth_off);
> + w_word = ULONG(sbitmap_word_buf + w_word_off);
> + w_cleared = ULONG(sbitmap_word_buf + w_cleared_off);
> +
> + depth = min(w_depth - nr, sc->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->shift) + nr, data))
> + return;
> +
> + nr++;
> + }
> +next:
> + nr = 0;
> + if (++index >= sc->map_nr)
> + index = 0;
> + }
> +
> + FREEBUF(sbitmap_word_buf);
> +}
> +
> +void sbitmap_for_each_set(const struct sbitmap_context *sc,
> + sbitmap_for_each_fn fn, void *data)
> +{
> + __sbitmap_for_each_set(sc, 0, fn, data);
> +}
> +
> +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;
> + char *sbq_wait_state_buf;
> + bool first;
> + int i;
> +
> + fprintf(fp, "depth = %u\n", sc->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->shift);
> + fprintf(fp, "map_nr = %u\n", sc->map_nr);
> +
> + fputs("alloc_hint = {", fp);
> + first = true;
> + for (i = 0; i < cpus; i++) {
> + ulong ptr;
> + int val;
> +
> + if (!first)
> + fprintf(fp, ", ");
> + first = false;
> +
> + ptr = kt->__per_cpu_offset[i] + sqc->alloc_hint;
> + readmem(ptr, KVADDR, &val, sizeof(val), "alloc_hint",
FAULT_ON_ERROR);
> +
> + fprintf(fp, "%u", val);
> + }
> + 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 = SIZE(sbq_wait_state);
> + wait_cnt_off = OFFSET(sbq_wait_state_wait_cnt);
> + wait_off = OFFSET(sbq_wait_state_wait);
> + list_head_off = OFFSET(wait_queue_head_head);
> +
> + sbq_wait_state_buf = GETBUF(sbq_wait_state_size);
> +
> + 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;
will remove these unused variables:
$ make clean ; make warn
...
sbitmap.c: In function ‘sbitmap_queue_show’:
sbitmap.c:342:24: warning: unused variable ‘list_head_addr’ [-Wunused-variable]
ulong wait_cnt_addr, list_head_addr;
^~~~~~~~~~~~~~
sbitmap.c:342:9: warning: unused variable ‘wait_cnt_addr’ [-Wunused-variable]
ulong wait_cnt_addr, list_head_addr;
^~~~~~~~~~~~~
fixed
> + ulong wait_cnt;
> +
> + readmem(ws_addr, KVADDR, sbq_wait_state_buf, sbq_wait_state_size,
"sbq_wait_state",
> FAULT_ON_ERROR);
> +
> + wait_cnt = INT(sbq_wait_state_buf + wait_cnt_off);
> + lh = (struct kernel_list_head *)(sbq_wait_state_buf + wait_off + list_head_off);
> +
> + fprintf(fp, "\t{ .wait_cnt = %lu, .wait = %s },\n",
> + wait_cnt, (lh->next == lh->prev) ? "inactive" :
"active");
> + }
> + fputs("}\n", fp);
> +
> + FREEBUF(sbq_wait_state_buf);
> +
> + fprintf(fp, "round_robin = %d\n", sqc->round_robin);
> + fprintf(fp, "min_shallow_depth = %u\n", sqc->min_shallow_depth);
> +}
> +
> +static void sbitmap_queue_context_load(ulong addr, struct sbitmap_queue_context
*sqc)
> +{
> + char *sbitmap_queue_buf;
> +
> + sqc->sb_addr = addr + OFFSET(sbitmap_queue_sb);
> +
> + sbitmap_queue_buf = GETBUF(SIZE(sbitmap_queue));
> + readmem(addr, KVADDR, sbitmap_queue_buf, SIZE(sbitmap_queue),
"sbitmap_queue", FAULT_ON_ERROR);
> +
> + sqc->alloc_hint = ULONG(sbitmap_queue_buf + OFFSET(sbitmap_queue_alloc_hint));
> + sqc->wake_batch = UINT(sbitmap_queue_buf + OFFSET(sbitmap_queue_wake_batch));
> + sqc->wake_index = INT(sbitmap_queue_buf + OFFSET(sbitmap_queue_wake_index));
> + sqc->ws_addr = ULONG(sbitmap_queue_buf + OFFSET(sbitmap_queue_ws));
> + sqc->ws_active = INT(sbitmap_queue_buf + OFFSET(sbitmap_queue_ws_active));
> + sqc->round_robin = BOOL(sbitmap_queue_buf + OFFSET(sbitmap_queue_round_robin));
> + sqc->min_shallow_depth = UINT(sbitmap_queue_buf +
OFFSET(sbitmap_queue_min_shallow_depth));
> +
> + FREEBUF(sbitmap_queue_buf);
> +}
> +
> +void sbitmap_context_load(ulong addr, struct sbitmap_context *sc)
> +{
> + char *sbitmap_buf;
> +
> + sbitmap_buf = GETBUF(SIZE(sbitmap));
> + readmem(addr, KVADDR, sbitmap_buf, SIZE(sbitmap), "sbitmap",
FAULT_ON_ERROR);
> +
> + sc->depth = UINT(sbitmap_buf + OFFSET(sbitmap_depth));
> + sc->shift = UINT(sbitmap_buf + OFFSET(sbitmap_shift));
> + sc->map_nr = UINT(sbitmap_buf + OFFSET(sbitmap_map_nr));
> + sc->map_addr = ULONG(sbitmap_buf + OFFSET(sbitmap_map));
> +
> + FREEBUF(sbitmap_buf);
> +}
> +
> +static bool for_each_func(unsigned int idx, void *p)
> +{
> + struct sbitmapq_ops *ops = p;
> + ulong addr = ops->addr + (ops->size * idx);
> +
> + return ops->fn(idx, addr, ops->p);
> +}
> +
> +void sbitmapq_for_each_set(ulong addr, struct sbitmapq_ops *ops)
> +{
> + struct sbitmap_queue_context sqc = {0};
> + struct sbitmap_context sc = {0};
> +
> + sbitmap_queue_context_load(addr, &sqc);
> + sbitmap_context_load(sqc.sb_addr, &sc);
> +
> + sbitmap_for_each_set(&sc, for_each_func, ops);
> +}
> +
> +static void 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);
> +}
> +
> +static bool sbitmap_data_print(unsigned int idx, ulong addr, void *p)
> +{
> + const struct sbitmapq_data *sd = p;
> + bool verbose = !!(sd->flags & VERBOSE);
> + bool members = !!(sd->flags & SBITMAPQ_DATA_FLAG_STRUCT_MEMBER);
> +
> + if (verbose) {
> + fprintf(fp, "%d (0x%08lx):\n", idx, addr);
> + if (members)
> + dump_struct_members(sd->data_name, addr, sd->radix);
> + else
> + dump_struct(sd->data_name, addr, sd->radix);
> + } else
> + fprintf(fp, "%d: 0x%08lx\n", idx, addr);
> +
> + return true;
> +}
> +
> +static void sbitmap_queue_data_dump(struct sbitmapq_data *sd)
> +{
> + struct sbitmapq_ops ops = {
> + .addr = sd->data_addr,
> + .size = sd->data_size,
> + .fn = sbitmap_data_print,
> + .p = sd
> + };
> +
> + sbitmapq_for_each_set(sd->addr, &ops);
> +}
> +
> +static void sbitmap_queue_dump(const struct sbitmapq_data *sd)
> +{
> + struct sbitmap_queue_context sqc ={0};
> + struct sbitmap_context sc = {0};
> +
> + sbitmap_queue_context_load(sd->addr, &sqc);
> + sbitmap_context_load(sqc.sb_addr, &sc);
> +
> + sbitmap_queue_show(&sqc, &sc);
> + fputc('\n', fp);
> + sbitmap_bitmap_show(&sc);
> +}
> +
> +void sbitmapq_init(void)
> +{
> + if (sb_flags & SB_FLAG_INIT)
> + return;
> +
> + STRUCT_SIZE_INIT(sbitmap_word, "sbitmap_word");
> + STRUCT_SIZE_INIT(sbitmap, "sbitmap");
> + STRUCT_SIZE_INIT(sbitmap_queue, "sbitmap_queue");
> + STRUCT_SIZE_INIT(sbq_wait_state, "sbq_wait_state");
> +
> + MEMBER_OFFSET_INIT(sbitmap_word_depth, "sbitmap_word",
"depth");
> + MEMBER_OFFSET_INIT(sbitmap_word_word, "sbitmap_word", "word");
> + MEMBER_OFFSET_INIT(sbitmap_word_cleared, "sbitmap_word",
"cleared");
> +
> + MEMBER_OFFSET_INIT(sbitmap_depth, "sbitmap", "depth");
> + MEMBER_OFFSET_INIT(sbitmap_shift, "sbitmap", "shift");
> + MEMBER_OFFSET_INIT(sbitmap_map_nr, "sbitmap", "map_nr");
> + MEMBER_OFFSET_INIT(sbitmap_map, "sbitmap", "map");
> +
> + MEMBER_OFFSET_INIT(sbitmap_queue_sb, "sbitmap_queue", "sb");
> + MEMBER_OFFSET_INIT(sbitmap_queue_alloc_hint, "sbitmap_queue",
"alloc_hint");
> + MEMBER_OFFSET_INIT(sbitmap_queue_wake_batch, "sbitmap_queue",
"wake_batch");
> + MEMBER_OFFSET_INIT(sbitmap_queue_wake_index, "sbitmap_queue",
"wake_index");
> + MEMBER_OFFSET_INIT(sbitmap_queue_ws, "sbitmap_queue", "ws");
> + MEMBER_OFFSET_INIT(sbitmap_queue_ws_active, "sbitmap_queue",
"ws_active");
> + MEMBER_OFFSET_INIT(sbitmap_queue_round_robin, "sbitmap_queue",
"round_robin");
> + MEMBER_OFFSET_INIT(sbitmap_queue_min_shallow_depth, "sbitmap_queue",
"min_shallow_depth");
> +
> + MEMBER_OFFSET_INIT(sbq_wait_state_wait_cnt, "sbq_wait_state",
"wait_cnt");
> + MEMBER_OFFSET_INIT(sbq_wait_state_wait, "sbq_wait_state",
"wait");
> +
> + if (!VALID_SIZE(sbitmap_word) ||
> + !VALID_SIZE(sbitmap) ||
> + !VALID_SIZE(sbitmap_queue) ||
> + !VALID_SIZE(sbq_wait_state) ||
> + INVALID_MEMBER(sbitmap_word_depth) ||
> + INVALID_MEMBER(sbitmap_word_word) ||
> + INVALID_MEMBER(sbitmap_word_cleared) ||
> + INVALID_MEMBER(sbitmap_depth) ||
> + INVALID_MEMBER(sbitmap_shift) ||
> + INVALID_MEMBER(sbitmap_map_nr) ||
> + INVALID_MEMBER(sbitmap_map) ||
> + INVALID_MEMBER(sbitmap_queue_sb) ||
> + INVALID_MEMBER(sbitmap_queue_alloc_hint) ||
> + INVALID_MEMBER(sbitmap_queue_wake_batch) ||
> + INVALID_MEMBER(sbitmap_queue_wake_index) ||
> + INVALID_MEMBER(sbitmap_queue_ws) ||
> + INVALID_MEMBER(sbitmap_queue_ws_active) ||
> + INVALID_MEMBER(sbitmap_queue_round_robin) ||
> + INVALID_MEMBER(sbitmap_queue_min_shallow_depth) ||
> + INVALID_MEMBER(sbq_wait_state_wait_cnt) ||
> + INVALID_MEMBER(sbq_wait_state_wait)) {
> + command_not_supported();
> + }
> +
> + sb_flags |= SB_FLAG_INIT;
> +}
> +
> +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;
> +}
> +
> +void cmd_sbitmapq(void)
> +{
> + struct sbitmapq_data sd = {0};
> + int c;
> +
> + while ((c = getopt(argcnt, args, "s:p:xdv")) != EOF) {
> + switch (c) {
> + case 's':
> + if (sd.flags & SBITMAPQ_DATA_FLAG_STRUCT_NAME)
> + error(FATAL, "-s option (%s) already entered\n", sd.data_name);
> +
> + sd.data_name = optarg;
> + sd.flags |= SBITMAPQ_DATA_FLAG_STRUCT_NAME;
> +
> + break;
> +
> + case 'p':
> + if (sd.flags & SBITMAPQ_DATA_FLAG_STRUCT_ADDR)
> + error(FATAL, "-p option (0x%lx) already entered\n", sd.data_addr);
> + else if (!IS_A_NUMBER(optarg))
> + error(FATAL, "invalid -p 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 |= SBITMAPQ_DATA_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 & SBITMAPQ_DATA_FLAG_STRUCT_NAME) &&
> + !(sd.flags & SBITMAPQ_DATA_FLAG_STRUCT_ADDR)) {
> + error(INFO, "-s option requires -p option");
> + cmd_usage(pc->curcmd, SYNOPSIS);
> + } else if ((sd.flags & SBITMAPQ_DATA_FLAG_STRUCT_ADDR) &&
> + !(sd.flags & SBITMAPQ_DATA_FLAG_STRUCT_NAME)) {
> + error(FATAL, "-p option is used with -s option only\n");
> + cmd_usage(pc->curcmd, SYNOPSIS);
> + }
> +
> + if (sd.flags & SBITMAPQ_DATA_FLAG_STRUCT_NAME) {
> + bool error_flag = false;
> +
> + if (count_chars(sd.data_name, '.') > 0)
> + sd.flags |= SBITMAPQ_DATA_FLAG_STRUCT_MEMBER;
> +
> + if (sd.flags & SBITMAPQ_DATA_FLAG_STRUCT_MEMBER) {
> + char *data_name = __get_struct_name(sd.data_name);
> +
> + sd.data_size = STRUCT_SIZE(data_name);
> + if (sd.data_size <= 0)
> + error_flag = true;
> +
> + FREEBUF(data_name);
> + } else {
> + sd.data_size = STRUCT_SIZE(sd.data_name);
> + if (sd.data_size <= 0)
> + error_flag = true;
> + }
> + if (error_flag)
> + error(FATAL, "invalid data structure reference: %s\n", sd.data_name);
> + }
The error_flag can be removed and this block can be shortened,
will change like this:
if (sd.flags & SBITMAPQ_DATA_FLAG_STRUCT_NAME) {
if (count_chars(sd.data_name, '.') > 0)
sd.flags |= SBITMAPQ_DATA_FLAG_STRUCT_MEMBER;
if (sd.flags & SBITMAPQ_DATA_FLAG_STRUCT_MEMBER) {
char *data_name = __get_struct_name(sd.data_name);
sd.data_size = STRUCT_SIZE(data_name);
FREEBUF(data_name);
} else
sd.data_size = STRUCT_SIZE(sd.data_name);
if (sd.data_size <= 0)
error(FATAL, "invalid data structure reference: %s\n",
sd.data_name);
}
Thanks,
Kazu
Agree, It looks better. Fixed.
> +
> + sbitmapq_init();
> +
> + if (sd.flags & SBITMAPQ_DATA_FLAG_STRUCT_NAME)
> + sbitmap_queue_data_dump(&sd);
> + else
> + sbitmap_queue_dump(&sd);
> +}
> --
> 2.25.1
>
>
> --
> Crash-utility mailing list
> Crash-utility(a)redhat.com
>
https://listman.redhat.com/mailman/listinfo/crash-utility Thanks,
Sergey