From 8bff022b52abdf54f905f1b14f0ff5d36cad8d22 Mon Sep 17 00:00:00 2001 From: Dave Anderson Date: Mon, 28 Apr 2014 15:45:51 -0400 Subject: [PATCH] Fix for Linux 3.11 and later ARM kernels, in which all non-panicking cpus offline themselves during a kdump procedure. This causes an invalid cpu count determination during crash session initialization from an ARM vmcore. The patch utilizes the cpu count found in the cpu_active_map if it is greater than the count in the cpu_online_map. In addition, the maximum NR_CPUS value for the ARM architecture has been raised from 4 to 32. (sdu.liu@huawei.com) --- arm.c | 2 +- defs.h | 7 ++++- diskdump.c | 4 +-- kernel.c | 76 +++++++++++++++++++++++++++++++++++++++++++++--------- netdump.c | 4 +-- ppc.c | 6 ++--- ppc64.c | 22 +++++++++------- s390.c | 8 +++--- s390x.c | 8 +++--- 9 files changed, 98 insertions(+), 39 deletions(-) diff --git a/arm.c b/arm.c index 3c38cd5..84dd3ec 100644 --- a/arm.c +++ b/arm.c @@ -1518,7 +1518,7 @@ arm_display_machine_stats(void) static int arm_get_smp_cpus(void) { - return get_cpus_online(); + return MAX(get_cpus_active(), get_cpus_online()); } /* diff --git a/defs.h b/defs.h index b25c513..711b154 100644 --- a/defs.h +++ b/defs.h @@ -131,7 +131,7 @@ #define NR_CPUS (512) #endif #ifdef ARM -#define NR_CPUS (4) +#define NR_CPUS (32) #endif #ifdef ARM64 #define NR_CPUS (4096) /* TBD */ @@ -658,6 +658,10 @@ struct kernel_table { /* kernel data */ #define PRESENT (0x2) #define ONLINE (0x4) #define NMI (0x8) +#define POSSIBLE_MAP (POSSIBLE) +#define PRESENT_MAP (PRESENT) +#define ONLINE_MAP (ONLINE) +#define ACTIVE_MAP (0x10) int BUG_bytes; ulong xen_flags; #define WRITABLE_PAGE_TABLES (0x1) @@ -4795,6 +4799,7 @@ void set_cpu(int); void clear_machdep_cache(void); struct stack_hook *gather_text_list(struct bt_info *); int get_cpus_online(void); +int get_cpus_active(void); int get_cpus_present(void); int get_cpus_possible(void); int get_highest_cpu_online(void); diff --git a/diskdump.c b/diskdump.c index 0c5b4c9..e230c1f 100644 --- a/diskdump.c +++ b/diskdump.c @@ -119,7 +119,7 @@ map_cpus_to_prstatus_kdump_cmprs(void) nrcpus = (kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : NR_CPUS); for (i = 0, j = 0; i < nrcpus; i++) { - if (in_cpu_map(ONLINE, i)) { + if (in_cpu_map(ONLINE_MAP, i)) { dd->nt_prstatus_percpu[i] = nt_ptr[j++]; dd->num_prstatus_notes = MAX(dd->num_prstatus_notes, i+1); @@ -1193,7 +1193,7 @@ get_diskdump_panic_task(void) if (kernel_symbol_exists("crashing_cpu") && cpu_map_addr("online")) { get_symbol_data("crashing_cpu", sizeof(int), &i); - if ((i >= 0) && in_cpu_map(ONLINE, i)) { + if ((i >= 0) && in_cpu_map(ONLINE_MAP, i)) { if (CRASHDEBUG(1)) error(INFO, "get_diskdump_panic_task: " "active_set[%d]: %lx\n", diff --git a/kernel.c b/kernel.c index 0e56b6b..a4b09c1 100644 --- a/kernel.c +++ b/kernel.c @@ -795,9 +795,10 @@ cpu_maps_init(void) ulong cpu_flag; char *name; } mapinfo[] = { - { POSSIBLE, "possible" }, - { PRESENT, "present" }, - { ONLINE, "online" }, + { POSSIBLE_MAP, "possible" }, + { PRESENT_MAP, "present" }, + { ONLINE_MAP, "online" }, + { ACTIVE_MAP, "active" }, }; if ((len = STRUCT_SIZE("cpumask_t")) < 0) @@ -864,26 +865,33 @@ in_cpu_map(int map, int cpu) switch (map) { - case POSSIBLE: + case POSSIBLE_MAP: if (!cpu_map_addr("possible")) { error(INFO, "cpu_possible_map does not exist\n"); return FALSE; } - return (kt->cpu_flags[cpu] & POSSIBLE); + return (kt->cpu_flags[cpu] & POSSIBLE_MAP); - case PRESENT: + case PRESENT_MAP: if (!cpu_map_addr("present")) { error(INFO, "cpu_present_map does not exist\n"); return FALSE; } - return (kt->cpu_flags[cpu] & PRESENT); + return (kt->cpu_flags[cpu] & PRESENT_MAP); - case ONLINE: + case ONLINE_MAP: if (!cpu_map_addr("online")) { error(INFO, "cpu_online_map does not exist\n"); return FALSE; } - return (kt->cpu_flags[cpu] & ONLINE); + return (kt->cpu_flags[cpu] & ONLINE_MAP); + + case ACTIVE_MAP: + if (!cpu_map_addr("active")) { + error(INFO, "cpu_active_map does not exist\n"); + return FALSE; + } + return (kt->cpu_flags[cpu] & ACTIVE_MAP); } return FALSE; @@ -5321,7 +5329,7 @@ dump_kernel_table(int verbose) fprintf(fp, " cpu_possible_map: "); if (cpu_map_addr("possible")) { for (i = 0; i < nr_cpus; i++) { - if (kt->cpu_flags[i] & POSSIBLE) + if (kt->cpu_flags[i] & POSSIBLE_MAP) fprintf(fp, "%d ", i); } fprintf(fp, "\n"); @@ -5330,7 +5338,7 @@ dump_kernel_table(int verbose) fprintf(fp, " cpu_present_map: "); if (cpu_map_addr("present")) { for (i = 0; i < nr_cpus; i++) { - if (kt->cpu_flags[i] & PRESENT) + if (kt->cpu_flags[i] & PRESENT_MAP) fprintf(fp, "%d ", i); } fprintf(fp, "\n"); @@ -5339,12 +5347,22 @@ dump_kernel_table(int verbose) fprintf(fp, " cpu_online_map: "); if (cpu_map_addr("online")) { for (i = 0; i < nr_cpus; i++) { - if (kt->cpu_flags[i] & ONLINE) + if (kt->cpu_flags[i] & ONLINE_MAP) fprintf(fp, "%d ", i); } fprintf(fp, "\n"); } else fprintf(fp, "(does not exist)\n"); + fprintf(fp, " cpu_active_map: "); + if (cpu_map_addr("active")) { + for (i = 0; i < nr_cpus; i++) { + if (kt->cpu_flags[i] & ACTIVE_MAP) + fprintf(fp, "%d ", i); + } + fprintf(fp, "\n"); + } else + fprintf(fp, "(does not exist)\n"); + no_cpu_flags: fprintf(fp, " vmcoreinfo: \n"); fprintf(fp, " log_buf_SYMBOL: %lx\n", kt->vmcoreinfo.log_buf_SYMBOL); @@ -7972,6 +7990,40 @@ get_highest_cpu_online() return highest; } +/* + * If it exists, return the number of cpus in the cpu_active_map. + */ +int +get_cpus_active() +{ + int i, len, active; + char *buf; + ulong *maskptr, addr; + + if (!(addr = cpu_map_addr("active"))) + return 0; + + len = cpu_map_size("active"); + buf = GETBUF(len); + + active = 0; + + if (readmem(addr, KVADDR, buf, len, + "cpu_active_map", RETURN_ON_ERROR)) { + + maskptr = (ulong *)buf; + for (i = 0; i < (len/sizeof(ulong)); i++, maskptr++) + active += count_bits_long(*maskptr); + + if (CRASHDEBUG(1)) + error(INFO, "get_cpus_active: active: %d\n", active); + } + + FREEBUF(buf); + + return active; +} + /* * If it exists, return the number of cpus in the cpu_present_map. */ diff --git a/netdump.c b/netdump.c index 62aadef..c86a992 100644 --- a/netdump.c +++ b/netdump.c @@ -92,7 +92,7 @@ map_cpus_to_prstatus(void) nrcpus = (kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : NR_CPUS); for (i = 0, j = 0; i < nrcpus; i++) { - if (in_cpu_map(ONLINE, i)) + if (in_cpu_map(ONLINE_MAP, i)) nd->nt_prstatus_percpu[i] = nt_ptr[j++]; } @@ -769,7 +769,7 @@ get_netdump_panic_task(void) crashing_cpu = -1; if (kernel_symbol_exists("crashing_cpu")) { get_symbol_data("crashing_cpu", sizeof(int), &i); - if ((i >= 0) && in_cpu_map(ONLINE, i)) { + if ((i >= 0) && in_cpu_map(ONLINE_MAP, i)) { crashing_cpu = i; if (CRASHDEBUG(1)) error(INFO, diff --git a/ppc.c b/ppc.c index 742f47b..cf5bf56 100644 --- a/ppc.c +++ b/ppc.c @@ -1,8 +1,8 @@ /* ppc.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002-2007, 2010-2013 David Anderson - * Copyright (C) 2002-2007, 2010-2013 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002-2007, 2010-2014 David Anderson + * Copyright (C) 2002-2007, 2010-2014 Red Hat, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -2036,7 +2036,7 @@ ppc_relocate_nt_prstatus_percpu(void **nt_prstatus_percpu, *num_prstatus_notes = 0; nrcpus = (kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : NR_CPUS); for (i = 0, j = 0; i < nrcpus; i++) { - if (!in_cpu_map(ONLINE, i)) + if (!in_cpu_map(ONLINE_MAP, i)) continue; if (verify_crash_note_in_kernel(i)) nt_prstatus_percpu[i] = nt_ptr[j++]; diff --git a/ppc64.c b/ppc64.c index e302ac0..a2409eb 100644 --- a/ppc64.c +++ b/ppc64.c @@ -1,7 +1,7 @@ /* ppc64.c -- core analysis suite * - * Copyright (C) 2004-2013 David Anderson - * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2014 David Anderson + * Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved. * Copyright (C) 2004, 2006 Haren Myneni, IBM Corporation * * This program is free software; you can redistribute it and/or modify @@ -2861,16 +2861,18 @@ ppc64_get_cpu_map(void) int map; if (cpu_map_addr("possible")) - map = POSSIBLE; + map = POSSIBLE_MAP; else if (cpu_map_addr("present")) - map = PRESENT; + map = PRESENT_MAP; else if (cpu_map_addr("online")) - map = ONLINE; + map = ONLINE_MAP; + else if (cpu_map_addr("active")) + map = ACTIVE_MAP; else { map = 0; error(FATAL, - "PPC64: cannot find 'cpu_possible_map' or\ - 'cpu_present_map' or 'cpu_online_map' symbols\n"); + "PPC64: cannot find 'cpu_possible_map', " + "'cpu_present_map', 'cpu_online_map' or 'cpu_active_map' symbols\n"); } return map; } @@ -2911,15 +2913,15 @@ ppc64_init_cpu_info(void) } switch (map) { - case POSSIBLE: + case POSSIBLE_MAP: if (cpus > kt->cpus) { i = get_highest_cpu_online() + 1; if (i > kt->cpus) kt->cpus = i; } break; - case ONLINE: - case PRESENT: + case ONLINE_MAP: + case PRESENT_MAP: kt->cpus = cpus; break; } diff --git a/s390.c b/s390.c index 16cd58c..45da7c4 100644 --- a/s390.c +++ b/s390.c @@ -1,8 +1,8 @@ /* s390.c - core analysis suite * * Copyright (C) 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002-2006, 2009-2010, 2012-2013 David Anderson - * Copyright (C) 2002-2006, 2009-2010, 2012-2013 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002-2006, 2009-2010, 2012-2014 David Anderson + * Copyright (C) 2002-2006, 2009-2010, 2012-2014 Red Hat, Inc. All rights reserved. * Copyright (C) 2005, 2006, 2010 Michael Holzheu, IBM Corporation * * This program is free software; you can redistribute it and/or modify @@ -558,7 +558,7 @@ s390_has_cpu(struct bt_info *bt) { int cpu = bt->tc->processor; - if (is_task_active(bt->task) && (kt->cpu_flags[cpu] & ONLINE)) + if (is_task_active(bt->task) && (kt->cpu_flags[cpu] & ONLINE_MAP)) return TRUE; else return FALSE; @@ -619,7 +619,7 @@ s390_back_trace_cmd(struct bt_info *bt) error(WARNING, "instruction pointer argument ignored on this architecture!\n"); } - if (is_task_active(bt->task) && !(kt->cpu_flags[cpu] & ONLINE)) { + if (is_task_active(bt->task) && !(kt->cpu_flags[cpu] & ONLINE_MAP)) { fprintf(fp, " CPU offline\n"); return; } diff --git a/s390x.c b/s390x.c index 9294e64..82fd7f1 100644 --- a/s390x.c +++ b/s390x.c @@ -1,8 +1,8 @@ /* s390.c - core analysis suite * * Copyright (C) 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002-2006, 2009-2013 David Anderson - * Copyright (C) 2002-2006, 2009-2013 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002-2006, 2009-2014 David Anderson + * Copyright (C) 2002-2006, 2009-2014 Red Hat, Inc. All rights reserved. * Copyright (C) 2005, 2006, 2010-2013 Michael Holzheu, IBM Corporation * * This program is free software; you can redistribute it and/or modify @@ -872,7 +872,7 @@ s390x_has_cpu(struct bt_info *bt) { int cpu = bt->tc->processor; - if (is_task_active(bt->task) && (kt->cpu_flags[cpu] & ONLINE)) + if (is_task_active(bt->task) && (kt->cpu_flags[cpu] & ONLINE_MAP)) return TRUE; else return FALSE; @@ -1165,7 +1165,7 @@ static void s390x_back_trace_cmd(struct bt_info *bt) error(WARNING, "instruction pointer argument ignored on this architecture!\n"); } - if (is_task_active(bt->task) && !(kt->cpu_flags[cpu] & ONLINE)) { + if (is_task_active(bt->task) && !(kt->cpu_flags[cpu] & ONLINE_MAP)) { fprintf(fp, " CPU offline\n"); return; }