----- Original Message ----- > > ----- Original Message ----- > > > > Current code is setting {hard,soft}irq_ctx[] to (irq_ctx **), because > > per_cpu symbol itself is pointer of specified type (irq_ctx *). > > > > But, I wonder how this works in past, the code is expecting > > {hard,soft}_ctx[] are (irq_ctx *). This fixes by deref per_cpu in > > initialization, and set expected pointers. > > > > Tested on i386 v3.10. > > > > You are correct -- apparently it never did work. > > The reason why I never noticed with RHEL kernels is that up until > linux-2.6.29, > the IRQ stacks were declared as a static NR_CPUS-bounded array: > > #ifdef CONFIG_4KSTACKS > /* > * per-CPU IRQ handling contexts (thread information and stack) > */ > union irq_ctx { > struct thread_info tinfo; > u32 stack[THREAD_SIZE/sizeof(u32)]; > }; > > static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly; > static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; > > static char softirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss; > static char hardirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss; > > > Then in linux-2.6.30, they were changed to be per-cpu variables: > > #ifdef CONFIG_4KSTACKS > /* > * per-CPU IRQ handling contexts (thread information and stack) > */ > union irq_ctx { > struct thread_info tinfo; > u32 stack[THREAD_SIZE/sizeof(u32)]; > } __attribute__((aligned(PAGE_SIZE))); > > static DEFINE_PER_CPU(union irq_ctx *, hardirq_ctx); > static DEFINE_PER_CPU(union irq_ctx *, softirq_ctx); > > static DEFINE_PER_CPU_PAGE_ALIGNED(union irq_ctx, hardirq_stack); > static DEFINE_PER_CPU_PAGE_ALIGNED(union irq_ctx, softirq_stack); > > We never ran into the bug in 32-bit x86 RHEL6 (2.6.32-based) kernels because > we did not configure CONFIG_4KSTACKS. > > Later on, the CONFIG_4KSTACKS restriction looks like it was removed, but we > stopped supporting 32-bit x86 in RHEL7. And nobody ever reported it from any > other x86 kernel sources. > > I also note that in linux-3.15 the data structure name and variables were > changed to: > > struct irq_stack { > u32 stack[THREAD_SIZE/sizeof(u32)]; > } __aligned(THREAD_SIZE); > > DECLARE_PER_CPU(struct irq_stack *, hardirq_stack); > DECLARE_PER_CPU(struct irq_stack *, softirq_stack); > > So your patch would need more work for 3.15 and later kernels. > > Thanks, > Dave Hi Ogawa, Please review the attached update to your patch, which adds support for the irq_ctx-to-irq_stack transition. Thanks, Dave
diff --git a/task.c b/task.c index 95d9130..661c104 100644 --- a/task.c +++ b/task.c @@ -567,13 +567,24 @@ irqstacks_init(void) thread_info_buf = GETBUF(SIZE(irq_ctx)); - if ((hard_sp = per_cpu_symbol_search("per_cpu__hardirq_ctx"))) { + if ((hard_sp = per_cpu_symbol_search("per_cpu__hardirq_ctx")) || + (hard_sp = per_cpu_symbol_search("per_cpu__hardirq_stack"))) { if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF)) { for (i = 0; i < NR_CPUS; i++) { + ulong ptr; + if (!kt->__per_cpu_offset[i]) continue; - tt->hardirq_ctx[i] = hard_sp->value + - kt->__per_cpu_offset[i]; + ptr = hard_sp->value + kt->__per_cpu_offset[i]; + + if (!readmem(ptr, KVADDR, &ptr, + sizeof(void *), "hardirq ctx", + RETURN_ON_ERROR)) { + error(INFO, "cannot read hardirq_ctx[%d] at %lx\n", + i, ptr); + continue; + } + tt->hardirq_ctx[i] = ptr; } } else tt->hardirq_ctx[0] = hard_sp->value; @@ -585,29 +596,42 @@ irqstacks_init(void) } else error(WARNING, "cannot determine hardirq_ctx addresses\n"); - for (i = 0; i < NR_CPUS; i++) { - if (!(tt->hardirq_ctx[i])) - continue; + if (MEMBER_EXISTS("irq_ctx", "tinfo")) { + for (i = 0; i < NR_CPUS; i++) { + if (!(tt->hardirq_ctx[i])) + continue; - if (!readmem(tt->hardirq_ctx[i], KVADDR, thread_info_buf, - SIZE(irq_ctx), "hardirq thread_union", - RETURN_ON_ERROR)) { - error(INFO, "cannot read hardirq_ctx[%d] at %lx\n", - i, tt->hardirq_ctx[i]); - continue; - } + if (!readmem(tt->hardirq_ctx[i], KVADDR, thread_info_buf, + SIZE(irq_ctx), "hardirq thread_union", + RETURN_ON_ERROR)) { + error(INFO, "cannot read hardirq_ctx[%d] at %lx\n", + i, tt->hardirq_ctx[i]); + continue; + } - tt->hardirq_tasks[i] = - ULONG(thread_info_buf+OFFSET(thread_info_task)); + tt->hardirq_tasks[i] = + ULONG(thread_info_buf+OFFSET(thread_info_task)); + } } - if ((soft_sp = per_cpu_symbol_search("per_cpu__softirq_ctx"))) { + if ((soft_sp = per_cpu_symbol_search("per_cpu__softirq_ctx")) || + (soft_sp = per_cpu_symbol_search("per_cpu__softirq_stack"))) { if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF)) { for (i = 0; i < NR_CPUS; i++) { + ulong ptr; + if (!kt->__per_cpu_offset[i]) continue; - tt->softirq_ctx[i] = soft_sp->value + - kt->__per_cpu_offset[i]; + ptr = soft_sp->value + kt->__per_cpu_offset[i]; + + if (!readmem(ptr, KVADDR, &ptr, + sizeof(void *), "softirq ctx", + RETURN_ON_ERROR)) { + error(INFO, "cannot read softirq_ctx[%d] at %lx\n", + i, ptr); + continue; + } + tt->softirq_ctx[i] = ptr; } } else tt->softirq_ctx[0] = soft_sp->value; @@ -619,21 +643,23 @@ irqstacks_init(void) } else error(WARNING, "cannot determine softirq_ctx addresses\n"); - for (i = 0; i < NR_CPUS; i++) { - if (!(tt->softirq_ctx[i])) - continue; - - if (!readmem(tt->softirq_ctx[i], KVADDR, thread_info_buf, - SIZE(irq_ctx), "softirq thread_union", - RETURN_ON_ERROR)) { - error(INFO, "cannot read softirq_ctx[%d] at %lx\n", - i, tt->hardirq_ctx[i]); - continue; - } - - tt->softirq_tasks[i] = - ULONG(thread_info_buf+OFFSET(thread_info_task)); - } + if (MEMBER_EXISTS("irq_ctx", "tinfo")) { + for (i = 0; i < NR_CPUS; i++) { + if (!(tt->softirq_ctx[i])) + continue; + + if (!readmem(tt->softirq_ctx[i], KVADDR, thread_info_buf, + SIZE(irq_ctx), "softirq thread_union", + RETURN_ON_ERROR)) { + error(INFO, "cannot read softirq_ctx[%d] at %lx\n", + i, tt->hardirq_ctx[i]); + continue; + } + + tt->softirq_tasks[i] = + ULONG(thread_info_buf+OFFSET(thread_info_task)); + } + } tt->flags |= IRQSTACKS; diff --git a/x86.c b/x86.c index 54ce7a5..27bf0ea 100644 --- a/x86.c +++ b/x86.c @@ -1963,6 +1963,8 @@ x86_init(int when) STRUCT_SIZE_INIT(e820map, "e820map"); STRUCT_SIZE_INIT(e820entry, "e820entry"); STRUCT_SIZE_INIT(irq_ctx, "irq_ctx"); + if (!VALID_STRUCT(irq_ctx)) + STRUCT_SIZE_INIT(irq_ctx, "irq_stack"); MEMBER_OFFSET_INIT(e820map_nr_map, "e820map", "nr_map"); MEMBER_OFFSET_INIT(e820entry_addr, "e820entry", "addr"); MEMBER_OFFSET_INIT(e820entry_size, "e820entry", "size");
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility