[PATCH] arm64: handle vabits_actual symbol missing case
by Pavankumar Kondeti
After the commit 0d9b1ffefabe ("arm64: mm: make vabits_actual
a build time constant if possible") introduced in v5.19
Linux kernel, the crash will not find vabits_actual symbol
if if VA_BITS <= 48. Add a fallback option to initialize VA_BITS
based on the user supplied machdep option.
Tested ramdumps loading in both 6.0 and 5.15 kernels.
Signed-off-by: Pavankumar Kondeti <quic_pkondeti(a)quicinc.com>
---
arm64.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arm64.c b/arm64.c
index c3e26a3..7125458 100644
--- a/arm64.c
+++ b/arm64.c
@@ -4671,6 +4671,10 @@ arm64_calc_VA_BITS(void)
return;
} else if (arm64_set_va_bits_by_tcr()) {
return;
+ } else if (machdep->machspec->VA_BITS_ACTUAL) {
+ machdep->machspec->VA_BITS = machdep->machspec->VA_BITS_ACTUAL;
+ machdep->machspec->VA_START = _VA_START(machdep->machspec->VA_BITS_ACTUAL);
+ return;
}
if (!(sp = symbol_search("swapper_pg_dir")) &&
--
2.7.4
1 year, 11 months
[PATCH] arm64: Add fallback option when vabits_actual is missing
by Pavankumar Kondeti
After the commit 0d9b1ffefabe ("arm64: mm: make vabits_actual
a build time constant if possible") introduced in v5.19
Linux kernel, the crash will not find vabits_actual symbol.
Add a fallback option to initialize VA_BITS based on the
user supplied machdep options.
Tested ramdumps loading in both 6.0 and 5.15 kernels.
Signed-off-by: Pavankumar Kondeti <quic_pkondeti(a)quicinc.com>
---
arm64.c | 33 +++++++++++++++++++++++++--------
1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/arm64.c b/arm64.c
index c3e26a3..9d5d0bd 100644
--- a/arm64.c
+++ b/arm64.c
@@ -4588,6 +4588,27 @@ arm64_IS_VMALLOC_ADDR(ulong vaddr)
/* Return TRUE if we succeed, return FALSE on failure. */
static int
+arm64_set_va_bits_fallback(void)
+{
+ if (machdep->machspec->VA_BITS_ACTUAL) {
+ machdep->machspec->VA_BITS = machdep->machspec->VA_BITS_ACTUAL;
+ machdep->machspec->VA_START = _VA_START(machdep->machspec->VA_BITS_ACTUAL);
+ return TRUE;
+ }
+
+ if (machdep->machspec->CONFIG_ARM64_VA_BITS) {
+ /* guess */
+ machdep->machspec->VA_BITS_ACTUAL = machdep->machspec->CONFIG_ARM64_VA_BITS;
+ machdep->machspec->VA_BITS = machdep->machspec->CONFIG_ARM64_VA_BITS;
+ machdep->machspec->VA_START = _VA_START(machdep->machspec->VA_BITS_ACTUAL);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Return TRUE if we succeed, return FALSE on failure. */
+static int
arm64_set_va_bits_by_tcr(void)
{
ulong value;
@@ -4648,14 +4669,8 @@ arm64_calc_VA_BITS(void)
else {
if (arm64_set_va_bits_by_tcr()) {
/* nothing */
- } else if (machdep->machspec->VA_BITS_ACTUAL) {
- machdep->machspec->VA_BITS = machdep->machspec->VA_BITS_ACTUAL;
- machdep->machspec->VA_START = _VA_START(machdep->machspec->VA_BITS_ACTUAL);
- } else if (machdep->machspec->CONFIG_ARM64_VA_BITS) {
- /* guess */
- machdep->machspec->VA_BITS_ACTUAL = machdep->machspec->CONFIG_ARM64_VA_BITS;
- machdep->machspec->VA_BITS = machdep->machspec->CONFIG_ARM64_VA_BITS;
- machdep->machspec->VA_START = _VA_START(machdep->machspec->VA_BITS_ACTUAL);
+ } else if (arm64_set_va_bits_fallback()) {
+ /* nothing */
} else
error(FATAL, "cannot determine VA_BITS_ACTUAL\n");
}
@@ -4671,6 +4686,8 @@ arm64_calc_VA_BITS(void)
return;
} else if (arm64_set_va_bits_by_tcr()) {
return;
+ } else if (arm64_set_va_bits_fallback()) {
+ return;
}
if (!(sp = symbol_search("swapper_pg_dir")) &&
--
2.7.4
1 year, 11 months
[PATCH V5 0/2] Support VMCOREINFO export for RISCV64
by Xianting Tian
As disscussed in below patch set, the patch of 'describe VMCOREINFO export in Documentation'
need to update according to Bagas's comments.
https://lore.kernel.org/linux-riscv/22AAF52E-8CC8-4D11-99CB-88DE4D113444@...
As others patches in above patch set already applied, so this patch set only contains below two
patches.
------
Changes:
Fix commit message in patch 2: use "Document these RISCV64 exports above" instead of
"This patch just add the description of VMCOREINFO export for RISCV64."
V1 -> V2:
Remove unnecessary overline above header text in patch 2.
V2 -> V3:
Fix commit message in patch 1,2;
Use 'space' instead of 'region' for vmemmap description in patch 2.
V3 -> V4:
Remove unnecessary kernel space export:
KASAN_SHADOW_START ~ KASAN_SHADOW_END,
ADDRESS_SPACE_END
V4 -> V5:
Remove IS_ENABLED() judgement for KERNEL_LINK_ADDR in patch 1.
Xianting Tian (2):
RISC-V: Add arch_crash_save_vmcoreinfo support
Documentation: kdump: describe VMCOREINFO export for RISCV64
.../admin-guide/kdump/vmcoreinfo.rst | 29 +++++++++++++++++++
arch/riscv/kernel/Makefile | 1 +
arch/riscv/kernel/crash_core.c | 21 ++++++++++++++
3 files changed, 51 insertions(+)
create mode 100644 arch/riscv/kernel/crash_core.c
--
2.17.1
1 year, 11 months
Re: [Crash-utility] [PATCH v2 3/6] Add tree cmd support for maple tree
by lijiang
On Tue, Oct 25, 2022 at 8:39 PM <crash-utility-request(a)redhat.com> wrote:
> Date: Tue, 25 Oct 2022 20:38:22 +0800
> From: Tao Liu <ltao(a)redhat.com>
> To: crash-utility(a)redhat.com
> Subject: [Crash-utility] [PATCH v2 3/6] Add tree cmd support for maple
> tree
> Message-ID: <20221025123825.36421-4-ltao(a)redhat.com>
> Content-Type: text/plain; charset="US-ASCII"; x-default=true
>
> Maple tree is a new data structure for crash, so cmd_tree support is
> needed for users to dump and view the content of maple tree. This patch
> achieves this by porting mt_dump() and its related functions from kernel,
> and adapting them with tree cmd.
>
> We introduced a new -v arg specifically for dumping the complete
> content of maple tree:
>
> crash> tree -t maple 0xffff9034c006aec0 -v
>
> maple_tree(ffff9034c006aec0) flags 309, height 0 root 0xffff9034de70041e
>
> 0-18446744073709551615: node 0xffff9034de700400 depth 0 type 3 parent 0xffff9034c006aec1 contents:...
> 0-140112331583487: node 0xffff9034c01e8800 depth 1 type 1 parent 0xffff9034de700406 contents:...
> 0-94643156942847: (nil)
> 94643156942848-94643158024191: 0xffff9035131754c0
> 94643158024192-94643160117247: (nil)
> ...
>
> The old tree args can work as well:
>
> crash> tree -t maple -r mm_struct.mm_mt 0xffff9034c006aec0 -p
> ffff9034de70041e
> index: 0 position: root
> ffff9034c01e880c
> index: 1 position: root/0
> 0
> index: 2 position: root/0/0
> ffff9035131754c0
> index: 3 position: root/0/1
> 0
> index: 4 position: root/0/2
> ....
>
> crash> tree -t maple 0xffff9034c006aec0 -p -x -s vm_area_struct.vm_start,vm_end
> ffff9034de70041e
> index: 0 position: root
> ffff9034c01e880c
> index: 1 position: root/0
> 0
> index: 2 position: root/0/0
> ffff9035131754c0
> index: 3 position: root/0/1
> vm_start = 0x5613d3c00000,
> vm_end = 0x5613d3d08000,
> 0
> index: 4 position: root/0/2
> ...
>
> Signed-off-by: Tao Liu <ltao(a)redhat.com>
> ---
> defs.h | 5 +
> maple_tree.c | 385 +++++++++++++++++++++++++++++++++++++++++++++++++++
> tools.c | 20 ++-
> 3 files changed, 404 insertions(+), 6 deletions(-)
>
> diff --git a/defs.h b/defs.h
> index 2978cec..3f2453e 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -2191,12 +2191,15 @@ struct offset_table { /* stash of commonly-used offsets */
> long maple_arange_64_parent;
> long maple_arange_64_pivot;
> long maple_arange_64_slot;
> + long maple_arange_64_gap;
> long maple_arange_64_meta;
> long maple_range_64_parent;
> long maple_range_64_pivot;
> long maple_range_64_slot;
> + long maple_range_64_pad;
> long maple_range_64_meta;
> long maple_metadata_end;
> + long maple_metadata_gap;
> };
They have to be appended to the end of this table.
>
> struct size_table { /* stash of commonly-used sizes */
> @@ -2705,6 +2708,7 @@ struct tree_data {
> #define TREE_PARSE_MEMBER (VERBOSE << 7)
> #define TREE_READ_MEMBER (VERBOSE << 8)
> #define TREE_LINEAR_ORDER (VERBOSE << 9)
> +#define TREE_STRUCT_VERBOSE (VERBOSE << 9)
>
> #define ALIAS_RUNTIME (1)
> #define ALIAS_RCLOCAL (2)
> @@ -5576,6 +5580,7 @@ int same_file(char *, char *);
> int cleanup_memory_driver(void);
>
> void maple_init(void);
> +int do_mptree(struct tree_data *);
>
> /*
> * help.c
> diff --git a/maple_tree.c b/maple_tree.c
> index 058b769..33903cb 100644
> --- a/maple_tree.c
> +++ b/maple_tree.c
> @@ -34,6 +34,7 @@
>
> unsigned char *mt_slots = NULL;
> unsigned char *mt_pivots = NULL;
> +unsigned long mt_max[4] = {0};
>
> #define MAPLE_BUFSIZE 512
>
> @@ -791,6 +792,382 @@ void *mas_find(struct ma_state *mas, unsigned long max)
> return mas_next_entry(mas, max);
> }
>
> +/***************For cmd_tree********************/
> +
> +struct do_maple_tree_info {
> + ulong maxcount;
> + ulong count;
> + void *data;
> +};
> +
> +struct cmd_tree_info {
> + ulong index;
> + struct tree_data *td;
> +} cmd_tree_info;
> +
> +static const char spaces[] = " ";
> +
> +static void do_mt_range64(const struct maple_tree *, void *,
> + unsigned long, unsigned long, unsigned int, char *);
> +static void do_mt_arange64(const struct maple_tree *, void *,
> + unsigned long, unsigned long, unsigned int, char *);
> +static void do_mt_entry(void *, unsigned long, unsigned long, unsigned int,
> + unsigned int, char *);
> +static void do_mt_node(const struct maple_tree *, void *, unsigned long,
> + unsigned long, unsigned int, char *);
> +struct req_entry *fill_member_offsets(char *);
> +void dump_struct_members_fast(struct req_entry *, int, ulong);
> +void dump_struct_members_for_tree(struct tree_data *, int, ulong);
> +
> +static void mt_dump_range(unsigned long min, unsigned long max,
> + unsigned int depth)
> +{
> + if (min == max)
> + fprintf(fp, "%.*s%lu: ", depth * 2, spaces, min);
> + else
> + fprintf(fp, "%.*s%lu-%lu: ", depth * 2, spaces, min, max);
> +}
> +
> +static inline bool mt_is_reserved(const void *entry)
> +{
> + return ((unsigned long)entry < MAPLE_RESERVED_RANGE) &&
> + xa_is_internal(entry);
> +}
> +
> +static inline bool mte_is_leaf(const struct maple_enode *entry)
> +{
> + return ma_is_leaf(mte_node_type(entry));
> +}
> +
> +static unsigned int mt_height(const struct maple_tree *mt)
> +{
> + return (*(unsigned int *)(mt + OFFSET(maple_tree_ma_flags)) &
> + MT_FLAGS_HEIGHT_MASK)
> + >> MT_FLAGS_HEIGHT_OFFSET;
> +}
> +
> +static void dump_mt_range64(struct maple_range_64 *node)
> +{
> + int i;
> +
> + fprintf(fp, " contents: ");
> + for (i = 0; i < mt_slots[maple_range_64] - 1; i++)
> + fprintf(fp, "%p %lu ",
> + *((void **)((char *)node + OFFSET(maple_range_64_slot)) + i),
> + *((unsigned long *)((char *)node + OFFSET(maple_range_64_pivot)) + i));
> + fprintf(fp, "%p\n", *((void **)((char *)node + OFFSET(maple_range_64_slot)) + i));
> +}
> +
> +static void dump_mt_arange64(struct maple_arange_64 *node)
> +{
> + int i;
> +
> + fprintf(fp, " contents: ");
> + for (i = 0; i < mt_slots[maple_arange_64]; i++)
> + fprintf(fp, "%lu ",
> + *((unsigned long *)((char *)node + OFFSET(maple_arange_64_gap)) + i));
> +
> + fprintf(fp, "| %02X %02X| ",
> + *((unsigned char *)node + OFFSET(maple_arange_64_meta) + OFFSET(maple_metadata_end)),
> + *((unsigned char *)node + OFFSET(maple_arange_64_meta) + OFFSET(maple_metadata_gap)));
> +
> + for (i = 0; i < mt_slots[maple_arange_64] - 1; i++)
> + fprintf(fp, "%p %lu ",
> + *((void **)((char *)node + OFFSET(maple_arange_64_slot)) + i),
> + *((unsigned long *)((char *)node + OFFSET(maple_arange_64_pivot)) + i));
> + fprintf(fp, "%p\n",
> + *((void **)((char *)node + OFFSET(maple_arange_64_slot)) + i));
> +}
> +
> +static void dump_mt_entry(void *entry, unsigned long min, unsigned long max,
> + unsigned int depth)
> +{
> + mt_dump_range(min, max, depth);
> +
> + if (xa_is_value(entry))
> + fprintf(fp, "value %ld (0x%lx) [%p]\n", xa_to_value(entry),
> + xa_to_value(entry), entry);
> + else if (xa_is_zero(entry))
> + fprintf(fp, "zero (%ld)\n", xa_to_internal(entry));
> + else if (mt_is_reserved(entry))
> + fprintf(fp, "UNKNOWN ENTRY (%p)\n", entry);
> + else
> + fprintf(fp, "%p\n", entry);
> +}
> +
> +static void dump_mt_node(struct maple_node *node, char *node_data,
> + unsigned int type, unsigned long min, unsigned long max,
> + unsigned int depth)
> +{
> + mt_dump_range(min, max, depth);
> +
> + fprintf(fp, "node %p depth %d type %d parent %p", node, depth, type,
> + node ? *(struct maple_pnode **)(node_data + OFFSET(maple_node_parent))
> + : NULL);
> +}
> +
> +static void do_mt_range64(const struct maple_tree *mt, void *entry,
> + unsigned long min, unsigned long max,
> + unsigned int depth, char *path)
> +{
> + struct maple_node *m_node = mte_to_node(entry);
> + unsigned char tmp_node[MAPLE_BUFSIZE];
> + bool leaf = mte_is_leaf(entry);
> + unsigned long first = min, last;
> + int i;
> + int len = strlen(path);
> +
> + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE);
> +
> + readmem((ulonglong)m_node, KVADDR, tmp_node, SIZE(maple_node_struct),
> + "mt_dump_range64 read maple_node", FAULT_ON_ERROR);
> +
> + struct maple_range_64 *node = (struct maple_range_64 *)
> + (tmp_node + OFFSET(maple_node_mr64));
> +
> + if (cmd_tree_info.td) {
> + if (cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) {
> + dump_mt_range64(node);
> + }
> + if (cmd_tree_info.td->flags & TREE_POSITION_DISPLAY)
> + fprintf(fp, "%.*s index: %ld position: %s\n",
> + depth * 2, spaces, cmd_tree_info.index++, path);
> + }
> +
> + for (i = 0; i < mt_slots[maple_range_64]; i++) {
> + last = max;
> +
> + if (i < (mt_slots[maple_range_64] - 1))
> + last = *((unsigned long *)((char *)node + OFFSET(maple_range_64_pivot)) + i);
> + else if (!*((void **)((char *)node + OFFSET(maple_range_64_slot)) + i) &&
> + max != mt_max[mte_node_type(entry)])
> + break;
> + if (last == 0 && i > 0)
> + break;
> + if (leaf)
> + do_mt_entry(mt_slot(mt, (void **)((char *)node + OFFSET(maple_range_64_slot)), i),
> + first, last, depth + 1, i, path);
> + else if (*((void **)((char *)node + OFFSET(maple_range_64_slot)) + i)) {
> + sprintf(path + len, "/%d", i);
> + do_mt_node(mt, mt_slot(mt, (void **)((char *)node + OFFSET(maple_range_64_slot)), i),
> + first, last, depth + 1, path);
> + }
> +
> + if (last == max)
> + break;
> + if (last > max) {
> + fprintf(fp, "node %p last (%lu) > max (%lu) at pivot %d!\n",
> + node, last, max, i);
> + break;
> + }
> + first = last + 1;
> + }
> +}
> +
> +static void do_mt_arange64(const struct maple_tree *mt, void *entry,
> + unsigned long min, unsigned long max, unsigned int depth,
> + char *path)
> +{
> + struct maple_node *m_node = mte_to_node(entry);
> + unsigned char tmp_node[MAPLE_BUFSIZE];
> + bool leaf = mte_is_leaf(entry);
> + unsigned long first = min, last;
> + int i;
> + int len = strlen(path);
> +
> + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE);
> +
> + readmem((ulonglong)m_node, KVADDR, tmp_node, SIZE(maple_node_struct),
> + "mt_dump_arange64 read maple_node", FAULT_ON_ERROR);
> +
> + struct maple_arange_64 *node = (struct maple_arange_64 *)
> + (tmp_node + OFFSET(maple_node_ma64));
> +
> + if (cmd_tree_info.td) {
> + if (cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) {
> + dump_mt_arange64(node);
> + }
> + if (cmd_tree_info.td->flags & TREE_POSITION_DISPLAY)
> + fprintf(fp, "%.*s index: %ld position: %s\n",
> + depth * 2, spaces, cmd_tree_info.index++, path);
> + }
> +
> + for (i = 0; i < mt_slots[maple_arange_64]; i++) {
> + last = max;
> +
> + if (i < (mt_slots[maple_arange_64] - 1))
> + last = *((unsigned long *)((char *)node + OFFSET(maple_arange_64_pivot)) + i);
> + else if (! *((void **)((char *)node + OFFSET(maple_arange_64_slot)) + i))
> + break;
> + if (last == 0 && i > 0)
> + break;
> +
> + if (leaf)
> + do_mt_entry(mt_slot(mt, (void **)((char *)node + OFFSET(maple_arange_64_slot)), i),
> + first, last, depth + 1, i, path);
> + else if (*((void **)((char *)node + OFFSET(maple_arange_64_slot)) + i)) {
> + sprintf(path + len, "/%d", i);
> + do_mt_node(mt, mt_slot(mt, (void **)((char *)node + OFFSET(maple_arange_64_slot)), i),
> + first, last, depth + 1, path);
> + }
> +
> + if (last == max)
> + break;
> + if (last > max) {
> + fprintf(fp, "node %p last (%lu) > max (%lu) at pivot %d!\n",
> + node, last, max, i);
> + break;
> + }
> + first = last + 1;
> + }
> +}
> +
> +static void do_mt_entry(void *entry, unsigned long min, unsigned long max,
> + unsigned int depth, unsigned int index, char *path)
> +{
> + int print_radix = 0, i;
> + static struct req_entry **e = NULL;
> +
> + if (!cmd_tree_info.td)
> + return;
> +
> + if (!cmd_tree_info.td->count && cmd_tree_info.td->structname_args) {
> + /*
> + * Retrieve all members' info only once (count == 0)
> + * After last iteration all memory will be freed up
> + */
> + e = (struct req_entry **)GETBUF(sizeof(*e) * cmd_tree_info.td->structname_args);
> + for (i = 0; i < cmd_tree_info.td->structname_args; i++)
> + e[i] = fill_member_offsets(cmd_tree_info.td->structname[i]);
> + }
> +
> + cmd_tree_info.td->count++;
> +
> + if (cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) {
> + dump_mt_entry(entry, min, max, depth);
> + } else if (cmd_tree_info.td->flags & VERBOSE)
> + fprintf(fp, "%.*s%lx\n", depth * 2, spaces, (ulong)entry);
> + if (cmd_tree_info.td->flags & TREE_POSITION_DISPLAY)
> + fprintf(fp, "%.*s index: %ld position: %s/%u\n",
> + depth * 2, spaces, cmd_tree_info.index++, path, index);
> +
> + if (cmd_tree_info.td->structname) {
> + if (cmd_tree_info.td->flags & TREE_STRUCT_RADIX_10)
> + print_radix = 10;
> + else if (cmd_tree_info.td->flags & TREE_STRUCT_RADIX_16)
> + print_radix = 16;
> + else
> + print_radix = 0;
> +
> + for (i = 0; i < cmd_tree_info.td->structname_args; i++) {
> + switch (count_chars(cmd_tree_info.td->structname[i], '.')) {
> + case 0:
> + dump_struct(cmd_tree_info.td->structname[i],
> + (ulong)entry, print_radix);
> + break;
> + default:
> + if (cmd_tree_info.td->flags & TREE_PARSE_MEMBER)
> + dump_struct_members_for_tree(cmd_tree_info.td, i, (ulong)entry);
> + else if (cmd_tree_info.td->flags & TREE_READ_MEMBER)
> + dump_struct_members_fast(e[i], print_radix, (ulong)entry);
> + break;
> + }
> + }
> + }
> +}
> +
> +static void do_mt_node(const struct maple_tree *mt, void *entry,
> + unsigned long min, unsigned long max, unsigned int depth,
> + char *path)
> +{
> + struct maple_node *node = mte_to_node(entry);
> + unsigned int type = mte_node_type(entry);
> + unsigned int i;
> + char tmp_node[MAPLE_BUFSIZE];
> +
> + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE);
> +
> + readmem((ulonglong)node, KVADDR, tmp_node, SIZE(maple_node_struct),
> + "mt_dump_node read maple_node", FAULT_ON_ERROR);
> +
> + if (cmd_tree_info.td) {
> + if (cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) {
> + dump_mt_node(node, tmp_node, type, min, max, depth);
> + } else if (cmd_tree_info.td->flags & VERBOSE)
> + fprintf(fp, "%.*s%lx\n", depth * 2, spaces, (ulong)entry);
> + }
> +
> + switch (type) {
> + case maple_dense:
> + if (cmd_tree_info.td &&
> + cmd_tree_info.td->flags & TREE_POSITION_DISPLAY)
> + fprintf(fp, "%.*s index: %ld position: %s\n",
> + depth * 2, spaces, cmd_tree_info.index++, path);
> + for (i = 0; i < mt_slots[maple_dense]; i++) {
> + if (min + i > max)
> + fprintf(fp, "OUT OF RANGE: ");
> + do_mt_entry(mt_slot(mt, (void **)(tmp_node + OFFSET(maple_node_slot)), i),
> + min + i, min + i, depth, i, path);
> + }
> + break;
> + case maple_leaf_64:
> + case maple_range_64:
> + do_mt_range64(mt, entry, min, max, depth, path);
> + break;
> + case maple_arange_64:
> + do_mt_arange64(mt, entry, min, max, depth, path);
> + break;
> + default:
> + fprintf(fp, " UNKNOWN TYPE\n");
> + }
> +}
> +
> +static int do_maple_tree_traverse(ulong ptr, int is_root)
> +{
> + char path[BUFSIZE] = {0};
> + unsigned char tmp_tree[MAPLE_BUFSIZE];
> + void *entry;
> +
Here, I would recommend checking if the related structures or members
are valid, just like this:
if (!VALID_STRUCT(maple_tree_struct) ||
!VALID_STRUCT(maple_node_struct) ||
!VALID_MEMBER(maple_tree_ma_root) ...)
error(FATAL,
"maple tree does not exist or has changed its
format\n");
...
Thanks.
Lianbo
> + assert(SIZE(maple_tree_struct) <= MAPLE_BUFSIZE);
> +
> + if (!is_root) {
> + strcpy(path, "direct");
> + do_mt_node(NULL, (void *)ptr, 0,
> + mt_max[mte_node_type((struct maple_enode *)ptr)], 0, path);
> + } else {
> + readmem((ulonglong)ptr, KVADDR, tmp_tree, SIZE(maple_tree_struct),
> + "mt_dump read maple_tree", FAULT_ON_ERROR);
> + entry = *(void **)(tmp_tree + OFFSET(maple_tree_ma_root));
> +
> + if (cmd_tree_info.td &&
> + cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) {
> + fprintf(fp, "maple_tree(%lx) flags %X, height %u root %p\n\n",
> + ptr, *(unsigned int *)(tmp_tree + OFFSET(maple_tree_ma_flags)),
> + mt_height((struct maple_tree *)tmp_tree), entry);
> + }
> +
> + if (!xa_is_node(entry))
> + do_mt_entry(entry, 0, 0, 0, 0, path);
> + else if (entry) {
> + strcpy(path, "root");
> + do_mt_node((struct maple_tree *)tmp_tree, entry, 0,
> + mt_max[mte_node_type(entry)], 0, path);
> + }
> + }
> + return 0;
> +}
> +
> +int do_mptree(struct tree_data *td)
> +{
> + int is_root = !(td->flags & TREE_NODE_POINTER);
> +
> + memset(&cmd_tree_info, 0, sizeof(cmd_tree_info));
> + cmd_tree_info.td = td;
> + do_maple_tree_traverse(td->start, is_root);
> +
> + return 0;
> +}
> +
> /***********************************************/
> void maple_init(void)
> {
> @@ -810,14 +1187,17 @@ void maple_init(void)
> MEMBER_OFFSET_INIT(maple_arange_64_parent, "maple_arange_64", "parent");
> MEMBER_OFFSET_INIT(maple_arange_64_pivot, "maple_arange_64", "pivot");
> MEMBER_OFFSET_INIT(maple_arange_64_slot, "maple_arange_64", "slot");
> + MEMBER_OFFSET_INIT(maple_arange_64_gap, "maple_arange_64", "gap");
> MEMBER_OFFSET_INIT(maple_arange_64_meta, "maple_arange_64", "meta");
>
> MEMBER_OFFSET_INIT(maple_range_64_parent, "maple_range_64", "parent");
> MEMBER_OFFSET_INIT(maple_range_64_pivot, "maple_range_64", "pivot");
> MEMBER_OFFSET_INIT(maple_range_64_slot, "maple_range_64", "slot");
> + MEMBER_OFFSET_INIT(maple_range_64_pad, "maple_range_64", "pad");
> MEMBER_OFFSET_INIT(maple_range_64_meta, "maple_range_64", "meta");
>
> MEMBER_OFFSET_INIT(maple_metadata_end, "maple_metadata", "end");
> + MEMBER_OFFSET_INIT(maple_metadata_gap, "maple_metadata", "gap");
>
> array_len = get_array_length("mt_slots", NULL, sizeof(char));
> mt_slots = calloc(array_len, sizeof(char));
> @@ -830,4 +1210,9 @@ void maple_init(void)
> readmem(symbol_value("mt_pivots"), KVADDR, mt_pivots,
> array_len * sizeof(char), "maple_init read mt_pivots",
> FAULT_ON_ERROR);
> +
> + mt_max[maple_dense] = mt_slots[maple_dense];
> + mt_max[maple_leaf_64] = ULONG_MAX;
> + mt_max[maple_range_64] = ULONG_MAX;
> + mt_max[maple_arange_64] = ULONG_MAX;
> }
> \ No newline at end of file
> diff --git a/tools.c b/tools.c
> index 39306c1..3cb93c1 100644
> --- a/tools.c
> +++ b/tools.c
> @@ -30,7 +30,7 @@ static void dealloc_hq_entry(struct hq_entry *);
> static void show_options(void);
> static void dump_struct_members(struct list_data *, int, ulong);
> static void rbtree_iteration(ulong, struct tree_data *, char *);
> -static void dump_struct_members_for_tree(struct tree_data *, int, ulong);
> +void dump_struct_members_for_tree(struct tree_data *, int, ulong);
>
> struct req_entry {
> char *arg, *name, **member;
> @@ -40,8 +40,8 @@ struct req_entry {
> };
>
> static void print_value(struct req_entry *, unsigned int, ulong, unsigned int);
> -static struct req_entry *fill_member_offsets(char *);
> -static void dump_struct_members_fast(struct req_entry *, int, ulong);
> +struct req_entry *fill_member_offsets(char *);
> +void dump_struct_members_fast(struct req_entry *, int, ulong);
>
> FILE *
> set_error(char *target)
> @@ -3666,7 +3666,7 @@ dump_struct_members_fast(struct req_entry *e, int radix, ulong p)
> }
> }
>
> -static struct req_entry *
> +struct req_entry *
> fill_member_offsets(char *arg)
> {
> int j;
> @@ -4307,6 +4307,7 @@ dump_struct_members(struct list_data *ld, int idx, ulong next)
> #define RADIXTREE_REQUEST (0x1)
> #define RBTREE_REQUEST (0x2)
> #define XARRAY_REQUEST (0x4)
> +#define MAPLE_REQUEST (0x8)
>
> void
> cmd_tree()
> @@ -4324,11 +4325,11 @@ cmd_tree()
> td = &tree_data;
> BZERO(td, sizeof(struct tree_data));
>
> - while ((c = getopt(argcnt, args, "xdt:r:o:s:S:plN")) != EOF) {
> + while ((c = getopt(argcnt, args, "xdt:r:o:s:S:plNv")) != EOF) {
> switch (c)
> {
> case 't':
> - if (type_flag & (RADIXTREE_REQUEST|RBTREE_REQUEST|XARRAY_REQUEST)) {
> + if (type_flag & (RADIXTREE_REQUEST|RBTREE_REQUEST|XARRAY_REQUEST|MAPLE_REQUEST)) {
> error(INFO, "multiple tree types may not be entered\n");
> cmd_usage(pc->curcmd, SYNOPSIS);
> }
> @@ -4342,6 +4343,8 @@ cmd_tree()
> type_flag = RBTREE_REQUEST;
> else if (STRNEQ(optarg, "x"))
> type_flag = XARRAY_REQUEST;
> + else if (STRNEQ(optarg, "m"))
> + type_flag = MAPLE_REQUEST;
> else {
> error(INFO, "invalid tree type: %s\n", optarg);
> cmd_usage(pc->curcmd, SYNOPSIS);
> @@ -4417,6 +4420,9 @@ cmd_tree()
> "-d and -x are mutually exclusive\n");
> td->flags |= TREE_STRUCT_RADIX_10;
> break;
> + case 'v':
> + td->flags |= TREE_STRUCT_VERBOSE;
> + break;
> default:
> argerrs++;
> break;
> @@ -4532,6 +4538,8 @@ next_arg:
> do_rdtree(td);
> else if (type_flag & XARRAY_REQUEST)
> do_xatree(td);
> + else if (type_flag & MAPLE_REQUEST)
> + do_mptree(td);
> else
> do_rbtree(td);
> hq_close();
> --
> 2.33.1
1 year, 11 months
Re: [Crash-utility] [PATCH v2 5/6] Add do_maple_tree support for maple tree
by lijiang
On Tue, Oct 25, 2022 at 8:39 PM <crash-utility-request(a)redhat.com> wrote:
> Date: Tue, 25 Oct 2022 20:38:24 +0800
> From: Tao Liu <ltao(a)redhat.com>
> To: crash-utility(a)redhat.com
> Subject: [Crash-utility] [PATCH v2 5/6] Add do_maple_tree support for
> maple tree
> Message-ID: <20221025123825.36421-6-ltao(a)redhat.com>
> Content-Type: text/plain; charset="US-ASCII"; x-default=true
>
> do_maple_tree() is similar to do_radix_tree() and do_xarray(), which
> takes the same do_maple_tree_traverse entry as tree cmd. Currently
> do_maple_tree() is not called by any other functions, we reserve it
> for future use.
>
> Signed-off-by: Tao Liu <ltao(a)redhat.com>
> ---
> defs.h | 6 +++
> maple_tree.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 155 insertions(+)
>
> diff --git a/defs.h b/defs.h
> index 3f2453e..827e561 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -5581,6 +5581,12 @@ int cleanup_memory_driver(void);
>
> void maple_init(void);
> int do_mptree(struct tree_data *);
> +ulong do_maple_tree(ulong, int, struct list_pair *);
> +#define MAPLE_TREE_COUNT (1)
> +#define MAPLE_TREE_SEARCH (2)
> +#define MAPLE_TREE_DUMP (3)
> +#define MAPLE_TREE_GATHER (4)
> +#define MAPLE_TREE_DUMP_CB (5)
>
> /*
> * help.c
> diff --git a/maple_tree.c b/maple_tree.c
> index 33903cb..e8a287a 100644
> --- a/maple_tree.c
> +++ b/maple_tree.c
> @@ -805,6 +805,13 @@ struct cmd_tree_info {
> struct tree_data *td;
> } cmd_tree_info;
>
> +struct maple_tree_ops {
> + void (*entry)(ulong node, ulong slot, const char *path,
> + ulong index, void *private);
> + uint radix;
> + void *private;
> +} maple_tree_ops;
> +
> static const char spaces[] = " ";
>
> static void do_mt_range64(const struct maple_tree *, void *,
> @@ -1028,6 +1035,10 @@ static void do_mt_entry(void *entry, unsigned long min, unsigned long max,
> int print_radix = 0, i;
> static struct req_entry **e = NULL;
>
> + if (maple_tree_ops.entry)
> + maple_tree_ops.entry((ulong)entry, (ulong)entry, path, max,
> + maple_tree_ops.private);
> +
> if (!cmd_tree_info.td)
> return;
>
> @@ -1162,12 +1173,150 @@ int do_mptree(struct tree_data *td)
> int is_root = !(td->flags & TREE_NODE_POINTER);
>
> memset(&cmd_tree_info, 0, sizeof(cmd_tree_info));
> + memset(&maple_tree_ops, 0, sizeof(maple_tree_ops));
See comments below.
> cmd_tree_info.td = td;
> do_maple_tree_traverse(td->start, is_root);
>
> return 0;
> }
>
> +/*************For do_maple_tree*****************/
> +static void do_maple_tree_count(ulong node, ulong slot, const char *path,
> + ulong index, void *private)
> +{
> + struct do_maple_tree_info *info = private;
> + info->count++;
> +}
> +
> +static void do_maple_tree_search(ulong node, ulong slot, const char *path,
> + ulong index, void *private)
> +{
> + struct do_maple_tree_info *info = private;
> + struct list_pair *rtp = info->data;
> +
> + if (rtp->index == index) {
> + rtp->value = (void *)slot;
> + info->count = 1;
> + }
> +}
> +
> +static void do_maple_tree_dump(ulong node, ulong slot, const char *path,
> + ulong index, void *private)
> +{
> + struct do_maple_tree_info *info = private;
> + fprintf(fp, "[%lu] %lx\n", index, slot);
> + info->count++;
> +}
> +
> +static void do_maple_tree_gather(ulong node, ulong slot, const char *path,
> + ulong index, void *private)
> +{
> + struct do_maple_tree_info *info = private;
> + struct list_pair *rtp = info->data;
> +
> + if (info->maxcount) {
> + rtp[info->count].index = index;
> + rtp[info->count].value = (void *)slot;
> +
> + info->count++;
> + info->maxcount--;
> + }
> +}
> +
> +static void do_maple_tree_dump_cb(ulong node, ulong slot, const char *path,
> + ulong index, void *private)
> +{
> + struct do_maple_tree_info *info = private;
> + struct list_pair *rtp = info->data;
> + int (*cb)(ulong) = rtp->value;
> +
> + /* Caller defined operation */
> + if (!cb(slot)) {
> + error(FATAL, "do_maple_tree: callback "
> + "operation failed: entry: %ld item: %lx\n",
> + info->count, slot);
> + }
> + info->count++;
> +}
> +
> +/*
> + * do_maple_tree argument usage:
> + *
> + * root: Address of a maple_tree_root structure
> + *
> + * flag: MAPLE_TREE_COUNT - Return the number of entries in the tree.
> + * MAPLE_TREE_SEARCH - Search for an entry at rtp->index; if found,
> + * store the entry in rtp->value and return a count of 1; otherwise
> + * return a count of 0.
> + * MAPLE_TREE_DUMP - Dump all existing index/value pairs.
> + * MAPLE_TREE_GATHER - Store all existing index/value pairs in the
> + * passed-in array of list_pair structs starting at rtp,
> + * returning the count of entries stored; the caller can/should
> + * limit the number of returned entries by putting the array size
> + * (max count) in the rtp->index field of the first structure
> + * in the passed-in array.
> + * MAPLE_TREE_DUMP_CB - Similar with MAPLE_TREE_DUMP, but for each
> + * maple tree entry, a user defined callback at rtp->value will
> + * be invoked.
> + *
> + * rtp: Unused by MAPLE_TREE_COUNT and MAPLE_TREE_DUMP.
^^^
> + * A pointer to a list_pair structure for MAPLE_TREE_SEARCH.
> + * A pointer to an array of list_pair structures for
> + * MAPLE_TREE_GATHER; the dimension (max count) of the array may
> + * be stored in the index field of the first structure to avoid
> + * any chance of an overrun.
> + * For MAPLE_TREE_DUMP_CB, the rtp->value must be initialized as a
> + * callback function. The callback prototype must be: int (*)(ulong);
> + */
> +ulong
> +do_maple_tree(ulong root, int flag, struct list_pair *rtp)
The parameter name "rtp" looks a bit weird, could you please replace
the "rtp" with the "lp" and update the above comment?
> +{
> + struct do_maple_tree_info info = {
> + .count = 0,
> + .data = rtp,
Ditto.
> + };
> +
> + memset(&maple_tree_ops, 0, sizeof(maple_tree_ops));
> + memset(&cmd_tree_info, 0, sizeof(cmd_tree_info));
> + maple_tree_ops.private = &info;
Think about it again. It could be good to use a local variable and
eventually pass the ops parameter to do_maple_tree_traverse(). Just
like:
//filesys.c
struct do_radix_tree_info info = {
.count = 0,
.data = rtp,
};
struct radix_tree_ops ops = {
.radix = 16,
.private = &info,
};
> +
> + switch (flag)
> + {
> + case MAPLE_TREE_COUNT:
> + maple_tree_ops.entry = do_maple_tree_count;
> + break;
> +
> + case MAPLE_TREE_SEARCH:
> + maple_tree_ops.entry = do_maple_tree_search;
> + break;
> +
> + case MAPLE_TREE_DUMP:
> + maple_tree_ops.entry = do_maple_tree_dump;
> + break;
> +
> + case MAPLE_TREE_GATHER:
> + if (!(info.maxcount = rtp->index))
> + info.maxcount = (ulong)(-1); /* caller beware */
> +
> + maple_tree_ops.entry = do_maple_tree_gather;
> + break;
> +
> + case MAPLE_TREE_DUMP_CB:
> + if (rtp->value == NULL) {
> + error(FATAL, "do_maple_tree: need set callback function");
> + return -EINVAL;
The above "return" seems to be redundant.
Thanks.
Lianbo
> + }
> + maple_tree_ops.entry = do_maple_tree_dump_cb;
> + break;
> +
> + default:
> + error(FATAL, "do_maple_tree: invalid flag: %lx\n", flag);
> + }
> +
> + do_maple_tree_traverse(root, true);
> + return info.count;
> +}
> +
> /***********************************************/
> void maple_init(void)
> {
> --
> 2.33.1
1 year, 11 months
Re: [Crash-utility] [PATCH v2 3/6] Add tree cmd support for maple tree
by lijiang
> Date: Fri, 28 Oct 2022 11:28:10 +0800
> From: Tao Liu <ltao(a)redhat.com>
> To: crash-utility(a)redhat.com
> Subject: Re: [Crash-utility] [PATCH v2 3/6] Add tree cmd support for
> maple tree
> Message-ID:
> <CAO7dBbVL_er-hA8LtXs3Cz8GMcZAQDjVMGNHRVAc8LyekDKtrQ(a)mail.gmail.com>
> Content-Type: text/plain; charset="UTF-8"
>
> On Tue, Oct 25, 2022 at 8:38 PM Tao Liu <ltao(a)redhat.com> wrote:
> >
> > Maple tree is a new data structure for crash, so cmd_tree support is
> > needed for users to dump and view the content of maple tree. This patch
> > achieves this by porting mt_dump() and its related functions from kernel,
> > and adapting them with tree cmd.
> >
> > We introduced a new -v arg specifically for dumping the complete
> > content of maple tree:
> >
> > crash> tree -t maple 0xffff9034c006aec0 -v
> >
> > maple_tree(ffff9034c006aec0) flags 309, height 0 root 0xffff9034de70041e
> >
> > 0-18446744073709551615: node 0xffff9034de700400 depth 0 type 3 parent 0xffff9034c006aec1 contents:...
> > 0-140112331583487: node 0xffff9034c01e8800 depth 1 type 1 parent 0xffff9034de700406 contents:...
> > 0-94643156942847: (nil)
> > 94643156942848-94643158024191: 0xffff9035131754c0
> > 94643158024192-94643160117247: (nil)
> > ...
> >
> > The old tree args can work as well:
> >
> > crash> tree -t maple -r mm_struct.mm_mt 0xffff9034c006aec0 -p
> > ffff9034de70041e
> > index: 0 position: root
> > ffff9034c01e880c
> > index: 1 position: root/0
> > 0
> > index: 2 position: root/0/0
> > ffff9035131754c0
> > index: 3 position: root/0/1
> > 0
> > index: 4 position: root/0/2
> > ....
> >
> > crash> tree -t maple 0xffff9034c006aec0 -p -x -s vm_area_struct.vm_start,vm_end
> > ffff9034de70041e
> > index: 0 position: root
> > ffff9034c01e880c
> > index: 1 position: root/0
> > 0
> > index: 2 position: root/0/0
> > ffff9035131754c0
> > index: 3 position: root/0/1
> > vm_start = 0x5613d3c00000,
> > vm_end = 0x5613d3d08000,
> > 0
> > index: 4 position: root/0/2
> > ...
> >
> > Signed-off-by: Tao Liu <ltao(a)redhat.com>
> > ---
> > defs.h | 5 +
> > maple_tree.c | 385 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > tools.c | 20 ++-
> > 3 files changed, 404 insertions(+), 6 deletions(-)
> >
> > diff --git a/defs.h b/defs.h
> > index 2978cec..3f2453e 100644
> > --- a/defs.h
> > +++ b/defs.h
> > @@ -2191,12 +2191,15 @@ struct offset_table { /* stash of commonly-used offsets */
> > long maple_arange_64_parent;
> > long maple_arange_64_pivot;
> > long maple_arange_64_slot;
> > + long maple_arange_64_gap;
> > long maple_arange_64_meta;
> > long maple_range_64_parent;
> > long maple_range_64_pivot;
> > long maple_range_64_slot;
> > + long maple_range_64_pad;
> > long maple_range_64_meta;
> > long maple_metadata_end;
> > + long maple_metadata_gap;
> > };
> >
> > struct size_table { /* stash of commonly-used sizes */
> > @@ -2705,6 +2708,7 @@ struct tree_data {
> > #define TREE_PARSE_MEMBER (VERBOSE << 7)
> > #define TREE_READ_MEMBER (VERBOSE << 8)
> > #define TREE_LINEAR_ORDER (VERBOSE << 9)
> > +#define TREE_STRUCT_VERBOSE (VERBOSE << 9)
>
> Sorry, the (VERBOSE << 9) should be (VERBOSE << 10)
>
In addition, can you also replace the assert() with "if() error(FATAL, ...)" ?
Thanks.
Lianbo
> >
> > #define ALIAS_RUNTIME (1)
> > #define ALIAS_RCLOCAL (2)
> > @@ -5576,6 +5580,7 @@ int same_file(char *, char *);
> > int cleanup_memory_driver(void);
> >
> > void maple_init(void);
> > +int do_mptree(struct tree_data *);
> >
> > /*
> > * help.c
> > diff --git a/maple_tree.c b/maple_tree.c
> > index 058b769..33903cb 100644
> > --- a/maple_tree.c
> > +++ b/maple_tree.c
> > @@ -34,6 +34,7 @@
> >
> > unsigned char *mt_slots = NULL;
> > unsigned char *mt_pivots = NULL;
> > +unsigned long mt_max[4] = {0};
> >
> > #define MAPLE_BUFSIZE 512
> >
> > @@ -791,6 +792,382 @@ void *mas_find(struct ma_state *mas, unsigned long max)
> > return mas_next_entry(mas, max);
> > }
> >
> > +/***************For cmd_tree********************/
> > +
> > +struct do_maple_tree_info {
> > + ulong maxcount;
> > + ulong count;
> > + void *data;
> > +};
> > +
> > +struct cmd_tree_info {
> > + ulong index;
> > + struct tree_data *td;
> > +} cmd_tree_info;
> > +
> > +static const char spaces[] = " ";
> > +
> > +static void do_mt_range64(const struct maple_tree *, void *,
> > + unsigned long, unsigned long, unsigned int, char *);
> > +static void do_mt_arange64(const struct maple_tree *, void *,
> > + unsigned long, unsigned long, unsigned int, char *);
> > +static void do_mt_entry(void *, unsigned long, unsigned long, unsigned int,
> > + unsigned int, char *);
> > +static void do_mt_node(const struct maple_tree *, void *, unsigned long,
> > + unsigned long, unsigned int, char *);
> > +struct req_entry *fill_member_offsets(char *);
> > +void dump_struct_members_fast(struct req_entry *, int, ulong);
> > +void dump_struct_members_for_tree(struct tree_data *, int, ulong);
> > +
> > +static void mt_dump_range(unsigned long min, unsigned long max,
> > + unsigned int depth)
> > +{
> > + if (min == max)
> > + fprintf(fp, "%.*s%lu: ", depth * 2, spaces, min);
> > + else
> > + fprintf(fp, "%.*s%lu-%lu: ", depth * 2, spaces, min, max);
> > +}
> > +
> > +static inline bool mt_is_reserved(const void *entry)
> > +{
> > + return ((unsigned long)entry < MAPLE_RESERVED_RANGE) &&
> > + xa_is_internal(entry);
> > +}
> > +
> > +static inline bool mte_is_leaf(const struct maple_enode *entry)
> > +{
> > + return ma_is_leaf(mte_node_type(entry));
> > +}
> > +
> > +static unsigned int mt_height(const struct maple_tree *mt)
> > +{
> > + return (*(unsigned int *)(mt + OFFSET(maple_tree_ma_flags)) &
> > + MT_FLAGS_HEIGHT_MASK)
> > + >> MT_FLAGS_HEIGHT_OFFSET;
> > +}
> > +
> > +static void dump_mt_range64(struct maple_range_64 *node)
> > +{
> > + int i;
> > +
> > + fprintf(fp, " contents: ");
> > + for (i = 0; i < mt_slots[maple_range_64] - 1; i++)
> > + fprintf(fp, "%p %lu ",
> > + *((void **)((char *)node + OFFSET(maple_range_64_slot)) + i),
> > + *((unsigned long *)((char *)node + OFFSET(maple_range_64_pivot)) + i));
> > + fprintf(fp, "%p\n", *((void **)((char *)node + OFFSET(maple_range_64_slot)) + i));
> > +}
> > +
> > +static void dump_mt_arange64(struct maple_arange_64 *node)
> > +{
> > + int i;
> > +
> > + fprintf(fp, " contents: ");
> > + for (i = 0; i < mt_slots[maple_arange_64]; i++)
> > + fprintf(fp, "%lu ",
> > + *((unsigned long *)((char *)node + OFFSET(maple_arange_64_gap)) + i));
> > +
> > + fprintf(fp, "| %02X %02X| ",
> > + *((unsigned char *)node + OFFSET(maple_arange_64_meta) + OFFSET(maple_metadata_end)),
> > + *((unsigned char *)node + OFFSET(maple_arange_64_meta) + OFFSET(maple_metadata_gap)));
> > +
> > + for (i = 0; i < mt_slots[maple_arange_64] - 1; i++)
> > + fprintf(fp, "%p %lu ",
> > + *((void **)((char *)node + OFFSET(maple_arange_64_slot)) + i),
> > + *((unsigned long *)((char *)node + OFFSET(maple_arange_64_pivot)) + i));
> > + fprintf(fp, "%p\n",
> > + *((void **)((char *)node + OFFSET(maple_arange_64_slot)) + i));
> > +}
> > +
> > +static void dump_mt_entry(void *entry, unsigned long min, unsigned long max,
> > + unsigned int depth)
> > +{
> > + mt_dump_range(min, max, depth);
> > +
> > + if (xa_is_value(entry))
> > + fprintf(fp, "value %ld (0x%lx) [%p]\n", xa_to_value(entry),
> > + xa_to_value(entry), entry);
> > + else if (xa_is_zero(entry))
> > + fprintf(fp, "zero (%ld)\n", xa_to_internal(entry));
> > + else if (mt_is_reserved(entry))
> > + fprintf(fp, "UNKNOWN ENTRY (%p)\n", entry);
> > + else
> > + fprintf(fp, "%p\n", entry);
> > +}
> > +
> > +static void dump_mt_node(struct maple_node *node, char *node_data,
> > + unsigned int type, unsigned long min, unsigned long max,
> > + unsigned int depth)
> > +{
> > + mt_dump_range(min, max, depth);
> > +
> > + fprintf(fp, "node %p depth %d type %d parent %p", node, depth, type,
> > + node ? *(struct maple_pnode **)(node_data + OFFSET(maple_node_parent))
> > + : NULL);
> > +}
> > +
> > +static void do_mt_range64(const struct maple_tree *mt, void *entry,
> > + unsigned long min, unsigned long max,
> > + unsigned int depth, char *path)
> > +{
> > + struct maple_node *m_node = mte_to_node(entry);
> > + unsigned char tmp_node[MAPLE_BUFSIZE];
> > + bool leaf = mte_is_leaf(entry);
> > + unsigned long first = min, last;
> > + int i;
> > + int len = strlen(path);
> > +
> > + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE);
> > +
> > + readmem((ulonglong)m_node, KVADDR, tmp_node, SIZE(maple_node_struct),
> > + "mt_dump_range64 read maple_node", FAULT_ON_ERROR);
> > +
> > + struct maple_range_64 *node = (struct maple_range_64 *)
> > + (tmp_node + OFFSET(maple_node_mr64));
> > +
> > + if (cmd_tree_info.td) {
> > + if (cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) {
> > + dump_mt_range64(node);
> > + }
> > + if (cmd_tree_info.td->flags & TREE_POSITION_DISPLAY)
> > + fprintf(fp, "%.*s index: %ld position: %s\n",
> > + depth * 2, spaces, cmd_tree_info.index++, path);
> > + }
> > +
> > + for (i = 0; i < mt_slots[maple_range_64]; i++) {
> > + last = max;
> > +
> > + if (i < (mt_slots[maple_range_64] - 1))
> > + last = *((unsigned long *)((char *)node + OFFSET(maple_range_64_pivot)) + i);
> > + else if (!*((void **)((char *)node + OFFSET(maple_range_64_slot)) + i) &&
> > + max != mt_max[mte_node_type(entry)])
> > + break;
> > + if (last == 0 && i > 0)
> > + break;
> > + if (leaf)
> > + do_mt_entry(mt_slot(mt, (void **)((char *)node + OFFSET(maple_range_64_slot)), i),
> > + first, last, depth + 1, i, path);
> > + else if (*((void **)((char *)node + OFFSET(maple_range_64_slot)) + i)) {
> > + sprintf(path + len, "/%d", i);
> > + do_mt_node(mt, mt_slot(mt, (void **)((char *)node + OFFSET(maple_range_64_slot)), i),
> > + first, last, depth + 1, path);
> > + }
> > +
> > + if (last == max)
> > + break;
> > + if (last > max) {
> > + fprintf(fp, "node %p last (%lu) > max (%lu) at pivot %d!\n",
> > + node, last, max, i);
> > + break;
> > + }
> > + first = last + 1;
> > + }
> > +}
> > +
> > +static void do_mt_arange64(const struct maple_tree *mt, void *entry,
> > + unsigned long min, unsigned long max, unsigned int depth,
> > + char *path)
> > +{
> > + struct maple_node *m_node = mte_to_node(entry);
> > + unsigned char tmp_node[MAPLE_BUFSIZE];
> > + bool leaf = mte_is_leaf(entry);
> > + unsigned long first = min, last;
> > + int i;
> > + int len = strlen(path);
> > +
> > + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE);
> > +
> > + readmem((ulonglong)m_node, KVADDR, tmp_node, SIZE(maple_node_struct),
> > + "mt_dump_arange64 read maple_node", FAULT_ON_ERROR);
> > +
> > + struct maple_arange_64 *node = (struct maple_arange_64 *)
> > + (tmp_node + OFFSET(maple_node_ma64));
> > +
> > + if (cmd_tree_info.td) {
> > + if (cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) {
> > + dump_mt_arange64(node);
> > + }
> > + if (cmd_tree_info.td->flags & TREE_POSITION_DISPLAY)
> > + fprintf(fp, "%.*s index: %ld position: %s\n",
> > + depth * 2, spaces, cmd_tree_info.index++, path);
> > + }
> > +
> > + for (i = 0; i < mt_slots[maple_arange_64]; i++) {
> > + last = max;
> > +
> > + if (i < (mt_slots[maple_arange_64] - 1))
> > + last = *((unsigned long *)((char *)node + OFFSET(maple_arange_64_pivot)) + i);
> > + else if (! *((void **)((char *)node + OFFSET(maple_arange_64_slot)) + i))
> > + break;
> > + if (last == 0 && i > 0)
> > + break;
> > +
> > + if (leaf)
> > + do_mt_entry(mt_slot(mt, (void **)((char *)node + OFFSET(maple_arange_64_slot)), i),
> > + first, last, depth + 1, i, path);
> > + else if (*((void **)((char *)node + OFFSET(maple_arange_64_slot)) + i)) {
> > + sprintf(path + len, "/%d", i);
> > + do_mt_node(mt, mt_slot(mt, (void **)((char *)node + OFFSET(maple_arange_64_slot)), i),
> > + first, last, depth + 1, path);
> > + }
> > +
> > + if (last == max)
> > + break;
> > + if (last > max) {
> > + fprintf(fp, "node %p last (%lu) > max (%lu) at pivot %d!\n",
> > + node, last, max, i);
> > + break;
> > + }
> > + first = last + 1;
> > + }
> > +}
> > +
> > +static void do_mt_entry(void *entry, unsigned long min, unsigned long max,
> > + unsigned int depth, unsigned int index, char *path)
> > +{
> > + int print_radix = 0, i;
> > + static struct req_entry **e = NULL;
> > +
> > + if (!cmd_tree_info.td)
> > + return;
> > +
> > + if (!cmd_tree_info.td->count && cmd_tree_info.td->structname_args) {
> > + /*
> > + * Retrieve all members' info only once (count == 0)
> > + * After last iteration all memory will be freed up
> > + */
> > + e = (struct req_entry **)GETBUF(sizeof(*e) * cmd_tree_info.td->structname_args);
> > + for (i = 0; i < cmd_tree_info.td->structname_args; i++)
> > + e[i] = fill_member_offsets(cmd_tree_info.td->structname[i]);
> > + }
> > +
> > + cmd_tree_info.td->count++;
> > +
> > + if (cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) {
> > + dump_mt_entry(entry, min, max, depth);
> > + } else if (cmd_tree_info.td->flags & VERBOSE)
> > + fprintf(fp, "%.*s%lx\n", depth * 2, spaces, (ulong)entry);
> > + if (cmd_tree_info.td->flags & TREE_POSITION_DISPLAY)
> > + fprintf(fp, "%.*s index: %ld position: %s/%u\n",
> > + depth * 2, spaces, cmd_tree_info.index++, path, index);
> > +
> > + if (cmd_tree_info.td->structname) {
> > + if (cmd_tree_info.td->flags & TREE_STRUCT_RADIX_10)
> > + print_radix = 10;
> > + else if (cmd_tree_info.td->flags & TREE_STRUCT_RADIX_16)
> > + print_radix = 16;
> > + else
> > + print_radix = 0;
> > +
> > + for (i = 0; i < cmd_tree_info.td->structname_args; i++) {
> > + switch (count_chars(cmd_tree_info.td->structname[i], '.')) {
> > + case 0:
> > + dump_struct(cmd_tree_info.td->structname[i],
> > + (ulong)entry, print_radix);
> > + break;
> > + default:
> > + if (cmd_tree_info.td->flags & TREE_PARSE_MEMBER)
> > + dump_struct_members_for_tree(cmd_tree_info.td, i, (ulong)entry);
> > + else if (cmd_tree_info.td->flags & TREE_READ_MEMBER)
> > + dump_struct_members_fast(e[i], print_radix, (ulong)entry);
> > + break;
> > + }
> > + }
> > + }
> > +}
> > +
> > +static void do_mt_node(const struct maple_tree *mt, void *entry,
> > + unsigned long min, unsigned long max, unsigned int depth,
> > + char *path)
> > +{
> > + struct maple_node *node = mte_to_node(entry);
> > + unsigned int type = mte_node_type(entry);
> > + unsigned int i;
> > + char tmp_node[MAPLE_BUFSIZE];
> > +
> > + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE);
> > +
> > + readmem((ulonglong)node, KVADDR, tmp_node, SIZE(maple_node_struct),
> > + "mt_dump_node read maple_node", FAULT_ON_ERROR);
> > +
> > + if (cmd_tree_info.td) {
> > + if (cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) {
> > + dump_mt_node(node, tmp_node, type, min, max, depth);
> > + } else if (cmd_tree_info.td->flags & VERBOSE)
> > + fprintf(fp, "%.*s%lx\n", depth * 2, spaces, (ulong)entry);
> > + }
> > +
> > + switch (type) {
> > + case maple_dense:
> > + if (cmd_tree_info.td &&
> > + cmd_tree_info.td->flags & TREE_POSITION_DISPLAY)
> > + fprintf(fp, "%.*s index: %ld position: %s\n",
> > + depth * 2, spaces, cmd_tree_info.index++, path);
> > + for (i = 0; i < mt_slots[maple_dense]; i++) {
> > + if (min + i > max)
> > + fprintf(fp, "OUT OF RANGE: ");
> > + do_mt_entry(mt_slot(mt, (void **)(tmp_node + OFFSET(maple_node_slot)), i),
> > + min + i, min + i, depth, i, path);
> > + }
> > + break;
> > + case maple_leaf_64:
> > + case maple_range_64:
> > + do_mt_range64(mt, entry, min, max, depth, path);
> > + break;
> > + case maple_arange_64:
> > + do_mt_arange64(mt, entry, min, max, depth, path);
> > + break;
> > + default:
> > + fprintf(fp, " UNKNOWN TYPE\n");
> > + }
> > +}
> > +
> > +static int do_maple_tree_traverse(ulong ptr, int is_root)
> > +{
> > + char path[BUFSIZE] = {0};
> > + unsigned char tmp_tree[MAPLE_BUFSIZE];
> > + void *entry;
> > +
> > + assert(SIZE(maple_tree_struct) <= MAPLE_BUFSIZE);
> > +
> > + if (!is_root) {
> > + strcpy(path, "direct");
> > + do_mt_node(NULL, (void *)ptr, 0,
> > + mt_max[mte_node_type((struct maple_enode *)ptr)], 0, path);
> > + } else {
> > + readmem((ulonglong)ptr, KVADDR, tmp_tree, SIZE(maple_tree_struct),
> > + "mt_dump read maple_tree", FAULT_ON_ERROR);
> > + entry = *(void **)(tmp_tree + OFFSET(maple_tree_ma_root));
> > +
> > + if (cmd_tree_info.td &&
> > + cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) {
> > + fprintf(fp, "maple_tree(%lx) flags %X, height %u root %p\n\n",
> > + ptr, *(unsigned int *)(tmp_tree + OFFSET(maple_tree_ma_flags)),
> > + mt_height((struct maple_tree *)tmp_tree), entry);
> > + }
> > +
> > + if (!xa_is_node(entry))
> > + do_mt_entry(entry, 0, 0, 0, 0, path);
> > + else if (entry) {
> > + strcpy(path, "root");
> > + do_mt_node((struct maple_tree *)tmp_tree, entry, 0,
> > + mt_max[mte_node_type(entry)], 0, path);
> > + }
> > + }
> > + return 0;
> > +}
> > +
> > +int do_mptree(struct tree_data *td)
> > +{
> > + int is_root = !(td->flags & TREE_NODE_POINTER);
> > +
> > + memset(&cmd_tree_info, 0, sizeof(cmd_tree_info));
> > + cmd_tree_info.td = td;
> > + do_maple_tree_traverse(td->start, is_root);
> > +
> > + return 0;
> > +}
> > +
> > /***********************************************/
> > void maple_init(void)
> > {
> > @@ -810,14 +1187,17 @@ void maple_init(void)
> > MEMBER_OFFSET_INIT(maple_arange_64_parent, "maple_arange_64", "parent");
> > MEMBER_OFFSET_INIT(maple_arange_64_pivot, "maple_arange_64", "pivot");
> > MEMBER_OFFSET_INIT(maple_arange_64_slot, "maple_arange_64", "slot");
> > + MEMBER_OFFSET_INIT(maple_arange_64_gap, "maple_arange_64", "gap");
> > MEMBER_OFFSET_INIT(maple_arange_64_meta, "maple_arange_64", "meta");
> >
> > MEMBER_OFFSET_INIT(maple_range_64_parent, "maple_range_64", "parent");
> > MEMBER_OFFSET_INIT(maple_range_64_pivot, "maple_range_64", "pivot");
> > MEMBER_OFFSET_INIT(maple_range_64_slot, "maple_range_64", "slot");
> > + MEMBER_OFFSET_INIT(maple_range_64_pad, "maple_range_64", "pad");
> > MEMBER_OFFSET_INIT(maple_range_64_meta, "maple_range_64", "meta");
> >
> > MEMBER_OFFSET_INIT(maple_metadata_end, "maple_metadata", "end");
> > + MEMBER_OFFSET_INIT(maple_metadata_gap, "maple_metadata", "gap");
> >
> > array_len = get_array_length("mt_slots", NULL, sizeof(char));
> > mt_slots = calloc(array_len, sizeof(char));
> > @@ -830,4 +1210,9 @@ void maple_init(void)
> > readmem(symbol_value("mt_pivots"), KVADDR, mt_pivots,
> > array_len * sizeof(char), "maple_init read mt_pivots",
> > FAULT_ON_ERROR);
> > +
> > + mt_max[maple_dense] = mt_slots[maple_dense];
> > + mt_max[maple_leaf_64] = ULONG_MAX;
> > + mt_max[maple_range_64] = ULONG_MAX;
> > + mt_max[maple_arange_64] = ULONG_MAX;
> > }
> > \ No newline at end of file
> > diff --git a/tools.c b/tools.c
> > index 39306c1..3cb93c1 100644
> > --- a/tools.c
> > +++ b/tools.c
> > @@ -30,7 +30,7 @@ static void dealloc_hq_entry(struct hq_entry *);
> > static void show_options(void);
> > static void dump_struct_members(struct list_data *, int, ulong);
> > static void rbtree_iteration(ulong, struct tree_data *, char *);
> > -static void dump_struct_members_for_tree(struct tree_data *, int, ulong);
> > +void dump_struct_members_for_tree(struct tree_data *, int, ulong);
> >
> > struct req_entry {
> > char *arg, *name, **member;
> > @@ -40,8 +40,8 @@ struct req_entry {
> > };
> >
> > static void print_value(struct req_entry *, unsigned int, ulong, unsigned int);
> > -static struct req_entry *fill_member_offsets(char *);
> > -static void dump_struct_members_fast(struct req_entry *, int, ulong);
> > +struct req_entry *fill_member_offsets(char *);
> > +void dump_struct_members_fast(struct req_entry *, int, ulong);
> >
> > FILE *
> > set_error(char *target)
> > @@ -3666,7 +3666,7 @@ dump_struct_members_fast(struct req_entry *e, int radix, ulong p)
> > }
> > }
> >
> > -static struct req_entry *
> > +struct req_entry *
> > fill_member_offsets(char *arg)
> > {
> > int j;
> > @@ -4307,6 +4307,7 @@ dump_struct_members(struct list_data *ld, int idx, ulong next)
> > #define RADIXTREE_REQUEST (0x1)
> > #define RBTREE_REQUEST (0x2)
> > #define XARRAY_REQUEST (0x4)
> > +#define MAPLE_REQUEST (0x8)
> >
> > void
> > cmd_tree()
> > @@ -4324,11 +4325,11 @@ cmd_tree()
> > td = &tree_data;
> > BZERO(td, sizeof(struct tree_data));
> >
> > - while ((c = getopt(argcnt, args, "xdt:r:o:s:S:plN")) != EOF) {
> > + while ((c = getopt(argcnt, args, "xdt:r:o:s:S:plNv")) != EOF) {
> > switch (c)
> > {
> > case 't':
> > - if (type_flag & (RADIXTREE_REQUEST|RBTREE_REQUEST|XARRAY_REQUEST)) {
> > + if (type_flag & (RADIXTREE_REQUEST|RBTREE_REQUEST|XARRAY_REQUEST|MAPLE_REQUEST)) {
> > error(INFO, "multiple tree types may not be entered\n");
> > cmd_usage(pc->curcmd, SYNOPSIS);
> > }
> > @@ -4342,6 +4343,8 @@ cmd_tree()
> > type_flag = RBTREE_REQUEST;
> > else if (STRNEQ(optarg, "x"))
> > type_flag = XARRAY_REQUEST;
> > + else if (STRNEQ(optarg, "m"))
> > + type_flag = MAPLE_REQUEST;
> > else {
> > error(INFO, "invalid tree type: %s\n", optarg);
> > cmd_usage(pc->curcmd, SYNOPSIS);
> > @@ -4417,6 +4420,9 @@ cmd_tree()
> > "-d and -x are mutually exclusive\n");
> > td->flags |= TREE_STRUCT_RADIX_10;
> > break;
> > + case 'v':
> > + td->flags |= TREE_STRUCT_VERBOSE;
> > + break;
> > default:
> > argerrs++;
> > break;
> > @@ -4532,6 +4538,8 @@ next_arg:
> > do_rdtree(td);
> > else if (type_flag & XARRAY_REQUEST)
> > do_xatree(td);
> > + else if (type_flag & MAPLE_REQUEST)
> > + do_mptree(td);
> > else
> > do_rbtree(td);
> > hq_close();
> > --
> > 2.33.1
1 year, 11 months
Re: [Crash-utility] [PATCH v2 2/6] Introduce maple tree vma iteration to memory.c
by lijiang
On Tue, Oct 25, 2022 at 8:39 PM <crash-utility-request(a)redhat.com> wrote:
> Date: Tue, 25 Oct 2022 20:38:21 +0800
> From: Tao Liu <ltao(a)redhat.com>
> To: crash-utility(a)redhat.com
> Subject: [Crash-utility] [PATCH v2 2/6] Introduce maple tree vma
> iteration to memory.c
> Message-ID: <20221025123825.36421-3-ltao(a)redhat.com>
> Content-Type: text/plain; charset="US-ASCII"; x-default=true
>
> Since memory.c:vm_area_dump will iterate all vma, this patch mainly
> introduces maple tree vma iteration to it.
>
> We extract the code which handles each vma into a function. If
> mm_struct_mmap exist, aka the linked list of vma iteration available,
> we goto the original way; if not and mm_struct_mm_mt exist, aka
> maple tree is available, then we goto the maple tree vma iteration.
>
> Signed-off-by: Tao Liu <ltao(a)redhat.com>
> ---
> Makefile | 2 +-
> memory.c | 319 ++++++++++++++++++++++++++++++++-----------------------
> 2 files changed, 190 insertions(+), 131 deletions(-)
>
> diff --git a/Makefile b/Makefile
> index 6f19b77..ad8e9c4 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -355,7 +355,7 @@ filesys.o: ${GENERIC_HFILES} filesys.c
> help.o: ${GENERIC_HFILES} help.c
> ${CC} -c ${CRASH_CFLAGS} help.c ${WARNING_OPTIONS} ${WARNING_ERROR}
>
> -memory.o: ${GENERIC_HFILES} memory.c
> +memory.o: ${GENERIC_HFILES} ${MAPLE_TREE_HFILES} memory.c
> ${CC} -c ${CRASH_CFLAGS} memory.c ${WARNING_OPTIONS} ${WARNING_ERROR}
>
> test.o: ${GENERIC_HFILES} test.c
> diff --git a/memory.c b/memory.c
> index c80ef61..8e043d0 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -21,6 +21,7 @@
> #include <ctype.h>
> #include <netinet/in.h>
> #include <byteswap.h>
> +#include "maple_tree.h"
>
> struct meminfo { /* general purpose memory information structure */
> ulong cache; /* used by the various memory searching/dumping */
> @@ -136,6 +137,27 @@ struct searchinfo {
> char buf[BUFSIZE];
> };
>
> +struct handle_each_vm_area_args {
> + ulong task;
> + ulong flag;
> + ulong vaddr;
> + struct reference *ref;
> + char *vma_header;
> + char *buf1;
> + char *buf2;
> + char *buf3;
> + char *buf4;
> + char *buf5;
> + ulong vma;
> + char **vma_buf;
> + struct task_mem_usage *tm;
> + int *found;
> + int *single_vma_found;
> + unsigned int radix;
> + struct task_context *tc;
> + ulong *single_vma;
> +};
> +
> static char *memtype_string(int, int);
> static char *error_handle_string(ulong);
> static void collect_page_member_data(char *, struct meminfo *);
> @@ -298,6 +320,7 @@ static void dump_page_flags(ulonglong);
> static ulong kmem_cache_nodelists(ulong);
> static void dump_hstates(void);
> static ulong freelist_ptr(struct meminfo *, ulong, ulong);
> +static ulong handle_each_vm_area(struct handle_each_vm_area_args *);
>
> /*
> * Memory display modes specific to this file.
> @@ -362,6 +385,10 @@ vm_init(void)
>
> MEMBER_OFFSET_INIT(task_struct_mm, "task_struct", "mm");
> MEMBER_OFFSET_INIT(mm_struct_mmap, "mm_struct", "mmap");
> + MEMBER_OFFSET_INIT(mm_struct_mm_mt, "mm_struct", "mm_mt");
> + if (VALID_MEMBER(mm_struct_mm_mt)) {
> + maple_init();
> + }
> MEMBER_OFFSET_INIT(mm_struct_pgd, "mm_struct", "pgd");
> MEMBER_OFFSET_INIT(mm_struct_rss, "mm_struct", "rss");
> if (!VALID_MEMBER(mm_struct_rss))
> @@ -3866,7 +3893,7 @@ bailout:
> * for references -- and only then does a display
> */
>
> -#define PRINT_VM_DATA() \
> +#define PRINT_VM_DATA(buf4, buf5, tm) \
> { \
> fprintf(fp, "%s %s ", \
> mkstring(buf4, VADDR_PRLEN, CENTER|LJUST, "MM"), \
> @@ -3888,9 +3915,9 @@ bailout:
> mkstring(buf5, 8, CENTER|LJUST, NULL)); \
> }
>
> -#define PRINT_VMA_DATA() \
> +#define PRINT_VMA_DATA(buf1, buf2, buf3, buf4, vma) \
> fprintf(fp, "%s%s%s%s%s %6llx%s%s\n", \
> - mkstring(buf4, VADDR_PRLEN, CENTER|LJUST|LONG_HEX, MKSTR(vma)), \
> + mkstring(buf4, VADDR_PRLEN, CENTER|LJUST|LONG_HEX, MKSTR(vma)),\
> space(MINSPACE), \
> mkstring(buf2, UVADDR_PRLEN, RJUST|LONG_HEX, MKSTR(vm_start)), \
> space(MINSPACE), \
> @@ -3917,18 +3944,143 @@ bailout:
> (DO_REF_SEARCH(X) && (string_exists(S)) && FILENAME_COMPONENT((S),(X)->str))
> #define VM_REF_FOUND(X) ((X) && ((X)->cmdflags & VM_REF_HEADER))
>
> -ulong
> -vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
> +static ulong handle_each_vm_area(struct handle_each_vm_area_args *args)
> {
> - struct task_context *tc;
> - ulong vma;
> + char *dentry_buf, *file_buf;
> ulong vm_start;
> ulong vm_end;
> - ulong vm_next, vm_mm;
> - char *dentry_buf, *vma_buf, *file_buf;
> + ulong vm_mm;
> ulonglong vm_flags;
> ulong vm_file, inode;
> ulong dentry, vfsmnt;
> +
> + if ((args->flag & PHYSADDR) && !DO_REF_SEARCH(args->ref))
> + fprintf(fp, "%s", args->vma_header);
> +
> + inode = 0;
> + BZERO(args->buf1, BUFSIZE);
> + *(args->vma_buf) = fill_vma_cache(args->vma);
> +
> + vm_mm = ULONG(*(args->vma_buf) + OFFSET(vm_area_struct_vm_mm));
> + vm_end = ULONG(*(args->vma_buf) + OFFSET(vm_area_struct_vm_end));
> + vm_start = ULONG(*(args->vma_buf) + OFFSET(vm_area_struct_vm_start));
> + vm_flags = get_vm_flags(*(args->vma_buf));
> + vm_file = ULONG(*(args->vma_buf) + OFFSET(vm_area_struct_vm_file));
> +
> + if (args->flag & PRINT_SINGLE_VMA) {
> + if (args->vma != *(args->single_vma))
> + return 0;
> + fprintf(fp, "%s", args->vma_header);
> + *(args->single_vma_found) = TRUE;
> + }
> +
> + if (args->flag & PRINT_VMA_STRUCTS) {
> + dump_struct("vm_area_struct", args->vma, args->radix);
> + return 0;
> + }
> +
> + if (vm_file && !(args->flag & VERIFY_ADDR)) {
> + file_buf = fill_file_cache(vm_file);
> + dentry = ULONG(file_buf + OFFSET(file_f_dentry));
> + dentry_buf = NULL;
> + if (dentry) {
> + dentry_buf = fill_dentry_cache(dentry);
> + if (VALID_MEMBER(file_f_vfsmnt)) {
> + vfsmnt = ULONG(file_buf +
> + OFFSET(file_f_vfsmnt));
> + get_pathname(dentry, args->buf1, BUFSIZE,
> + 1, vfsmnt);
> + } else {
> + get_pathname(dentry, args->buf1, BUFSIZE,
> + 1, 0);
> + }
> + }
> + if ((args->flag & PRINT_INODES) && dentry) {
> + inode = ULONG(dentry_buf +
> + OFFSET(dentry_d_inode));
> + }
> + }
> +
> + if (!(args->flag & UVADDR) || ((args->flag & UVADDR) &&
> + ((args->vaddr >= vm_start) && (args->vaddr < vm_end)))) {
> + *(args->found) = TRUE;
> +
> + if (args->flag & VERIFY_ADDR)
> + return args->vma;
> +
> + if (DO_REF_SEARCH(args->ref)) {
> + if (VM_REF_CHECK_HEXVAL(args->ref, args->vma) ||
> + VM_REF_CHECK_HEXVAL(args->ref, (ulong)vm_flags) ||
> + VM_REF_CHECK_STRING(args->ref, args->buf1)) {
> + if (!(args->ref->cmdflags & VM_REF_HEADER)) {
> + print_task_header(fp, args->tc, 0);
> + PRINT_VM_DATA(args->buf4, args->buf5, args->tm);
> + args->ref->cmdflags |= VM_REF_HEADER;
> + }
> + if (!(args->ref->cmdflags & VM_REF_VMA) ||
> + (args->ref->cmdflags & VM_REF_PAGE)) {
> + fprintf(fp, "%s", args->vma_header);
> + args->ref->cmdflags |= VM_REF_VMA;
> + args->ref->cmdflags &= ~VM_REF_PAGE;
> + args->ref->ref1 = args->vma;
> + }
> + PRINT_VMA_DATA(args->buf1, args->buf2,
> + args->buf3, args->buf4, args->vma);
> + }
> +
> + if (vm_area_page_dump(args->vma, args->task,
> + vm_start, vm_end, vm_mm, args->ref)) {
> + if (!(args->ref->cmdflags & VM_REF_HEADER)) {
> + print_task_header(fp, args->tc, 0);
> + PRINT_VM_DATA(args->buf4, args->buf5, args->tm);
> + args->ref->cmdflags |= VM_REF_HEADER;
> + }
> + if (!(args->ref->cmdflags & VM_REF_VMA) ||
> + (args->ref->ref1 != args->vma)) {
> + fprintf(fp, "%s", args->vma_header);
> + PRINT_VMA_DATA(args->buf1, args->buf2,
> + args->buf3, args->buf4, args->vma);
> + args->ref->cmdflags |= VM_REF_VMA;
> + args->ref->ref1 = args->vma;
> + }
> +
> + args->ref->cmdflags |= VM_REF_DISPLAY;
> + vm_area_page_dump(args->vma, args->task,
> + vm_start, vm_end, vm_mm, args->ref);
> + args->ref->cmdflags &= ~VM_REF_DISPLAY;
> + }
> +
> + return 0;
> + }
> +
> + if (inode) {
> + fprintf(fp, "%lx%s%s%s%s%s%6llx%s%lx %s\n",
> + args->vma, space(MINSPACE),
> + mkstring(args->buf2, UVADDR_PRLEN, RJUST|LONG_HEX,
> + MKSTR(vm_start)), space(MINSPACE),
> + mkstring(args->buf3, UVADDR_PRLEN, RJUST|LONG_HEX,
> + MKSTR(vm_end)), space(MINSPACE),
> + vm_flags, space(MINSPACE), inode, args->buf1);
> + } else {
> + PRINT_VMA_DATA(args->buf1, args->buf2,
> + args->buf3, args->buf4, args->vma);
> +
> + if (args->flag & (PHYSADDR|PRINT_SINGLE_VMA))
> + vm_area_page_dump(args->vma, args->task,
> + vm_start, vm_end, vm_mm, args->ref);
> + }
> +
> + if (args->flag & UVADDR)
> + return args->vma;
> + }
> + return 0;
> +}
> +
> +ulong
> +vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
> +{
> + struct task_context *tc;
> + ulong vma;
> ulong single_vma;
> unsigned int radix;
> int single_vma_found;
> @@ -3940,6 +4092,7 @@ vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
> char buf4[BUFSIZE];
> char buf5[BUFSIZE];
> char vma_header[BUFSIZE];
> + char *vma_buf;
>
> tc = task_to_context(task);
> tm = &task_mem_usage;
> @@ -3973,14 +4126,14 @@ vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
> if (VM_REF_CHECK_HEXVAL(ref, tm->mm_struct_addr) ||
> VM_REF_CHECK_HEXVAL(ref, tm->pgd_addr)) {
> print_task_header(fp, tc, 0);
> - PRINT_VM_DATA();
> + PRINT_VM_DATA(buf4, buf5, tm);
> fprintf(fp, "\n");
> return (ulong)NULL;
> }
>
> if (!(flag & (UVADDR|PRINT_MM_STRUCT|PRINT_VMA_STRUCTS|PRINT_SINGLE_VMA)) &&
> !DO_REF_SEARCH(ref))
> - PRINT_VM_DATA();
> + PRINT_VM_DATA(buf4, buf5, tm);
>
> if (!tm->mm_struct_addr) {
> if (pc->curcmd_flags & MM_STRUCT_FORCE) {
> @@ -4004,9 +4157,6 @@ vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
> return (ulong)NULL;
> }
>
> - readmem(tm->mm_struct_addr + OFFSET(mm_struct_mmap), KVADDR,
> - &vma, sizeof(void *), "mm_struct mmap", FAULT_ON_ERROR);
> -
> sprintf(vma_header, "%s%s%s%s%s FLAGS%sFILE\n",
> mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "VMA"),
> space(MINSPACE),
> @@ -4019,125 +4169,34 @@ vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
> !DO_REF_SEARCH(ref))
> fprintf(fp, "%s", vma_header);
>
> - for (found = FALSE; vma; vma = vm_next) {
> -
> - if ((flag & PHYSADDR) && !DO_REF_SEARCH(ref))
> - fprintf(fp, "%s", vma_header);
> -
> - inode = 0;
> - BZERO(buf1, BUFSIZE);
> - vma_buf = fill_vma_cache(vma);
> -
> - vm_mm = ULONG(vma_buf + OFFSET(vm_area_struct_vm_mm));
> - vm_end = ULONG(vma_buf + OFFSET(vm_area_struct_vm_end));
> - vm_next = ULONG(vma_buf + OFFSET(vm_area_struct_vm_next));
> - vm_start = ULONG(vma_buf + OFFSET(vm_area_struct_vm_start));
> - vm_flags = get_vm_flags(vma_buf);
> - vm_file = ULONG(vma_buf + OFFSET(vm_area_struct_vm_file));
> -
> - if (flag & PRINT_SINGLE_VMA) {
> - if (vma != single_vma)
> - continue;
> - fprintf(fp, "%s", vma_header);
> - single_vma_found = TRUE;
> - }
> -
> - if (flag & PRINT_VMA_STRUCTS) {
> - dump_struct("vm_area_struct", vma, radix);
> - continue;
> - }
> -
> - if (vm_file && !(flag & VERIFY_ADDR)) {
> - file_buf = fill_file_cache(vm_file);
> - dentry = ULONG(file_buf + OFFSET(file_f_dentry));
> - dentry_buf = NULL;
> - if (dentry) {
> - dentry_buf = fill_dentry_cache(dentry);
> - if (VALID_MEMBER(file_f_vfsmnt)) {
> - vfsmnt = ULONG(file_buf +
> - OFFSET(file_f_vfsmnt));
> - get_pathname(dentry, buf1, BUFSIZE,
> - 1, vfsmnt);
> - } else {
> - get_pathname(dentry, buf1, BUFSIZE,
> - 1, 0);
> - }
> - }
> - if ((flag & PRINT_INODES) && dentry) {
> - inode = ULONG(dentry_buf +
> - OFFSET(dentry_d_inode));
> - }
> - }
> -
> - if (!(flag & UVADDR) || ((flag & UVADDR) &&
> - ((vaddr >= vm_start) && (vaddr < vm_end)))) {
> - found = TRUE;
> + found = FALSE;
>
> - if (flag & VERIFY_ADDR)
> + struct handle_each_vm_area_args args = {
> + .task = task, .flag = flag, .vaddr = vaddr,
> + .ref = ref, .vma_header = vma_header, .buf1 = buf1,
> + .buf2 = buf2, .buf3 = buf3, .buf4 = buf4,
> + .buf5 = buf5, .vma_buf = &vma_buf, .tm = tm,
> + .found = &found, .single_vma_found = &single_vma_found,
> + .radix = radix, .tc = tc, .single_vma = &single_vma,
> + };
The refactored code looks good, but the above structure seems to lack
a little readability. Is it possible to rearrange/split them according
to some rules? Such as parameter dependencies or input/output
parameters, etc... Just an idea.
Thanks.
Lianbo
> +
> + if (INVALID_MEMBER(mm_struct_mmap) && VALID_MEMBER(mm_struct_mm_mt)) {
> + VMA_ITERATOR(vmi, (struct maple_tree *)
> + (tm->mm_struct_addr + OFFSET(mm_struct_mm_mt)), 0);
> + for_each_vma(vmi, vma) {
> + args.vma = vma;
> + if (handle_each_vm_area(&args))
> return vma;
> -
> - if (DO_REF_SEARCH(ref)) {
> - if (VM_REF_CHECK_HEXVAL(ref, vma) ||
> - VM_REF_CHECK_HEXVAL(ref, (ulong)vm_flags) ||
> - VM_REF_CHECK_STRING(ref, buf1)) {
> - if (!(ref->cmdflags & VM_REF_HEADER)) {
> - print_task_header(fp, tc, 0);
> - PRINT_VM_DATA();
> - ref->cmdflags |= VM_REF_HEADER;
> - }
> - if (!(ref->cmdflags & VM_REF_VMA) ||
> - (ref->cmdflags & VM_REF_PAGE)) {
> - fprintf(fp, "%s", vma_header);
> - ref->cmdflags |= VM_REF_VMA;
> - ref->cmdflags &= ~VM_REF_PAGE;
> - ref->ref1 = vma;
> - }
> - PRINT_VMA_DATA();
> - }
> -
> - if (vm_area_page_dump(vma, task,
> - vm_start, vm_end, vm_mm, ref)) {
> - if (!(ref->cmdflags & VM_REF_HEADER)) {
> - print_task_header(fp, tc, 0);
> - PRINT_VM_DATA();
> - ref->cmdflags |= VM_REF_HEADER;
> - }
> - if (!(ref->cmdflags & VM_REF_VMA) ||
> - (ref->ref1 != vma)) {
> - fprintf(fp, "%s", vma_header);
> - PRINT_VMA_DATA();
> - ref->cmdflags |= VM_REF_VMA;
> - ref->ref1 = vma;
> - }
> -
> - ref->cmdflags |= VM_REF_DISPLAY;
> - vm_area_page_dump(vma, task,
> - vm_start, vm_end, vm_mm, ref);
> - ref->cmdflags &= ~VM_REF_DISPLAY;
> - }
> -
> - continue;
> - }
> -
> - if (inode) {
> - fprintf(fp, "%lx%s%s%s%s%s%6llx%s%lx %s\n",
> - vma, space(MINSPACE),
> - mkstring(buf2, UVADDR_PRLEN, RJUST|LONG_HEX,
> - MKSTR(vm_start)), space(MINSPACE),
> - mkstring(buf3, UVADDR_PRLEN, RJUST|LONG_HEX,
> - MKSTR(vm_end)), space(MINSPACE),
> - vm_flags, space(MINSPACE), inode, buf1);
> - } else {
> - PRINT_VMA_DATA();
> -
> - if (flag & (PHYSADDR|PRINT_SINGLE_VMA))
> - vm_area_page_dump(vma, task,
> - vm_start, vm_end, vm_mm, ref);
> - }
> -
> - if (flag & UVADDR)
> + }
> + } else {
> + readmem(tm->mm_struct_addr + OFFSET(mm_struct_mmap), KVADDR,
> + &vma, sizeof(void *), "mm_struct mmap", FAULT_ON_ERROR);
> + while (vma) {
> + args.vma = vma;
> + if (handle_each_vm_area(&args))
> return vma;
> - }
> + vma = ULONG(vma_buf + OFFSET(vm_area_struct_vm_next));
> + }
> }
>
> if (flag & VERIFY_ADDR)
> --
> 2.33.1
1 year, 11 months
Re: [Crash-utility] [PATCH v2 1/6] Port the maple tree data structures and main functions
by lijiang
On Tue, Oct 25, 2022 at 8:39 PM <crash-utility-request(a)redhat.com> wrote:
> Date: Tue, 25 Oct 2022 20:38:20 +0800
> From: Tao Liu <ltao(a)redhat.com>
> To: crash-utility(a)redhat.com
> Subject: [Crash-utility] [PATCH v2 1/6] Port the maple tree data
> structures and main functions
> Message-ID: <20221025123825.36421-2-ltao(a)redhat.com>
> Content-Type: text/plain; charset="US-ASCII"; x-default=true
>
> There are 2 ways to iterate vm_area_struct: 1) by rbtree,
> aka vma.vm_rb; 2) by linked list, aka vma.vm_prev/next.
> However for linux maple tree patch[1][2], vm_rb and vm_prev/next
> are removed from vm_area_struct. For memory.c:vm_area_dump
> of crash, it mainly uses linked list as a way of vma iteration,
> which will not work for this case. So maple tree iteration
> need to be ported to crash.
>
> For crash, currently it only iteratively read the maple tree,
> no more rcu safe or maple tree modification features
> needed. So we only port a subset of kernel maple tree
> features. In addition, we need to modify the ported kernel
> source code, making it compatible with crash.
>
> The formal crash way of vmcore struct member resolving is:
>
> readmem(node, KVADDR, buf, SIZE(buf), "", flag);
> return buf + OFFSET(member);
>
> which is the reimplementation of kernel way of member resolving:
>
> return node->member;
>
> The 1st one is arch independent, it uses gdb to resolve the OFFSET
> of members, so crash don't need to know what the inside of the
> struct is, even if the struct changes for new kernel version. The 2nd
> one is arch dependent, the struct need to be ported to crash, and the
> OFFSET of members may differ between crash and kernel due to padding/
> alignment or optimization reasons.
>
> This patch deals with the 2 issues: 1) Poring for_each_vma() macro, and
> all its dependencies from kernel source[3] to crash, to enable crash
> maple tree vma iteration, 2) adapting the ported code with crash.
>
> [1]: https://github.com/oracle/linux-uek/commit/d19703645b80abe35dff1a88449d07...
> [2]: https://github.com/oracle/linux-uek/commit/91dee01f1ebb6b6587463b6ee6f7bb...
> [3]: https://github.com/oracle/linux-uek, maple/mainline branch
>
> Signed-off-by: Tao Liu <ltao(a)redhat.com>
> ---
> Makefile | 10 +-
> defs.h | 19 ++
> maple_tree.c | 833 +++++++++++++++++++++++++++++++++++++++++++++++++++
> maple_tree.h | 214 +++++++++++++
> 4 files changed, 1073 insertions(+), 3 deletions(-)
> create mode 100644 maple_tree.c
> create mode 100644 maple_tree.h
>
> diff --git a/Makefile b/Makefile
> index 79aef17..6f19b77 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -59,6 +59,7 @@ IBM_HFILES=ibm_common.h
> SADUMP_HFILES=sadump.h
> UNWIND_HFILES=unwind.h unwind_i.h rse.h unwind_x86.h unwind_x86_64.h
> VMWARE_HFILES=vmware_vmss.h
> +MAPLE_TREE_HFILES=maple_tree.h
>
> CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \
> kernel.c test.c gdb_interface.c configure.c net.c dev.c bpf.c \
> @@ -73,12 +74,12 @@ 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 sbitmap.c
> + xen_dom0.c kaslr_helper.c sbitmap.c maple_tree.c
>
> SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \
> ${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \
> ${LKCD_DUMP_HFILES} ${LKCD_TRACE_HFILES} ${LKCD_OBSOLETE_HFILES}\
> - ${IBM_HFILES} ${SADUMP_HFILES} ${VMWARE_HFILES}
> + ${IBM_HFILES} ${SADUMP_HFILES} ${VMWARE_HFILES} ${MAPLE_TREE_HFILES}
>
> OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \
> build_data.o kernel.o test.o gdb_interface.o net.o dev.o bpf.o \
> @@ -93,7 +94,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 sbitmap.o
> + xen_dom0.o kaslr_helper.o sbitmap.o maple_tree.o
>
> MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c memory_driver/README
>
> @@ -536,6 +537,9 @@ kaslr_helper.o: ${GENERIC_HFILES} kaslr_helper.c
> bpf.o: ${GENERIC_HFILES} bpf.c
> ${CC} -c ${CRASH_CFLAGS} bpf.c ${WARNING_OPTIONS} ${WARNING_ERROR}
>
> +maple_tree.o: ${GENERIC_HFILES} ${MAPLE_TREE_HFILES} maple_tree.c
> + ${CC} -c ${CRASH_CFLAGS} maple_tree.c ${WARNING_OPTIONS} ${WARNING_ERROR}
> +
> ${PROGRAM}: force
> @$(MAKE) all
>
> diff --git a/defs.h b/defs.h
> index afdcf6c..2978cec 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -2181,6 +2181,22 @@ struct offset_table { /* stash of commonly-used offsets */
> long blk_mq_tags_nr_reserved_tags;
> long blk_mq_tags_rqs;
> long request_queue_hctx_table;
> + long mm_struct_mm_mt;
> + long maple_tree_ma_root;
> + long maple_tree_ma_flags;
> + long maple_node_parent;
> + long maple_node_ma64;
> + long maple_node_mr64;
> + long maple_node_slot;
> + long maple_arange_64_parent;
> + long maple_arange_64_pivot;
> + long maple_arange_64_slot;
> + long maple_arange_64_meta;
> + long maple_range_64_parent;
> + long maple_range_64_pivot;
> + long maple_range_64_slot;
> + long maple_range_64_meta;
> + long maple_metadata_end;
> };
>
> struct size_table { /* stash of commonly-used sizes */
> @@ -2351,6 +2367,8 @@ struct size_table { /* stash of commonly-used sizes */
> long sbitmap_queue;
> long sbq_wait_state;
> long blk_mq_tags;
> + long maple_tree_struct;
> + long maple_node_struct;
> };
>
> struct array_table {
> @@ -5557,6 +5575,7 @@ int file_dump(ulong, ulong, ulong, int, int);
> int same_file(char *, char *);
> int cleanup_memory_driver(void);
>
> +void maple_init(void);
>
> /*
> * help.c
> diff --git a/maple_tree.c b/maple_tree.c
> new file mode 100644
> index 0000000..058b769
> --- /dev/null
> +++ b/maple_tree.c
> @@ -0,0 +1,833 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Maple Tree implementation
> + * Copyright (c) 2018-2022 Oracle Corporation
> + * Authors: Liam R. Howlett <Liam.Howlett(a)oracle.com>
> + * Matthew Wilcox <willy(a)infradead.org>
> + *
> + * The following are copied and modified from lib/maple_tree.c
> + */
> +
> +#include "maple_tree.h"
> +#include "defs.h"
> +
> +/* Bit 1 indicates the root is a node */
> +#define MAPLE_ROOT_NODE 0x02
> +/* maple_type stored bit 3-6 */
> +#define MAPLE_ENODE_TYPE_SHIFT 0x03
> +/* Bit 2 means a NULL somewhere below */
> +#define MAPLE_ENODE_NULL 0x04
> +
> +#define MA_ROOT_PARENT 1
> +
> +#define MAPLE_PARENT_ROOT 0x01
> +
> +#define MAPLE_PARENT_SLOT_SHIFT 0x03
> +#define MAPLE_PARENT_SLOT_MASK 0xF8
> +
> +#define MAPLE_PARENT_16B_SLOT_SHIFT 0x02
> +#define MAPLE_PARENT_16B_SLOT_MASK 0xFC
> +
> +#define MAPLE_PARENT_RANGE64 0x06
> +#define MAPLE_PARENT_RANGE32 0x04
> +#define MAPLE_PARENT_NOT_RANGE16 0x02
> +
> +unsigned char *mt_slots = NULL;
> +unsigned char *mt_pivots = NULL;
> +
> +#define MAPLE_BUFSIZE 512
> +
> +#define ma_parent_ptr(x) ((struct maple_pnode *)(x))
Unused.
> +#define ma_enode_ptr(x) ((struct maple_enode *)(x))
> +
> +static inline bool mas_is_ptr(struct ma_state *mas)
> +{
> + return mas->node == MAS_ROOT;
> +}
> +
> +static inline bool mas_is_start(struct ma_state *mas)
> +{
> + return mas->node == MAS_START;
> +}
> +
> +static inline void *mte_safe_root(const struct maple_enode *node)
> +{
> + return (void *)((unsigned long)node & ~MAPLE_ROOT_NODE);
> +}
> +
> +static inline struct maple_node *mte_to_node(const struct maple_enode *entry)
> +{
> + return (struct maple_node *)((unsigned long)entry & ~MAPLE_NODE_MASK);
> +}
> +
> +static inline enum maple_type mte_node_type(const struct maple_enode *entry)
> +{
> + return ((unsigned long)entry >> MAPLE_NODE_TYPE_SHIFT) &
> + MAPLE_NODE_TYPE_MASK;
> +}
> +
> +static inline void *mas_root(struct ma_state *mas)
> +{
> + char tree[MAPLE_BUFSIZE];
> + assert(SIZE(maple_tree_struct) <= MAPLE_BUFSIZE);
The assert() may cause the crash coredump, could you please replace
the assert() with the similar code block as below?
if (SIZE(maple_tree_struct) <= MAPLE_BUFSIZE)
error(FATAL, "");
> +
> + readmem((ulonglong)(mas->tree), KVADDR, tree, SIZE(maple_tree_struct),
> + "mas_root read maple_tree", FAULT_ON_ERROR);
> + return *(void **)(tree + OFFSET(maple_tree_ma_root));
> +}
> +
> +static inline struct maple_enode *mas_start(struct ma_state *mas)
> +{
> + if (mas_is_start(mas)) {
> + struct maple_enode *root;
> +
> + mas->node = MAS_NONE;
> + mas->min = 0;
> + mas->max = ULONG_MAX;
> + mas->depth = 0;
> + mas->offset = 0;
> +
> + root = mas_root(mas);
> + /* Tree with nodes */
> + if (xa_is_node(root)) {
> + mas->node = mte_safe_root(root);
> + return NULL;
> + }
> +
> + /* empty tree */
> + if (!root) {
> + // mas->offset = MAPLE_NODE_SLOTS;
> + mas->offset = mt_slots[maple_dense];
> + return NULL;
> + }
> +
> + /* Single entry tree */
> + mas->node = MAS_ROOT;
> + // mas->offset = MAPLE_NODE_SLOTS;
> + mas->offset = mt_slots[maple_dense];
> +
> + /* Single entry tree. */
> + if (mas->index > 0)
> + return NULL;
> +
> + return root;
> + }
> +
> + return NULL;
> +}
> +
> +static inline unsigned long *ma_pivots(struct maple_node *node,
> + enum maple_type type)
> +{
> + switch (type) {
> + case maple_arange_64:
> + return (unsigned long *)((char *)node + OFFSET(maple_node_ma64)
> + + OFFSET(maple_arange_64_pivot));
> + case maple_range_64:
> + case maple_leaf_64:
> + return (unsigned long *)((char *)node + OFFSET(maple_node_mr64)
> + + OFFSET(maple_range_64_pivot));
> + case maple_dense:
> + return NULL;
> + }
> + return NULL;
> +}
> +
> +static inline struct maple_metadata *ma_meta(struct maple_node *mn,
> + enum maple_type mt)
> +{
> + switch (mt) {
> + case maple_arange_64:
> + return (struct maple_metadata *)(
> + (char *)mn + OFFSET(maple_node_ma64)
> + + OFFSET(maple_arange_64_meta));
> + default:
> + return (struct maple_metadata *)(
> + (char *)mn + OFFSET(maple_node_mr64)
> + + OFFSET(maple_range_64_meta));
> + }
> +}
> +
> +static inline unsigned char ma_meta_end(struct maple_node *mn,
> + enum maple_type mt)
> +{
> + struct maple_metadata *meta = ma_meta(mn, mt);
> +
> + return *((char *)meta + OFFSET(maple_metadata_end));
> +}
> +
> +static inline unsigned char ma_data_end(struct maple_node *node,
> + enum maple_type type,
> + unsigned long *pivots,
> + unsigned long max)
> +{
> + unsigned char offset;
> +
> + if (type == maple_arange_64)
> + return ma_meta_end(node, type);
> +
> + offset = mt_pivots[type] - 1;
> + if (!pivots[offset])
> + return ma_meta_end(node, type);
> +
> + if (pivots[offset] == max)
> + return offset;
> +
> + return mt_pivots[type];
> +}
> +
> +static inline bool ma_dead_node(const struct maple_node *node,
> + const struct maple_node *orig_node)
> +{
> + struct maple_node *parent = (struct maple_node *)
> + (*(unsigned long *)((char *)node
> + + OFFSET(maple_node_parent))
> + & ~MAPLE_NODE_MASK);
> + return (parent == orig_node);
> +}
> +
> +static inline void **ma_slots(struct maple_node *mn, enum maple_type mt)
> +{
> + switch (mt) {
> + default:
> + case maple_arange_64:
> + return (void **)((char *)mn + OFFSET(maple_node_ma64)
> + + OFFSET(maple_arange_64_slot));
> + case maple_range_64:
> + case maple_leaf_64:
> + return (void **)((char *)mn + OFFSET(maple_node_mr64)
> + + OFFSET(maple_range_64_slot));
> + case maple_dense:
> + return (void **)((char *)mn + OFFSET(maple_node_slot));
> + }
> +}
> +
> +static inline void *mt_slot(const struct maple_tree *mt,
> + void **slots, unsigned char offset)
> +{
> + return slots[offset];
> +}
> +
> +static inline bool ma_is_leaf(const enum maple_type type)
> +{
> + return type < maple_range_64;
> +}
> +
> +static inline void *mtree_range_walk(struct ma_state *mas)
> +{
> + unsigned long *pivots;
> + unsigned char offset;
> + struct maple_node *node;
> + struct maple_enode *next, *last;
> + enum maple_type type;
> + void **slots;
> + unsigned char end;
> + unsigned long max, min;
> + unsigned long prev_max, prev_min;
> +
> + char tmp_node[MAPLE_BUFSIZE];
> + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE);
Ditto.
> +
> + last = next = mas->node;
> + prev_min = min = mas->min;
> + max = mas->max;
> + do {
> + offset = 0;
> + last = next;
> + node = mte_to_node(next);
> + type = mte_node_type(next);
> + readmem((ulonglong)node, KVADDR, tmp_node, SIZE(maple_node_struct),
> + "mtree_range_walk read maple_node", FAULT_ON_ERROR);
> + pivots = ma_pivots((struct maple_node *)tmp_node, type);
> + end = ma_data_end((struct maple_node *)tmp_node, type, pivots, max);
> + if (ma_dead_node((struct maple_node *)tmp_node, node))
> + goto dead_node;
> +
> + if (pivots[offset] >= mas->index) {
> + prev_max = max;
> + prev_min = min;
> + max = pivots[offset];
> + goto next;
> + }
> +
> + do {
> + offset++;
> + } while ((offset < end) && (pivots[offset] < mas->index));
> +
> + prev_min = min;
> + min = pivots[offset - 1] + 1;
> + prev_max = max;
> + if (offset < end && pivots[offset])
> + max = pivots[offset];
> +
> +next:
> + slots = ma_slots((struct maple_node *)tmp_node, type);
> + next = mt_slot(mas->tree, slots, offset);
> + if (ma_dead_node((struct maple_node *)tmp_node, node))
> + goto dead_node;
> + } while (!ma_is_leaf(type));
> +
> + mas->offset = offset;
> + mas->index = min;
> + mas->last = max;
> + mas->min = prev_min;
> + mas->max = prev_max;
> + mas->node = last;
> + return (void *) next;
> +
> +dead_node:
> + mas_reset(mas);
> + return NULL;
> +}
> +
> +static inline void *mas_state_walk(struct ma_state *mas)
> +{
> + void *entry;
> +
> + entry = mas_start(mas);
> + if (mas_is_none(mas))
> + return NULL;
> +
> + if (mas_is_ptr(mas))
> + return entry;
> +
> + return mtree_range_walk(mas);
> +}
> +
> +static inline bool mas_searchable(struct ma_state *mas)
> +{
> + if (mas_is_none(mas))
> + return false;
> +
> + if (mas_is_ptr(mas))
> + return false;
> +
> + return true;
> +}
> +
> +static inline struct maple_node *mas_mn(const struct ma_state *mas)
> +{
> + return mte_to_node(mas->node);
> +}
> +
> +static inline unsigned long
> +mas_safe_min(struct ma_state *mas, unsigned long *pivots, unsigned char offset)
> +{
> + if (offset)
> + return pivots[offset - 1] + 1;
> +
> + return mas->min;
> +}
> +
> +static inline void *mas_slot(struct ma_state *mas, void **slots,
> + unsigned char offset)
> +{
> + return mt_slot(mas->tree, slots, offset);
> +}
> +
> +static inline unsigned long
> +mas_safe_pivot(const struct ma_state *mas, unsigned long *pivots,
> + unsigned char piv, enum maple_type type)
> +{
> + if (piv >= mt_pivots[type])
> + return mas->max;
> +
> + return pivots[piv];
> +}
> +
> +static inline void *mas_next_nentry(struct ma_state *mas,
> + struct maple_node *node, unsigned long max,
> + enum maple_type type, struct maple_node *orig_node)
> +{
> + unsigned char count;
> + unsigned long pivot;
> + unsigned long *pivots;
> + void **slots;
> + void *entry;
> +
> + if (mas->last == mas->max) {
> + mas->index = mas->max;
> + return NULL;
> + }
> +
> + pivots = ma_pivots(node, type);
> + slots = ma_slots(node, type);
> + mas->index = mas_safe_min(mas, pivots, mas->offset);
> + if (ma_dead_node(node, orig_node))
> + return NULL;
> +
> + if (mas->index > max)
> + return NULL;
> +
> + count = ma_data_end(node, type, pivots, mas->max);
> + if (mas->offset > count)
> + return NULL;
> +
> + while (mas->offset < count) {
> + pivot = pivots[mas->offset];
> + entry = mas_slot(mas, slots, mas->offset);
> + if (ma_dead_node(node, orig_node))
> + return NULL;
> +
> + if (entry)
> + goto found;
> +
> + if (pivot >= max)
> + return NULL;
> +
> + mas->index = pivot + 1;
> + mas->offset++;
> + }
> +
> + if (mas->index > mas->max) {
> + mas->index = mas->last;
> + return NULL;
> + }
> +
> + pivot = mas_safe_pivot(mas, pivots, mas->offset, type);
> + entry = mas_slot(mas, slots, mas->offset);
> + if (ma_dead_node(node, orig_node))
> + return NULL;
> +
> + if (!pivot)
> + return NULL;
> +
> + if (!entry)
> + return NULL;
> +
> +found:
> + mas->last = pivot;
> + return entry;
> +}
> +
> +static inline void mas_rewalk(struct ma_state *mas, unsigned long index)
> +{
> +
> +retry:
> + mas_set(mas, index);
> + mas_state_walk(mas);
> + if (mas_is_start(mas))
> + goto retry;
> +
> + return;
The "return" is redundant?
> +}
> +
> +static inline bool ma_is_root(struct maple_node *node)
> +{
> + return (*(unsigned long *)((char *)node
> + + OFFSET(maple_node_parent))
> + & MA_ROOT_PARENT);
> +}
> +
> +static inline struct maple_node *mte_parent(const struct maple_node *node)
> +{
> + return (void *)(*(unsigned long *)((char *)node
> + + OFFSET(maple_node_parent))
> + & ~MAPLE_NODE_MASK);
> +}
> +
> +static inline unsigned long mte_parent_slot_mask(unsigned long parent)
> +{
> + /* Note bit 1 == 0 means 16B */
> + if (parent & MAPLE_PARENT_NOT_RANGE16)
> + return MAPLE_PARENT_SLOT_MASK;
> +
> + return MAPLE_PARENT_16B_SLOT_MASK;
> +}
> +
> +static inline bool mt_is_alloc(struct maple_tree *mt)
> +{
> + return (*(unsigned int *)((char *)mt
> + + OFFSET(maple_tree_ma_flags))
> + & MT_FLAGS_ALLOC_RANGE);
> +}
> +
> +static inline
> +enum maple_type mte_parent_enum(struct maple_enode *p_enode,
> + struct maple_tree *mt)
> +{
> + unsigned long p_type;
> + char tmp_tree[MAPLE_BUFSIZE];
> + assert(SIZE(maple_tree_struct) <= MAPLE_BUFSIZE);
Ditto.
> +
> + p_type = (unsigned long)p_enode;
> + if (p_type & MAPLE_PARENT_ROOT)
> + return 0; /* Validated in the caller. */
Does this indicate that it is the enum maple_type: maple_dense?
> +
> + p_type &= MAPLE_NODE_MASK;
> + p_type = p_type & ~(MAPLE_PARENT_ROOT | mte_parent_slot_mask(p_type));
> +
> + switch (p_type) {
> + case MAPLE_PARENT_RANGE64: /* or MAPLE_PARENT_ARANGE64 */
> + readmem((ulonglong)mt, KVADDR, tmp_tree, SIZE(maple_tree_struct),
> + "mte_parent_enum read maple_tree", FAULT_ON_ERROR);
> + if (mt_is_alloc((struct maple_tree *)tmp_tree))
> + return maple_arange_64;
> + return maple_range_64;
> + }
> +
> + return 0;
> +}
> +
> +static inline
> +enum maple_type mas_parent_enum(struct ma_state *mas, struct maple_node *node)
> +{
> + return mte_parent_enum(ma_enode_ptr(*(struct maple_pnode **)
> + ((char *)node + OFFSET(maple_node_parent))),
> + mas->tree);
> +}
> +
> +static inline unsigned long mte_parent_shift(unsigned long parent)
> +{
> + /* Note bit 1 == 0 means 16B */
> + if (parent & MAPLE_PARENT_NOT_RANGE16)
> + return MAPLE_PARENT_SLOT_SHIFT;
> +
> + return MAPLE_PARENT_16B_SLOT_SHIFT;
> +}
> +
> +static inline unsigned int mte_parent_slot(const struct maple_node *node)
> +{
> + unsigned long val = *(unsigned long *)((char *)node
> + + OFFSET(maple_node_parent));
> +
> + /* Root. */
> + if (val & 1)
> + return 0;
> +
> + /*
> + * Okay to use MAPLE_PARENT_16B_SLOT_MASK as the last bit will be lost
> + * by shift if the parent shift is MAPLE_PARENT_SLOT_SHIFT
> + */
> + return (val & MAPLE_PARENT_16B_SLOT_MASK) >> mte_parent_shift(val);
> +}
> +
> +static inline struct maple_enode *mt_mk_node(const struct maple_node *node,
> + enum maple_type type)
> +{
> + return (void *)((unsigned long)node |
> + (type << MAPLE_ENODE_TYPE_SHIFT) | MAPLE_ENODE_NULL);
> +}
> +
> +static inline bool mte_is_root(struct maple_node *node)
> +{
> + return ma_is_root(node);
> +}
> +
> +static int mas_ascend(struct ma_state *mas)
> +{
> + struct maple_enode *p_enode; /* parent enode. */
> + struct maple_enode *a_enode; /* ancestor enode. */
> + struct maple_node *a_node; /* ancestor node. */
> + struct maple_node *p_node; /* parent node. */
> + unsigned char a_slot;
> + enum maple_type a_type;
> + unsigned long min, max;
> + unsigned long *pivots;
> + unsigned char offset;
> + bool set_max = false, set_min = false;
> +
> + char tmp_node[MAPLE_BUFSIZE];
> + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE);
Ditto.
> +
> + a_node = mas_mn(mas);
> + readmem((ulonglong)a_node, KVADDR, tmp_node, SIZE(maple_node_struct),
> + "mas_ascend read maple_node", FAULT_ON_ERROR);
> + if (ma_is_root((struct maple_node *)tmp_node)) {
> + mas->offset = 0;
> + return 0;
> + }
> +
> + readmem((ulonglong)(mte_to_node(mas->node)), KVADDR, tmp_node,
> + SIZE(maple_node_struct), "mas_ascend read maple_node", FAULT_ON_ERROR);
> + p_node = mte_parent((struct maple_node *)tmp_node);
> + if (a_node == p_node)
> + return 1;
> + a_type = mas_parent_enum(mas, (struct maple_node *)tmp_node);
> + offset = mte_parent_slot((struct maple_node *)tmp_node);
> + a_enode = mt_mk_node(p_node, a_type);
> +
> + /* Check to make sure all parent information is still accurate */
> + if (p_node != mte_parent((struct maple_node *)tmp_node))
> + return 1;
> +
> + mas->node = a_enode;
> + mas->offset = offset;
> +
> + readmem((ulonglong)(mte_to_node(a_enode)), KVADDR, tmp_node,
> + SIZE(maple_node_struct), "mas_ascend read maple_node", FAULT_ON_ERROR);
> + if (mte_is_root((struct maple_node *)tmp_node)) {
> + mas->max = ULONG_MAX;
> + mas->min = 0;
> + return 0;
> + }
> +
> + min = 0;
> + max = ULONG_MAX;
> + do {
> + p_enode = a_enode;
> + readmem((ulonglong)(mte_to_node(p_enode)), KVADDR, tmp_node,
> + SIZE(maple_node_struct),
> + "mas_ascend read maple_node", FAULT_ON_ERROR);
> + a_type = mas_parent_enum(mas, (struct maple_node *)tmp_node);
> + a_node = mte_parent((struct maple_node *)tmp_node);
> + a_slot = mte_parent_slot((struct maple_node *)tmp_node);
> + readmem((ulonglong)a_node, KVADDR, tmp_node, SIZE(maple_node_struct),
> + "mas_ascend read maple_node", FAULT_ON_ERROR);
> + pivots = ma_pivots((struct maple_node *)tmp_node, a_type);
> + a_enode = mt_mk_node((struct maple_node *)tmp_node, a_type);
> +
> + if (!set_min && a_slot) {
> + set_min = true;
> + min = pivots[a_slot - 1] + 1;
> + }
> +
> + if (!set_max && a_slot < mt_pivots[a_type]) {
> + set_max = true;
> + max = pivots[a_slot];
> + }
> +
> + if (ma_dead_node((struct maple_node *)tmp_node, a_node))
> + return 1;
> +
> + if (ma_is_root((struct maple_node *)tmp_node))
> + break;
> +
> + } while (!set_min || !set_max);
> +
> + mas->max = max;
> + mas->min = min;
> + return 0;
> +}
> +
> +static inline int mas_next_node(struct ma_state *mas, struct maple_node *node,
> + unsigned long max)
> +{
> + unsigned long min, pivot;
> + unsigned long *pivots;
> + struct maple_enode *enode;
> + int level = 0;
> + unsigned char offset;
> + enum maple_type mt;
> + void **slots;
> +
> + char tmp_node[MAPLE_BUFSIZE];
> + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE);
Ditto.
> +
> + if (mas->max >= max)
> + goto no_entry;
> +
> + level = 0;
> + readmem((ulonglong)node, KVADDR, tmp_node, SIZE(maple_node_struct),
> + "mas_next_node read maple_node", FAULT_ON_ERROR);
> + do {
> + if (ma_is_root((struct maple_node *)tmp_node))
> + goto no_entry;
> +
> + min = mas->max + 1;
> + if (min > max)
> + goto no_entry;
> +
> + if (mas_ascend(mas))
> + return 1;
> +
> + offset = mas->offset;
> + level++;
> + node = mas_mn(mas);
> + mt = mte_node_type(mas->node);
> + readmem((ulonglong)node, KVADDR, tmp_node, SIZE(maple_node_struct),
> + "mas_next_node read maple_node", FAULT_ON_ERROR);
> + pivots = ma_pivots((struct maple_node *)tmp_node, mt);
> + } while (offset == ma_data_end((struct maple_node *)tmp_node, mt, pivots, mas->max));
> +
> + slots = ma_slots((struct maple_node *)tmp_node, mt);
> + pivot = mas_safe_pivot(mas, pivots, ++offset, mt);
> + while (level > 1) {
> + /* Descend, if necessary */
> + enode = mas_slot(mas, slots, offset);
> + if (ma_dead_node((struct maple_node *)tmp_node, node))
> + return 1;
> +
> + mas->node = enode;
> + level--;
> + node = mas_mn(mas);
> + mt = mte_node_type(mas->node);
> + readmem((ulonglong)node, KVADDR, tmp_node, SIZE(maple_node_struct),
> + "mas_next_node read maple_node", FAULT_ON_ERROR);
> + slots = ma_slots((struct maple_node *)tmp_node, mt);
> + pivots = ma_pivots((struct maple_node *)tmp_node, mt);
> + offset = 0;
> + pivot = pivots[0];
> + }
> +
> + enode = mas_slot(mas, slots, offset);
> + if (ma_dead_node((struct maple_node *)tmp_node, node))
> + return 1;
> +
> + mas->node = enode;
> + mas->min = min;
> + mas->max = pivot;
> + return 0;
> +
> +no_entry:
> + if (ma_dead_node((struct maple_node *)tmp_node, node))
> + return 1;
> +
> + mas->node = MAS_NONE;
> + return 0;
> +}
> +
> +static inline void *mas_next_entry(struct ma_state *mas, unsigned long limit)
> +{
> + void *entry = NULL;
> + struct maple_enode *prev_node;
> + struct maple_node *node;
> + unsigned char offset;
> + unsigned long last;
> + enum maple_type mt;
> +
> + char tmp_node[MAPLE_BUFSIZE];
> + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE);
Ditto.
> +
> + last = mas->last;
> +retry:
> + offset = mas->offset;
> + prev_node = mas->node;
> + node = mas_mn(mas);
> + mt = mte_node_type(mas->node);
> + mas->offset++;
> + if (mas->offset >= mt_slots[mt]) {
> + mas->offset = mt_slots[mt] - 1;
> + goto next_node;
> + }
> +
> + while (!mas_is_none(mas)) {
> + readmem((ulonglong)node, KVADDR, tmp_node, SIZE(maple_node_struct),
> + "mas_next_entry read maple_node", FAULT_ON_ERROR);
> + entry = mas_next_nentry(mas, (struct maple_node *)tmp_node, limit, mt, node);
> + if (ma_dead_node((struct maple_node *)tmp_node, node)) {
> + mas_rewalk(mas, last);
> + goto retry;
> + }
> +
> + if (entry)
> + return entry;
> +
> + if ((mas->index > limit))
> + break;
> +
> +next_node:
> + prev_node = mas->node;
> + offset = mas->offset;
> + if (mas_next_node(mas, node, limit)) {
> + mas_rewalk(mas, last);
> + goto retry;
> + }
> + mas->offset = 0;
> + node = mas_mn(mas);
> + mt = mte_node_type(mas->node);
> + }
> +
> + mas->index = mas->last = limit;
> + mas->offset = offset;
> + mas->node = prev_node;
> + return NULL;
> +}
> +
> +static void *mas_walk(struct ma_state *mas)
> +{
> + void *entry;
> +
> +retry:
> + entry = mas_state_walk(mas);
> + if (mas_is_start(mas))
> + goto retry;
> +
> + if (mas_is_ptr(mas)) {
> + if (!mas->index) {
> + mas->last = 0;
> + } else {
> + mas->index = 1;
> + mas->last = ULONG_MAX;
> + }
> + return entry;
> + }
> +
> + if (mas_is_none(mas)) {
> + mas->index = 0;
> + mas->last = ULONG_MAX;
> + }
> +
> + return entry;
> +}
> +
> +void *mas_find(struct ma_state *mas, unsigned long max)
> +{
> + if (mas_is_paused(mas)) {
> + if (mas->last == ULONG_MAX) {
> + mas->node = MAS_NONE;
> + return NULL;
> + }
> + mas->node = MAS_START;
> + mas->index = ++mas->last;
> + }
> +
> + if (mas_is_start(mas)) {
> + /* First run or continue */
> + void *entry;
> +
> + if (mas->index > max)
> + return NULL;
> +
> + entry = mas_walk(mas);
> + if (entry)
> + return entry;
> + }
> +
> + if (!mas_searchable(mas))
> + return NULL;
> +
> + /* Retries on dead nodes handled by mas_next_entry */
> + return mas_next_entry(mas, max);
> +}
> +
> +/***********************************************/
> +void maple_init(void)
> +{
> + int array_len;
> +
> + STRUCT_SIZE_INIT(maple_tree_struct, "maple_tree");
> + STRUCT_SIZE_INIT(maple_node_struct, "maple_node");
> +
> + MEMBER_OFFSET_INIT(maple_tree_ma_root, "maple_tree", "ma_root");
> + MEMBER_OFFSET_INIT(maple_tree_ma_flags, "maple_tree", "ma_flags");
> +
> + MEMBER_OFFSET_INIT(maple_node_parent, "maple_node", "parent");
> + MEMBER_OFFSET_INIT(maple_node_ma64, "maple_node", "ma64");
> + MEMBER_OFFSET_INIT(maple_node_mr64, "maple_node", "mr64");
> + MEMBER_OFFSET_INIT(maple_node_slot, "maple_node", "slot");
> +
> + MEMBER_OFFSET_INIT(maple_arange_64_parent, "maple_arange_64", "parent");
> + MEMBER_OFFSET_INIT(maple_arange_64_pivot, "maple_arange_64", "pivot");
> + MEMBER_OFFSET_INIT(maple_arange_64_slot, "maple_arange_64", "slot");
> + MEMBER_OFFSET_INIT(maple_arange_64_meta, "maple_arange_64", "meta");
> +
> + MEMBER_OFFSET_INIT(maple_range_64_parent, "maple_range_64", "parent");
> + MEMBER_OFFSET_INIT(maple_range_64_pivot, "maple_range_64", "pivot");
> + MEMBER_OFFSET_INIT(maple_range_64_slot, "maple_range_64", "slot");
> + MEMBER_OFFSET_INIT(maple_range_64_meta, "maple_range_64", "meta");
> +
> + MEMBER_OFFSET_INIT(maple_metadata_end, "maple_metadata", "end");
> +
> + array_len = get_array_length("mt_slots", NULL, sizeof(char));
> + mt_slots = calloc(array_len, sizeof(char));
> + readmem(symbol_value("mt_slots"), KVADDR, mt_slots,
> + array_len * sizeof(char), "maple_init read mt_slots",
> + FAULT_ON_ERROR);
> +
> + array_len = get_array_length("mt_pivots", NULL, sizeof(char));
> + mt_pivots = calloc(array_len, sizeof(char));
> + readmem(symbol_value("mt_pivots"), KVADDR, mt_pivots,
> + array_len * sizeof(char), "maple_init read mt_pivots",
> + FAULT_ON_ERROR);
> +}
> \ No newline at end of file
> diff --git a/maple_tree.h b/maple_tree.h
> new file mode 100644
> index 0000000..8b36c29
> --- /dev/null
> +++ b/maple_tree.h
> @@ -0,0 +1,214 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +#ifndef _MAPLE_TREE_H
> +#define _MAPLE_TREE_H
> +/*
> + * Maple Tree - An RCU-safe adaptive tree for storing ranges
> + * Copyright (c) 2018-2022 Oracle
> + * Authors: Liam R. Howlett <Liam.Howlett(a)Oracle.com>
> + * Matthew Wilcox <willy(a)infradead.org>
> + *
> + * eXtensible Arrays
> + * Copyright (c) 2017 Microsoft Corporation
> + * Author: Matthew Wilcox <willy(a)infradead.org>
> + *
> + * See Documentation/core-api/xarray.rst for how to use the XArray.
> + */
> +#include <stdbool.h>
> +#include <limits.h>
> +
> +/*
> + * The following are copied and modified from include/linux/maple_tree.h
> + *
> + * Keep the empty struct names for debug purpose of compiler warning.
> + * And can also keep the function prototypes consistent with kernel's
> + * corresponding functions.
> + */
> +struct maple_tree { };
> +struct maple_metadata { };
> +struct maple_range_64 { };
> +struct maple_arange_64 { };
> +struct maple_alloc { };
> +struct maple_node { };
> +
Is it possible to define them with the "void *" ? For example:
struct ma_state {
void *tree;
unsigned long index;
...
void *node;
...
};
Kernel may change them or move them out of the structure in the
future, in this situation crash won't have to change accordingly.
> +struct ma_state {
> + struct maple_tree *tree; /* The tree we're operating in */
> + unsigned long index; /* The index we're operating on - range start */
> + unsigned long last; /* The last index we're operating on - range end */
> + struct maple_enode *node; /* The node containing this entry */
> + unsigned long min; /* The minimum index of this node - implied pivot min */
> + unsigned long max; /* The maximum index of this node - implied pivot max */
> + struct maple_alloc *alloc; /* Allocated nodes for this operation */
> + unsigned char depth; /* depth of tree descent during write */
> + unsigned char offset;
> + unsigned char mas_flags;
> +};
> +
> +enum maple_type {
> + maple_dense,
> + maple_leaf_64,
> + maple_range_64,
> + maple_arange_64,
> +};
> +
> +#define MAS_START ((struct maple_enode *)1UL)
> +#define MAS_ROOT ((struct maple_enode *)5UL)
> +#define MAS_NONE ((struct maple_enode *)9UL)
> +#define MAS_PAUSE ((struct maple_enode *)17UL)
> +#define MA_ERROR(err) \
> + ((struct maple_enode *)(((unsigned long)err << 2) | 2UL))
> +
> +#define MA_STATE(name, mt, first, end) \
> + struct ma_state name = { \
> + .tree = mt, \
> + .index = first, \
> + .last = end, \
> + .node = MAS_START, \
> + .min = 0, \
> + .max = ULONG_MAX, \
> + }
The above two macros are unused.
> +
> +#define MAPLE_NODE_MASK 255UL
> +
> +#define MT_FLAGS_ALLOC_RANGE 0x01
> +#define MT_FLAGS_USE_RCU 0x02
Unused.
> +#define MT_FLAGS_HEIGHT_OFFSET 0x02
> +#define MT_FLAGS_HEIGHT_MASK 0x7C
> +#define MT_FLAGS_LOCK_MASK 0x300
> +#define MT_FLAGS_LOCK_IRQ 0x100
> +#define MT_FLAGS_LOCK_BH 0x200
> +#define MT_FLAGS_LOCK_EXTERN 0x300
The above four macros are unused.
> +
> +#define MAPLE_HEIGHT_MAX 31
Unused.
> +
> +#define MAPLE_NODE_TYPE_MASK 0x0F
> +#define MAPLE_NODE_TYPE_SHIFT 0x03
> +
> +#define MAPLE_RESERVED_RANGE 4096
> +
> +static inline void mas_reset(struct ma_state *mas)
> +{
> + mas->node = MAS_START;
> +}
> +
> +static inline
> +void mas_set_range(struct ma_state *mas, unsigned long start, unsigned long last)
> +{
> + mas->index = start;
> + mas->last = last;
> + mas->node = MAS_START;
> +}
> +
> +static inline void mas_set(struct ma_state *mas, unsigned long index)
> +{
> + mas_set_range(mas, index, index);
> +}
> +
> +static inline bool mas_is_none(struct ma_state *mas)
> +{
()> + return mas->node == MAS_NONE;
> +}
> +
> +static inline bool mas_is_paused(struct ma_state *mas)
> +{
> + return mas->node == MAS_PAUSE;
> +}
> +
> +/*
> + * The following are copied and modified from include/linux/xarray.h
> + */
> +
> +#define MAX_ERRNO 4095
The macro MAX_ERRNO is unused because the xa_is_err() is not called.
> +#define XA_ZERO_ENTRY xa_mk_internal(257)
> +#define XA_RETRY_ENTRY xa_mk_internal(256)
The macro XA_RETRY_ENTRY is unused because the xa_is_advanced() is not
called by other functions.
> +
> +static inline void *xa_mk_internal(unsigned long v)
> +{
> + return (void *)((v << 2) | 2);
> +}
> +
> +static inline bool xa_is_internal(const void *entry)
> +{
> + return ((unsigned long)entry & 3) == 2;
> +}
> +
> +static inline bool xa_is_err(const void *entry)
> +{
> + return xa_is_internal(entry) &&
> + entry >= xa_mk_internal(-MAX_ERRNO);
> +}
The xa_is_err() is unused.
> +
> +static inline int xa_err(void *entry)
> +{
> + /* xa_to_internal() would not do sign extension. */
> + if (xa_is_err(entry))
> + return (long)entry >> 2;
> + return 0;
> +}
Ditto.
> +
> +static inline bool xa_is_node(const void *entry)
> +{
> + return xa_is_internal(entry) && (unsigned long)entry > 4096;
> +}
> +
> +static inline bool xa_is_value(const void *entry)
> +{
> + return (unsigned long)entry & 1;
> +}
> +
> +static inline bool xa_is_zero(const void *entry)
> +{
> + return entry == XA_ZERO_ENTRY;
> +}
> +
> +static inline unsigned long xa_to_internal(const void *entry)
> +{
> + return (unsigned long)entry >> 2;
> +}
> +
> +static inline unsigned long xa_to_value(const void *entry)
> +{
> + return (unsigned long)entry >> 1;
> +}
> +
> +static inline bool xa_is_advanced(const void *entry)
> +{
> + return xa_is_internal(entry) && (entry <= XA_RETRY_ENTRY);
> +}
Ditto.
Thanks.
Lianbo
> +
> +/*
> + * The following are copied and modified from include/linux/mm.h
> + */
> +
> +struct vma_iterator {
> + struct ma_state mas;
> +};
> +
> +#define VMA_ITERATOR(name, mm_mt, addr) \
> + struct vma_iterator name = { \
> + .mas = { \
> + .tree = mm_mt, \
> + .index = addr, \
> + .node = MAS_START, \
> + }, \
> + }
> +
> +void *mas_find(struct ma_state *, unsigned long);
> +
> +static void *vma_find(struct vma_iterator *vmi, unsigned long max)
> +{
> + return mas_find(&vmi->mas, max);
> +}
> +
> + __attribute__((unused)) static void *vma_next(struct vma_iterator *vmi)
> +{
> + /*
> + * Uses vma_find() to get the first VMA when the iterator starts.
> + * Calling mas_next() could skip the first entry.
> + */
> + return vma_find(vmi, ULONG_MAX);
> +}
> +
> +#define for_each_vma(vmi, vma) \
> + while ((vma = (ulong)vma_next(&(vmi))) != 0)
> +
> +#endif /* _MAPLE_TREE_H */
> \ No newline at end of file
> --
> 2.33.1
1 year, 11 months
Re: [Crash-utility] [PATCH] task: ps: Provide an option to display no header line
by lijiang
Hi, Aaron
Thank you for the patch.
On Wed, Nov 30, 2022 at 8:30 PM <crash-utility-request(a)redhat.com> wrote:
> Date: Tue, 29 Nov 2022 14:05:26 +0000
> From: Aaron Tomlin <atomlin(a)redhat.com>
> To: crash-utility(a)redhat.com
> Cc: atomlin(a)atomlin.com
> Subject: [Crash-utility] [PATCH] task: ps: Provide an option to
> display no header line
> Message-ID: <20221129140526.1740542-1-atomlin(a)redhat.com>
> Content-Type: text/plain; charset="US-ASCII"; x-default=true
>
> One might often find it useful to redirect/or filter the output
> generated by the 'ps' command. This simple patch provides an option
> (i.e. '-H') to display no header line so it does not need to be
> considered e.g.
>
This looks good to me, so: Ack.
Thanks.
Lianbo
> crash> ps -u -H | head -5
> 1 0 1 ffff956e8028d280 IN 0.0 174276 9272 systemd
> 1067 1 2 ffff956e81380000 IN 0.1 59480 15788 systemd-journal
> 1080 1 0 ffff956e8d152940 IN 0.0 36196 3548 systemd-udevd
> 1278 1 6 ffff956e8aa60000 IN 0.0 17664 3072 systemd-oomd
> 1366 1 7 ffff956e88548000 IN 0.0 10868 2328 dbus-broker-lau
>
> Signed-off-by: Aaron Tomlin <atomlin(a)atomlin.com>
> ---
> help.c | 3 ++-
> task.c | 6 +++++-
> 2 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/help.c b/help.c
> index 99214c15..14981cd0 100644
> --- a/help.c
> +++ b/help.c
> @@ -1379,7 +1379,7 @@ NULL
> char *help_ps[] = {
> "ps",
> "display process status information",
> -"[-k|-u|-G|-y policy] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S|-A]\n [pid | task | command] ...",
> +"[-k|-u|-G|-y policy] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S|-A|-H]\n [pid | task | command] ...",
> " This command displays process status for selected, or all, processes" ,
> " in the system. If no arguments are entered, the process data is",
> " is displayed for all processes. Specific processes may be selected",
> @@ -1458,6 +1458,7 @@ char *help_ps[] = {
> " -r display resource limits (rlimits) of selected, or all, tasks.",
> " -S display a summary consisting of the number of tasks in a task state.",
> " -A display only the active task on each cpu.",
> +" -H display no header line.",
> "\nEXAMPLES",
> " Show the process status of all current tasks:\n",
> " %s> ps",
> diff --git a/task.c b/task.c
> index db2abc81..88941c7b 100644
> --- a/task.c
> +++ b/task.c
> @@ -3504,7 +3504,7 @@ cmd_ps(void)
> cpuspec = NULL;
> flag = 0;
>
> - while ((c = getopt(argcnt, args, "ASgstcpkuGlmarC:y:")) != EOF) {
> + while ((c = getopt(argcnt, args, "HASgstcpkuGlmarC:y:")) != EOF) {
> switch(c)
> {
> case 'k':
> @@ -3615,6 +3615,10 @@ cmd_ps(void)
> flag |= PS_ACTIVE;
> break;
>
> + case 'H':
> + flag |= PS_NO_HEADER;
> + break;
> +
> default:
> argerrs++;
> break;
> --
> 2.37.3
1 year, 11 months