mirror of https://github.com/crash-utility/crash
Introduce sbitmapq command
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. Signed-off-by: Sergey Samoylenko <s.samoylenko@yadro.com>
This commit is contained in:
parent
6ecb8a23ca
commit
ac86cc3558
7
Makefile
7
Makefile
|
@ -73,7 +73,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} \
|
||||
|
@ -93,7 +93,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
|
||||
|
||||
|
@ -342,6 +342,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}
|
||||
|
||||
|
|
59
defs.h
59
defs.h
|
@ -18,6 +18,7 @@
|
|||
|
||||
#ifndef GDB_COMMON
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
@ -2150,6 +2151,23 @@ struct offset_table { /* stash of commonly-used offsets */
|
|||
long printk_safe_seq_buf_len;
|
||||
long printk_safe_seq_buf_message_lost;
|
||||
long printk_safe_seq_buf_buffer;
|
||||
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 */
|
||||
|
@ -2315,6 +2333,10 @@ struct size_table { /* stash of commonly-used sizes */
|
|||
long wait_queue_entry;
|
||||
long task_struct_state;
|
||||
long printk_safe_seq_buf_buffer;
|
||||
long sbitmap_word;
|
||||
long sbitmap;
|
||||
long sbitmap_queue;
|
||||
long sbq_wait_state;
|
||||
};
|
||||
|
||||
struct array_table {
|
||||
|
@ -2441,6 +2463,7 @@ DEF_LOADER(ushort);
|
|||
DEF_LOADER(short);
|
||||
typedef void *pointer_t;
|
||||
DEF_LOADER(pointer_t);
|
||||
DEF_LOADER(bool);
|
||||
|
||||
#define LOADER(TYPE) load_##TYPE
|
||||
|
||||
|
@ -2454,6 +2477,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
|
||||
|
||||
|
@ -2467,6 +2491,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 */
|
||||
|
||||
|
@ -4967,6 +4992,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 */
|
||||
|
@ -5580,6 +5606,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[];
|
||||
|
@ -5850,6 +5877,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);
|
||||
|
|
|
@ -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},
|
||||
|
|
103
help.c
103
help.c
|
@ -962,6 +962,109 @@ char *help_ascii[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
char *help_sbitmapq[] = {
|
||||
"sbitmapq",
|
||||
"sbitmap_queue struct contents",
|
||||
"[-s struct[.member[,member]] -a address [-v]] -[x|d] 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",
|
||||
" associated with sbitmap_queue structure. Use the",
|
||||
" \"struct.member\" format in order to display a particular",
|
||||
" member of the structure. -s option requires -a option",
|
||||
" -a 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 with iSCSI",
|
||||
" 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 -a 0xc0000000671c0000 c0000000e118c808",
|
||||
" 76: 0xc0000000671d5600",
|
||||
" 77: 0xc0000000671d5a80",
|
||||
"",
|
||||
" Dump of formatted content of structures:",
|
||||
"",
|
||||
" %s> sbitmapq -s iscsi_cmd -a 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",
|
||||
|
|
|
@ -0,0 +1,653 @@
|
|||
/* sbitmap.c
|
||||
*
|
||||
* Copyright (C) 2022 YADRO. 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"
|
||||
|
||||
#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_MEMBER (VERBOSE << 2)
|
||||
#define SBITMAPQ_DATA_FLAG_ARRAY_ADDR (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;
|
||||
|
||||
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;
|
||||
|
||||
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:a: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 'a':
|
||||
if (sd.flags & SBITMAPQ_DATA_FLAG_ARRAY_ADDR)
|
||||
error(FATAL, "-a option (0x%lx) already entered\n", sd.data_addr);
|
||||
else if (!IS_A_NUMBER(optarg))
|
||||
error(FATAL, "invalid -a 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_ARRAY_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_ARRAY_ADDR)) {
|
||||
error(INFO, "-s option requires -a option\n");
|
||||
cmd_usage(pc->curcmd, SYNOPSIS);
|
||||
} else if ((sd.flags & SBITMAPQ_DATA_FLAG_ARRAY_ADDR) &&
|
||||
!(sd.flags & SBITMAPQ_DATA_FLAG_STRUCT_NAME)) {
|
||||
error(INFO, "-a option is used with -s option only\n");
|
||||
cmd_usage(pc->curcmd, SYNOPSIS);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
sbitmapq_init();
|
||||
|
||||
if (sd.flags & SBITMAPQ_DATA_FLAG_STRUCT_NAME)
|
||||
sbitmap_queue_data_dump(&sd);
|
||||
else
|
||||
sbitmap_queue_dump(&sd);
|
||||
}
|
39
symbols.c
39
symbols.c
|
@ -10694,6 +10694,41 @@ 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));
|
||||
|
@ -10960,6 +10995,10 @@ dump_offset_table(char *spec, ulong makestruct)
|
|||
fprintf(fp, " prb_desc: %ld\n", SIZE(prb_desc));
|
||||
fprintf(fp, " printk_safe_seq_buf_buffer: %ld\n", SIZE(printk_safe_seq_buf_buffer));
|
||||
|
||||
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");
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue