From 38d35bd1423ccafd0b8be0744155ce59ef3034ff Mon Sep 17 00:00:00 2001 From: Kazuhito Hagio Date: Wed, 12 Jul 2023 17:55:29 +0900 Subject: [PATCH 19/30] Fix "irq [-a|-s]" options on Linux 6.5-rc1 and later Kernel commit 721255b982 ("genirq: Use a maple tree for interrupt descriptor management"), which is contained in Linux 6.5-rc1 and later kernels, replaced irq_desc_tree with a maple tree sparse_irqs. Without the patch, "irq [-a|-s]" options fail with an error, e.g. the following on x86_64, on kernels configured with CONFIG_SPARSE_IRQ=y. crash> irq irq: x86_64_dump_irq: irq_desc[] or irq_desc_tree do not exist? Signed-off-by: Kazuhito Hagio Signed-off-by: Lianbo Jiang --- defs.h | 2 ++ ia64.c | 3 ++- kernel.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++--- symbols.c | 1 + x86_64.c | 9 ++++++--- 5 files changed, 59 insertions(+), 7 deletions(-) diff --git a/defs.h b/defs.h index 26afe232cc3e..358f365585cf 100644 --- a/defs.h +++ b/defs.h @@ -676,6 +676,7 @@ struct new_utsname { #define IRQ_DESC_TREE_XARRAY (0x80ULL) #define KMOD_PAX (0x100ULL) #define KMOD_MEMORY (0x200ULL) +#define IRQ_DESC_TREE_MAPLE (0x400ULL) #define XEN() (kt->flags & ARCH_XEN) #define OPENVZ() (kt->flags & ARCH_OPENVZ) @@ -2222,6 +2223,7 @@ struct offset_table { /* stash of commonly-used offsets */ long module_mem; long module_memory_base; long module_memory_size; + long irq_data_irq; }; struct size_table { /* stash of commonly-used sizes */ diff --git a/ia64.c b/ia64.c index 2e1d15fe6042..d3e0a3b01869 100644 --- a/ia64.c +++ b/ia64.c @@ -791,7 +791,8 @@ ia64_back_trace_cmd(struct bt_info *bt) static void ia64_dump_irq(int irq) { - if (symbol_exists("irq_desc") || symbol_exists("_irq_desc") || + if (kernel_symbol_exists("sparse_irqs") || + symbol_exists("irq_desc") || symbol_exists("_irq_desc") || kernel_symbol_exists("irq_desc_ptrs")) { machdep->dump_irq = generic_dump_irq; return(generic_dump_irq(irq)); diff --git a/kernel.c b/kernel.c index 0fc77c19f12a..546eed95eebd 100644 --- a/kernel.c +++ b/kernel.c @@ -541,7 +541,10 @@ kernel_init() MEMBER_OFFSET_INIT(irqaction_dev_id, "irqaction", "dev_id"); MEMBER_OFFSET_INIT(irqaction_next, "irqaction", "next"); - if (kernel_symbol_exists("irq_desc_tree")) { + /* 6.5 and later: CONFIG_SPARSE_IRQ */ + if (kernel_symbol_exists("sparse_irqs")) + kt->flags2 |= IRQ_DESC_TREE_MAPLE; + else if (kernel_symbol_exists("irq_desc_tree")) { get_symbol_type("irq_desc_tree", NULL, &req); if (STREQ(req.type_tag_name, "xarray")) { kt->flags2 |= IRQ_DESC_TREE_XARRAY; @@ -554,6 +557,7 @@ kernel_init() } STRUCT_SIZE_INIT(irq_data, "irq_data"); if (VALID_STRUCT(irq_data)) { + MEMBER_OFFSET_INIT(irq_data_irq, "irq_data", "irq"); MEMBER_OFFSET_INIT(irq_data_chip, "irq_data", "chip"); MEMBER_OFFSET_INIT(irq_data_affinity, "irq_data", "affinity"); MEMBER_OFFSET_INIT(irq_desc_irq_data, "irq_desc", "irq_data"); @@ -6180,6 +6184,8 @@ dump_kernel_table(int verbose) fprintf(fp, "%sIRQ_DESC_TREE_RADIX", others++ ? "|" : ""); if (kt->flags2 & IRQ_DESC_TREE_XARRAY) fprintf(fp, "%sIRQ_DESC_TREE_XARRAY", others++ ? "|" : ""); + if (kt->flags2 & IRQ_DESC_TREE_MAPLE) + fprintf(fp, "%sIRQ_DESC_TREE_MAPLE", others++ ? "|" : ""); if (kt->flags2 & KMOD_PAX) fprintf(fp, "%sKMOD_PAX", others++ ? "|" : ""); if (kt->flags2 & KMOD_MEMORY) @@ -6652,6 +6658,45 @@ get_irq_desc_addr(int irq) readmem(ptr, KVADDR, &addr, sizeof(void *), "irq_desc_ptrs entry", FAULT_ON_ERROR); + } else if (kt->flags2 & IRQ_DESC_TREE_MAPLE) { + unsigned int i; + + if (kt->highest_irq && (irq > kt->highest_irq)) + return addr; + + cnt = do_maple_tree(symbol_value("sparse_irqs"), MAPLE_TREE_COUNT, NULL); + + len = sizeof(struct list_pair) * (cnt+1); + lp = (struct list_pair *)GETBUF(len); + lp[0].index = cnt; /* maxcount */ + + cnt = do_maple_tree(symbol_value("sparse_irqs"), MAPLE_TREE_GATHER, lp); + + /* + * NOTE: We cannot use lp.index like Radix Tree or XArray because + * it's not an absolute index and just counter in Maple Tree. + */ + if (kt->highest_irq == 0) { + readmem((ulong)lp[cnt-1].value + + OFFSET(irq_desc_irq_data) + OFFSET(irq_data_irq), + KVADDR, &kt->highest_irq, sizeof(int), "irq_data.irq", + FAULT_ON_ERROR); + } + + for (c = 0; c < cnt; c++) { + readmem((ulong)lp[c].value + + OFFSET(irq_desc_irq_data) + OFFSET(irq_data_irq), + KVADDR, &i, sizeof(int), "irq_data.irq", FAULT_ON_ERROR); + if (i == irq) { + if (CRASHDEBUG(1)) + fprintf(fp, "index: %d value: %lx\n", + i, (ulong)lp[c].value); + addr = (ulong)lp[c].value; + break; + } + } + FREEBUF(lp); + } else if (kt->flags2 & (IRQ_DESC_TREE_RADIX|IRQ_DESC_TREE_XARRAY)) { if (kt->highest_irq && (irq > kt->highest_irq)) return addr; @@ -6700,8 +6745,8 @@ get_irq_desc_addr(int irq) FREEBUF(lp); } else { error(FATAL, - "neither irq_desc, _irq_desc, irq_desc_ptrs " - "or irq_desc_tree symbols exist\n"); + "neither irq_desc, _irq_desc, irq_desc_ptrs, " + "irq_desc_tree or sparse_irqs symbols exist\n"); } return addr; diff --git a/symbols.c b/symbols.c index 82529a6785c9..876be7aea90e 100644 --- a/symbols.c +++ b/symbols.c @@ -10375,6 +10375,7 @@ dump_offset_table(char *spec, ulong makestruct) OFFSET(irq_desc_t_kstat_irqs)); fprintf(fp, " irq_desc_t_affinity: %ld\n", OFFSET(irq_desc_t_affinity)); + fprintf(fp, " irq_data_irq: %ld\n", OFFSET(irq_data_irq)); fprintf(fp, " irq_data_chip: %ld\n", OFFSET(irq_data_chip)); fprintf(fp, " irq_data_affinity: %ld\n", diff --git a/x86_64.c b/x86_64.c index 87e87ae6e1e8..42ade4817ad9 100644 --- a/x86_64.c +++ b/x86_64.c @@ -5391,7 +5391,8 @@ get_x86_64_frame(struct bt_info *bt, ulong *getpc, ulong *getsp) static void x86_64_dump_irq(int irq) { - if (symbol_exists("irq_desc") || + if (kernel_symbol_exists("sparse_irqs") || + symbol_exists("irq_desc") || kernel_symbol_exists("irq_desc_ptrs") || kernel_symbol_exists("irq_desc_tree")) { machdep->dump_irq = generic_dump_irq; @@ -5405,7 +5406,8 @@ x86_64_dump_irq(int irq) static void x86_64_get_irq_affinity(int irq) { - if (symbol_exists("irq_desc") || + if (kernel_symbol_exists("sparse_irqs") || + symbol_exists("irq_desc") || kernel_symbol_exists("irq_desc_ptrs") || kernel_symbol_exists("irq_desc_tree")) { machdep->get_irq_affinity = generic_get_irq_affinity; @@ -5419,7 +5421,8 @@ x86_64_get_irq_affinity(int irq) static void x86_64_show_interrupts(int irq, ulong *cpus) { - if (symbol_exists("irq_desc") || + if (kernel_symbol_exists("sparse_irqs") || + symbol_exists("irq_desc") || kernel_symbol_exists("irq_desc_ptrs") || kernel_symbol_exists("irq_desc_tree")) { machdep->show_interrupts = generic_show_interrupts; -- 2.37.1