Skip to content

Commit e789d44

Browse files
committed
Merge branch 'topic/kdump-hotplug' into next
Merge our topic branch containing kdump hotplug changes, more detail from the original cover letter: Commit 2472627 ("crash: add generic infrastructure for crash hotplug support") added a generic infrastructure that allows architectures to selectively update the kdump image component during CPU or memory add/remove events within the kernel itself. This patch series adds crash hotplug handler for PowerPC and enable support to update the kdump image on CPU/Memory add/remove events. Among the 6 patches in this series, the first two patches make changes to the generic crash hotplug handler to assist PowerPC in adding support for this feature. The last four patches add support for this feature. The following section outlines the problem addressed by this patch series, along with the current solution, its shortcomings, and the proposed resolution. Problem: ======== Due to CPU/Memory hotplug or online/offline events the elfcorehdr (which describes the CPUs and memory of the crashed kernel) and FDT (Flattened Device Tree) of kdump image becomes outdated. Consequently, attempting dump collection with an outdated elfcorehdr or FDT can lead to failed or inaccurate dump collection. Going forward CPU hotplug or online/offline events are referred as CPU/Memory add/remove events. Existing solution and its shortcoming: ====================================== The current solution to address the above issue involves monitoring the CPU/memory add/remove events in userspace using udev rules and whenever there are changes in CPU and memory resources, the entire kdump image is loaded again. The kdump image includes kernel, initrd, elfcorehdr, FDT, purgatory. Given that only elfcorehdr and FDT get outdated due to CPU/Memory add/remove events, reloading the entire kdump image is inefficient. More importantly, kdump remains inactive for a substantial amount of time until the kdump reload completes. Proposed solution: ================== Instead of initiating a full kdump image reload from userspace on CPU/Memory hotplug and online/offline events, the proposed solution aims to update only the necessary kdump image component within the kernel itself.
2 parents 6d4e52f + 9803af2 commit e789d44

File tree

19 files changed

+713
-359
lines changed

19 files changed

+713
-359
lines changed

arch/powerpc/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,10 @@ config ARCH_SELECTS_CRASH_DUMP
686686
depends on CRASH_DUMP
687687
select RELOCATABLE if PPC64 || 44x || PPC_85xx
688688

689+
config ARCH_SUPPORTS_CRASH_HOTPLUG
690+
def_bool y
691+
depends on PPC64
692+
689693
config FA_DUMP
690694
bool "Firmware-assisted dump"
691695
depends on CRASH_DUMP && PPC64 && (PPC_RTAS || PPC_POWERNV)

arch/powerpc/include/asm/kexec.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,17 @@ static inline void crash_setup_regs(struct pt_regs *newregs,
135135
ppc_save_regs(newregs);
136136
}
137137

138+
#ifdef CONFIG_CRASH_HOTPLUG
139+
void arch_crash_handle_hotplug_event(struct kimage *image, void *arg);
140+
#define arch_crash_handle_hotplug_event arch_crash_handle_hotplug_event
141+
142+
int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags);
143+
#define arch_crash_hotplug_support arch_crash_hotplug_support
144+
145+
unsigned int arch_crash_get_elfcorehdr_size(void);
146+
#define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size
147+
#endif /* CONFIG_CRASH_HOTPLUG */
148+
138149
extern int crashing_cpu;
139150
extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *));
140151
extern void crash_ipi_callback(struct pt_regs *regs);
@@ -185,6 +196,10 @@ static inline void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
185196

186197
#endif /* CONFIG_CRASH_DUMP */
187198

199+
#if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_DUMP)
200+
int update_cpus_node(void *fdt);
201+
#endif
202+
188203
#ifdef CONFIG_PPC_BOOK3S_64
189204
#include <asm/book3s/64/kexec.h>
190205
#endif

arch/powerpc/include/asm/kexec_ranges.h

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,9 @@
77
void sort_memory_ranges(struct crash_mem *mrngs, bool merge);
88
struct crash_mem *realloc_mem_ranges(struct crash_mem **mem_ranges);
99
int add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size);
10-
int add_tce_mem_ranges(struct crash_mem **mem_ranges);
11-
int add_initrd_mem_range(struct crash_mem **mem_ranges);
12-
#ifdef CONFIG_PPC_64S_HASH_MMU
13-
int add_htab_mem_range(struct crash_mem **mem_ranges);
14-
#else
15-
static inline int add_htab_mem_range(struct crash_mem **mem_ranges)
16-
{
17-
return 0;
18-
}
19-
#endif
20-
int add_kernel_mem_range(struct crash_mem **mem_ranges);
21-
int add_rtas_mem_range(struct crash_mem **mem_ranges);
22-
int add_opal_mem_range(struct crash_mem **mem_ranges);
23-
int add_reserved_mem_ranges(struct crash_mem **mem_ranges);
24-
10+
int remove_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size);
11+
int get_exclude_memory_ranges(struct crash_mem **mem_ranges);
12+
int get_reserved_memory_ranges(struct crash_mem **mem_ranges);
13+
int get_crash_memory_ranges(struct crash_mem **mem_ranges);
14+
int get_usable_memory_ranges(struct crash_mem **mem_ranges);
2515
#endif /* _ASM_POWERPC_KEXEC_RANGES_H */

arch/powerpc/kexec/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
# Makefile for the linux kernel.
44
#
55

6-
obj-y += core.o core_$(BITS).o
6+
obj-y += core.o core_$(BITS).o ranges.o
77

88
obj-$(CONFIG_PPC32) += relocate_32.o
99

10-
obj-$(CONFIG_KEXEC_FILE) += file_load.o ranges.o file_load_$(BITS).o elf_$(BITS).o
10+
obj-$(CONFIG_KEXEC_FILE) += file_load.o file_load_$(BITS).o elf_$(BITS).o
1111
obj-$(CONFIG_VMCORE_INFO) += vmcore_info.o
1212
obj-$(CONFIG_CRASH_DUMP) += crash.o
1313

arch/powerpc/kexec/core_64.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/cpu.h>
1818
#include <linux/hardirq.h>
1919
#include <linux/of.h>
20+
#include <linux/libfdt.h>
2021

2122
#include <asm/page.h>
2223
#include <asm/current.h>
@@ -30,6 +31,7 @@
3031
#include <asm/hw_breakpoint.h>
3132
#include <asm/svm.h>
3233
#include <asm/ultravisor.h>
34+
#include <asm/crashdump-ppc64.h>
3335

3436
int machine_kexec_prepare(struct kimage *image)
3537
{
@@ -419,3 +421,92 @@ static int __init export_htab_values(void)
419421
}
420422
late_initcall(export_htab_values);
421423
#endif /* CONFIG_PPC_64S_HASH_MMU */
424+
425+
#if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_DUMP)
426+
/**
427+
* add_node_props - Reads node properties from device node structure and add
428+
* them to fdt.
429+
* @fdt: Flattened device tree of the kernel
430+
* @node_offset: offset of the node to add a property at
431+
* @dn: device node pointer
432+
*
433+
* Returns 0 on success, negative errno on error.
434+
*/
435+
static int add_node_props(void *fdt, int node_offset, const struct device_node *dn)
436+
{
437+
int ret = 0;
438+
struct property *pp;
439+
440+
if (!dn)
441+
return -EINVAL;
442+
443+
for_each_property_of_node(dn, pp) {
444+
ret = fdt_setprop(fdt, node_offset, pp->name, pp->value, pp->length);
445+
if (ret < 0) {
446+
pr_err("Unable to add %s property: %s\n", pp->name, fdt_strerror(ret));
447+
return ret;
448+
}
449+
}
450+
return ret;
451+
}
452+
453+
/**
454+
* update_cpus_node - Update cpus node of flattened device tree using of_root
455+
* device node.
456+
* @fdt: Flattened device tree of the kernel.
457+
*
458+
* Returns 0 on success, negative errno on error.
459+
*/
460+
int update_cpus_node(void *fdt)
461+
{
462+
struct device_node *cpus_node, *dn;
463+
int cpus_offset, cpus_subnode_offset, ret = 0;
464+
465+
cpus_offset = fdt_path_offset(fdt, "/cpus");
466+
if (cpus_offset < 0 && cpus_offset != -FDT_ERR_NOTFOUND) {
467+
pr_err("Malformed device tree: error reading /cpus node: %s\n",
468+
fdt_strerror(cpus_offset));
469+
return cpus_offset;
470+
}
471+
472+
if (cpus_offset > 0) {
473+
ret = fdt_del_node(fdt, cpus_offset);
474+
if (ret < 0) {
475+
pr_err("Error deleting /cpus node: %s\n", fdt_strerror(ret));
476+
return -EINVAL;
477+
}
478+
}
479+
480+
/* Add cpus node to fdt */
481+
cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), "cpus");
482+
if (cpus_offset < 0) {
483+
pr_err("Error creating /cpus node: %s\n", fdt_strerror(cpus_offset));
484+
return -EINVAL;
485+
}
486+
487+
/* Add cpus node properties */
488+
cpus_node = of_find_node_by_path("/cpus");
489+
ret = add_node_props(fdt, cpus_offset, cpus_node);
490+
of_node_put(cpus_node);
491+
if (ret < 0)
492+
return ret;
493+
494+
/* Loop through all subnodes of cpus and add them to fdt */
495+
for_each_node_by_type(dn, "cpu") {
496+
cpus_subnode_offset = fdt_add_subnode(fdt, cpus_offset, dn->full_name);
497+
if (cpus_subnode_offset < 0) {
498+
pr_err("Unable to add %s subnode: %s\n", dn->full_name,
499+
fdt_strerror(cpus_subnode_offset));
500+
ret = cpus_subnode_offset;
501+
goto out;
502+
}
503+
504+
ret = add_node_props(fdt, cpus_subnode_offset, dn);
505+
if (ret < 0)
506+
goto out;
507+
}
508+
out:
509+
of_node_put(dn);
510+
return ret;
511+
}
512+
#endif /* CONFIG_KEXEC_FILE || CONFIG_CRASH_DUMP */

0 commit comments

Comments
 (0)