mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
riscv: crash: Add crash hotplug support
When CPUs or memory are hot-plugged on a running system, the crash dump's elfcorehdr -- which describes the available CPUs and memory to the capture kernel -- must be kept in sync, otherwise a crash after a hotplug event would produce a vmcore that does not reflect the current system topology. Enable crash hotplug for RISC-V by selecting ARCH_SUPPORTS_CRASH_HOTPLUG and providing the three architecture hooks invoked through the override macros in <asm/kexec.h>: arch_crash_hotplug_support() reports whether an image supports the mechanism; arch_crash_get_elfcorehdr_size() sizes the segment for NR_CPUS and, with memory hotplug, CRASH_MAX_MEMORY_RANGES; arch_crash_handle_hotplug_event() rebuilds the elfcorehdr through the crash_prepare_headers() helper and writes it over the old segment. The elfcorehdr is copied with memcpy_flushcache(), matching the x86 implementation; on RISC-V this currently expands to a plain memcpy() and will benefit automatically once the architecture provides a flushcache backend. The implementation otherwise follows the x86 crash hotplug model. Signed-off-by: Rui Qi <qirui.001@bytedance.com> Tested-by: Rui Qi <qirui.001@bytedance.com> Link: https://patch.msgid.link/20260910032619.2477279-1-qirui.001@bytedance.com Signed-off-by: Paul Walmsley <pjw@kernel.org>
This commit is contained in:
parent
f89e5ee4d8
commit
8be4655bc9
|
|
@ -1133,6 +1133,9 @@ config ARCH_DEFAULT_CRASH_DUMP
|
|||
config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
|
||||
def_bool CRASH_RESERVE
|
||||
|
||||
config ARCH_SUPPORTS_CRASH_HOTPLUG
|
||||
def_bool y
|
||||
|
||||
config COMPAT
|
||||
bool "Kernel support for 32-bit U-mode"
|
||||
default 64BIT
|
||||
|
|
|
|||
|
|
@ -75,4 +75,17 @@ int load_extra_segments(struct kimage *image, unsigned long kernel_start,
|
|||
unsigned long cmdline_len);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CRASH_HOTPLUG
|
||||
struct kimage;
|
||||
|
||||
void arch_crash_handle_hotplug_event(struct kimage *image, void *arg);
|
||||
#define arch_crash_handle_hotplug_event arch_crash_handle_hotplug_event
|
||||
|
||||
int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags);
|
||||
#define arch_crash_hotplug_support arch_crash_hotplug_support
|
||||
|
||||
unsigned int arch_crash_get_elfcorehdr_size(void);
|
||||
#define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ obj-$(CONFIG_KGDB) += kgdb.o
|
|||
obj-$(CONFIG_KEXEC_CORE) += kexec_relocate.o crash_save_regs.o machine_kexec.o
|
||||
obj-$(CONFIG_KEXEC_FILE) += kexec_elf.o kexec_image.o machine_kexec_file.o
|
||||
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
|
||||
obj-$(CONFIG_CRASH_HOTPLUG) += crash.o
|
||||
obj-$(CONFIG_VMCORE_INFO) += vmcore_info.o
|
||||
|
||||
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
|
||||
|
|
|
|||
113
arch/riscv/kernel/crash.c
Normal file
113
arch/riscv/kernel/crash.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* RISC-V crash hotplug support
|
||||
*
|
||||
* Copyright (C) 2025 Bytedance Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/crash_core.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#ifdef CONFIG_CRASH_HOTPLUG
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "crash hp: " fmt
|
||||
|
||||
int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags)
|
||||
{
|
||||
#ifdef CONFIG_KEXEC_FILE
|
||||
if (image->file_mode)
|
||||
return 1;
|
||||
#endif
|
||||
/*
|
||||
* For the kexec_load() syscall path, the user space kexec tool
|
||||
* needs to indicate that the elfcorehdr segment is excluded from
|
||||
* SHA verification by setting the appropriate flags.
|
||||
*/
|
||||
return (kexec_flags & KEXEC_UPDATE_ELFCOREHDR ||
|
||||
kexec_flags & KEXEC_CRASH_HOTPLUG_SUPPORT);
|
||||
}
|
||||
|
||||
unsigned int arch_crash_get_elfcorehdr_size(void)
|
||||
{
|
||||
unsigned int sz;
|
||||
|
||||
/* kernel_map, VMCOREINFO and maximum CPUs */
|
||||
sz = 2 + CONFIG_NR_CPUS;
|
||||
if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG))
|
||||
sz += CONFIG_CRASH_MAX_MEMORY_RANGES;
|
||||
sz *= sizeof(Elf64_Phdr);
|
||||
return sz;
|
||||
}
|
||||
|
||||
/**
|
||||
* arch_crash_handle_hotplug_event() - Handle hotplug elfcorehdr changes
|
||||
* @image: a pointer to kexec_crash_image
|
||||
* @arg: struct memory_notify handler for memory hotplug case and
|
||||
* NULL for CPU hotplug case.
|
||||
*
|
||||
* Prepare the new elfcorehdr and replace the existing elfcorehdr.
|
||||
*/
|
||||
void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
|
||||
{
|
||||
void *elfbuf = NULL, *old_elfcorehdr;
|
||||
unsigned long mem, memsz;
|
||||
unsigned long elfsz = 0;
|
||||
|
||||
/*
|
||||
* As crash_prepare_elf64_headers() has already described all
|
||||
* possible CPUs, there is no need to update the elfcorehdr
|
||||
* for additional CPU changes.
|
||||
*/
|
||||
if ((image->file_mode || image->elfcorehdr_updated) &&
|
||||
((image->hp_action == KEXEC_CRASH_HP_ADD_CPU) ||
|
||||
(image->hp_action == KEXEC_CRASH_HP_REMOVE_CPU)))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Create the new elfcorehdr reflecting the changes to CPU and/or
|
||||
* memory resources.
|
||||
*/
|
||||
if (crash_prepare_headers(true, &elfbuf, &elfsz, NULL)) {
|
||||
pr_err("unable to create new elfcorehdr");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain address and size of the elfcorehdr segment, and
|
||||
* check it against the new elfcorehdr buffer.
|
||||
*/
|
||||
mem = image->segment[image->elfcorehdr_index].mem;
|
||||
memsz = image->segment[image->elfcorehdr_index].memsz;
|
||||
if (elfsz > memsz) {
|
||||
pr_err("update elfcorehdr elfsz %lu > memsz %lu",
|
||||
elfsz, memsz);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy new elfcorehdr over the old elfcorehdr at destination.
|
||||
*/
|
||||
old_elfcorehdr = kmap_local_page(pfn_to_page(mem >> PAGE_SHIFT));
|
||||
if (!old_elfcorehdr) {
|
||||
pr_err("mapping elfcorehdr segment failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Temporarily invalidate the crash image while the
|
||||
* elfcorehdr is updated.
|
||||
*/
|
||||
xchg(&kexec_crash_image, NULL);
|
||||
memcpy_flushcache(old_elfcorehdr, elfbuf, elfsz);
|
||||
xchg(&kexec_crash_image, image);
|
||||
kunmap_local(old_elfcorehdr);
|
||||
pr_debug("updated elfcorehdr\n");
|
||||
|
||||
out:
|
||||
vfree(elfbuf);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CRASH_HOTPLUG */
|
||||
Loading…
Reference in New Issue
Block a user