History

crash: hotplug support for kexec_load()

The hotplug support for kexec_load() requires changes to the userspace kexec-tools and a little extra help from the kernel. Given a kdump capture kernel loaded via kexec_load(), and a subsequent hotplug event, the crash hotplug handler finds the elfcorehdr and rewrites it to reflect the hotplug change. That is the desired outcome, however, at kernel panic time, the purgatory integrity check fails (because the elfcorehdr changed), and the capture kernel does not boot and no vmcore is generated. Therefore, the userspace kexec-tools/kexec must indicate to the kernel that the elfcorehdr can be modified (because the kexec excluded the elfcorehdr from the digest, and sized the elfcorehdr memory buffer appropriately). To facilitate hotplug support with kexec_load(): - a new kexec flag KEXEC_UPATE_ELFCOREHDR indicates that it is safe for the kernel to modify the kexec_load()'d elfcorehdr - the /sys/kernel/crash_elfcorehdr_size node communicates the preferred size of the elfcorehdr memory buffer - The sysfs crash_hotplug nodes (ie. /sys/devices/system/[cpu|memory]/crash_hotplug) dynamically take into account kexec_file_load() vs kexec_load() and KEXEC_UPDATE_ELFCOREHDR. This is critical so that the udev rule processing of crash_hotplug is all that is needed to determine if the userspace unload-then-load of the kdump image is to be skipped, or not. The proposed udev rule change looks like: # The kernel updates the crash elfcorehdr for CPU and memory changes SUBSYSTEM=="cpu", ATTRS{crash_hotplug}=="1", GOTO="kdump_reload_end" SUBSYSTEM=="memory", ATTRS{crash_hotplug}=="1", GOTO="kdump_reload_end" The table below indicates the behavior of kexec_load()'d kdump image updates (with the new udev crash_hotplug rule in place): Kernel |Kexec -------+-----+---- Old |Old |New | a | a -------+-----+---- New | a | b -------+-----+---- where kexec 'old' and 'new' delineate kexec-tools has the needed modifications for the crash hotplug feature, and kernel 'old' and 'new' delineate the kernel supports this crash hotplug feature. Behavior 'a' indicates the unload-then-reload of the entire kdump image. For the kexec 'old' column, the unload-then-reload occurs due to the missing flag KEXEC_UPDATE_ELFCOREHDR. An 'old' kernel (with 'new' kexec) does not present the crash_hotplug sysfs node, which leads to the unload-then-reload of the kdump image. Behavior 'b' indicates the desired optimized behavior of the kernel directly modifying the elfcorehdr and avoiding the unload-then-reload of the kdump image. If the udev rule is not updated with crash_hotplug node check, then no matter any combination of kernel or kexec is new or old, the kdump image continues to be unload-then-reload on hotplug changes. To fully support crash hotplug feature, there needs to be a rollout of kernel, kexec-tools and udev rule changes. However, the order of the rollout of these pieces does not matter; kexec_load()'d kdump images still function for hotplug as-is.

Eric DeVolder committed 3 years ago

Commit a72bbec1 parent ea53ad98 files · +102 −6Browse files

Unified · Split

8 files
  1. arch/x86/include/asm/kexec.h +7 −4
  2. arch/x86/kernel/crash.c +27 −0
  3. include/linux/kexec.h +12 −2
  4. include/uapi/linux/kexec.h +1 −0
  5. kernel/Kconfig.kexec +4 −0
  6. kernel/crash_core.c +31 −0
  7. kernel/kexec.c +5 −0
  8. kernel/ksysfs.c +15 −0
arch/x86/include/asm/kexec.h+7−4
@@ -214,14 +214,17 @@ void arch_crash_handle_hotplug_event(struct kimage *image); · 213 unmodified lines
214#define arch_crash_handle_hotplug_event arch_crash_handle_hotplug_event214#define arch_crash_handle_hotplug_event arch_crash_handle_hotplug_event
215 215
216#ifdef CONFIG_HOTPLUG_CPU216#ifdef CONFIG_HOTPLUG_CPU
217static inline int crash_hotplug_cpu_support(void) { return 1; }217int arch_crash_hotplug_cpu_support(void);
218#define crash_hotplug_cpu_support crash_hotplug_cpu_support218#define crash_hotplug_cpu_support arch_crash_hotplug_cpu_support
219#endif219#endif
220 220
221#ifdef CONFIG_MEMORY_HOTPLUG221#ifdef CONFIG_MEMORY_HOTPLUG
222static inline int crash_hotplug_memory_support(void) { return 1; }222int arch_crash_hotplug_memory_support(void);
223#define crash_hotplug_memory_support crash_hotplug_memory_support223#define crash_hotplug_memory_support arch_crash_hotplug_memory_support
224#endif224#endif
225
226unsigned int arch_crash_get_elfcorehdr_size(void);
227#define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size
225#endif228#endif
226 229
227#endif /* __ASSEMBLY__ */230#endif /* __ASSEMBLY__ */
arch/x86/kernel/crash.c+27−0
@@ -429,6 +429,33 @@ int crash_load_segments(struct kimage *image) · 428 unmodified lines
429#undef pr_fmt429#undef pr_fmt
430#define pr_fmt(fmt) "crash hp: " fmt430#define pr_fmt(fmt) "crash hp: " fmt
431 431
432/* These functions provide the value for the sysfs crash_hotplug nodes */
433#ifdef CONFIG_HOTPLUG_CPU
434int arch_crash_hotplug_cpu_support(void)
435{
436 return crash_check_update_elfcorehdr();
437}
438#endif
439
440#ifdef CONFIG_MEMORY_HOTPLUG
441int arch_crash_hotplug_memory_support(void)
442{
443 return crash_check_update_elfcorehdr();
444}
445#endif
446
447unsigned int arch_crash_get_elfcorehdr_size(void)
448{
449 unsigned int sz;
450
451 /* kernel_map, VMCOREINFO and maximum CPUs */
452 sz = 2 + CONFIG_NR_CPUS_DEFAULT;
453 if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG))
454 sz += CONFIG_CRASH_MAX_MEMORY_RANGES;
455 sz *= sizeof(Elf64_Phdr);
456 return sz;
457}
458
432/**459/**
433 * arch_crash_handle_hotplug_event() - Handle hotplug elfcorehdr changes460 * arch_crash_handle_hotplug_event() - Handle hotplug elfcorehdr changes
434 * @image: a pointer to kexec_crash_image461 * @image: a pointer to kexec_crash_image
include/linux/kexec.h+12−2
@@ -320,6 +320,10 @@ struct kimage { · 319 unmodified lines
320 unsigned int preserve_context : 1;320 unsigned int preserve_context : 1;
321 /* If set, we are using file mode kexec syscall */321 /* If set, we are using file mode kexec syscall */
322 unsigned int file_mode:1;322 unsigned int file_mode:1;
323#ifdef CONFIG_CRASH_HOTPLUG
324 /* If set, allow changes to elfcorehdr of kexec_load'd image */
325 unsigned int update_elfcorehdr:1;
326#endif
323 327
324#ifdef ARCH_HAS_KIMAGE_ARCH328#ifdef ARCH_HAS_KIMAGE_ARCH
325 struct kimage_arch arch;329 struct kimage_arch arch;
@@ -396,9 +400,9 @@ bool kexec_load_permitted(int kexec_image_type); · 70 unmodified lines
396 400
397/* List of defined/legal kexec flags */401/* List of defined/legal kexec flags */
398#ifndef CONFIG_KEXEC_JUMP402#ifndef CONFIG_KEXEC_JUMP
399#define KEXEC_FLAGS KEXEC_ON_CRASH403#define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_UPDATE_ELFCOREHDR)
400#else404#else
401#define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)405#define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT | KEXEC_UPDATE_ELFCOREHDR)
402#endif406#endif
403 407
404/* List of defined/legal kexec file flags */408/* List of defined/legal kexec file flags */
@@ -486,6 +490,8 @@ static inline void arch_kexec_pre_free_pages(void *vaddr, unsigned int pages) { · 81 unmodified lines
486static inline void arch_crash_handle_hotplug_event(struct kimage *image) { }490static inline void arch_crash_handle_hotplug_event(struct kimage *image) { }
487#endif491#endif
488 492
493int crash_check_update_elfcorehdr(void);
494
489#ifndef crash_hotplug_cpu_support495#ifndef crash_hotplug_cpu_support
490static inline int crash_hotplug_cpu_support(void) { return 0; }496static inline int crash_hotplug_cpu_support(void) { return 0; }
491#endif497#endif
@@ -494,6 +500,10 @@ static inline int crash_hotplug_cpu_support(void) { return 0; } · 2 unmodified lines
494static inline int crash_hotplug_memory_support(void) { return 0; }500static inline int crash_hotplug_memory_support(void) { return 0; }
495#endif501#endif
496 502
503#ifndef crash_get_elfcorehdr_size
504static inline unsigned int crash_get_elfcorehdr_size(void) { return 0; }
505#endif
506
497#else /* !CONFIG_KEXEC_CORE */507#else /* !CONFIG_KEXEC_CORE */
498struct pt_regs;508struct pt_regs;
499struct task_struct;509struct task_struct;
include/uapi/linux/kexec.h+1−0
@@ -12,6 +12,7 @@ · 11 unmodified lines
12/* kexec flags for different usage scenarios */12/* kexec flags for different usage scenarios */
13#define KEXEC_ON_CRASH 0x0000000113#define KEXEC_ON_CRASH 0x00000001
14#define KEXEC_PRESERVE_CONTEXT 0x0000000214#define KEXEC_PRESERVE_CONTEXT 0x00000002
15#define KEXEC_UPDATE_ELFCOREHDR 0x00000004
15#define KEXEC_ARCH_MASK 0xffff000016#define KEXEC_ARCH_MASK 0xffff0000
16 17
17/*18/*
kernel/Kconfig.kexec+4−0
@@ -143,4 +143,8 @@ config CRASH_MAX_MEMORY_RANGES · 142 unmodified lines
143 memory buffer/segment size under 1MiB. This represents a sane choice143 memory buffer/segment size under 1MiB. This represents a sane choice
144 to accommodate both baremetal and virtual machine configurations.144 to accommodate both baremetal and virtual machine configurations.
145 145
146 For the kexec_load() syscall path, CRASH_MAX_MEMORY_RANGES is part of
147 the computation behind the value provided through the
148 /sys/kernel/crash_elfcorehdr_size attribute.
149
146endmenu150endmenu
kernel/crash_core.c+31−0
@@ -740,6 +740,33 @@ subsys_initcall(crash_notes_memory_init); · 739 unmodified lines
740#ifdef CONFIG_CRASH_HOTPLUG740#ifdef CONFIG_CRASH_HOTPLUG
741#undef pr_fmt741#undef pr_fmt
742#define pr_fmt(fmt) "crash hp: " fmt742#define pr_fmt(fmt) "crash hp: " fmt
743
744/*
745 * This routine utilized when the crash_hotplug sysfs node is read.
746 * It reflects the kernel's ability/permission to update the crash
747 * elfcorehdr directly.
748 */
749int crash_check_update_elfcorehdr(void)
750{
751 int rc = 0;
752
753 /* Obtain lock while reading crash information */
754 if (!kexec_trylock()) {
755 pr_info("kexec_trylock() failed, elfcorehdr may be inaccurate\n");
756 return 0;
757 }
758 if (kexec_crash_image) {
759 if (kexec_crash_image->file_mode)
760 rc = 1;
761 else
762 rc = kexec_crash_image->update_elfcorehdr;
763 }
764 /* Release lock now that update complete */
765 kexec_unlock();
766
767 return rc;
768}
769
743/*770/*
744 * To accurately reflect hot un/plug changes of cpu and memory resources771 * To accurately reflect hot un/plug changes of cpu and memory resources
745 * (including onling and offlining of those resources), the elfcorehdr772 * (including onling and offlining of those resources), the elfcorehdr
@@ -770,6 +797,10 @@ static void crash_handle_hotplug_event(unsigned int hp_action, unsigned int cpu) · 24 unmodified lines
770 797
771 image = kexec_crash_image;798 image = kexec_crash_image;
772 799
800 /* Check that updating elfcorehdr is permitted */
801 if (!(image->file_mode || image->update_elfcorehdr))
802 goto out;
803
773 if (hp_action == KEXEC_CRASH_HP_ADD_CPU ||804 if (hp_action == KEXEC_CRASH_HP_ADD_CPU ||
774 hp_action == KEXEC_CRASH_HP_REMOVE_CPU)805 hp_action == KEXEC_CRASH_HP_REMOVE_CPU)
775 pr_debug("hp_action %u, cpu %u\n", hp_action, cpu);806 pr_debug("hp_action %u, cpu %u\n", hp_action, cpu);
kernel/kexec.c+5−0
@@ -129,6 +129,11 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments, · 128 unmodified lines
129 if (flags & KEXEC_PRESERVE_CONTEXT)129 if (flags & KEXEC_PRESERVE_CONTEXT)
130 image->preserve_context = 1;130 image->preserve_context = 1;
131 131
132#ifdef CONFIG_CRASH_HOTPLUG
133 if (flags & KEXEC_UPDATE_ELFCOREHDR)
134 image->update_elfcorehdr = 1;
135#endif
136
132 ret = machine_kexec_prepare(image);137 ret = machine_kexec_prepare(image);
133 if (ret)138 if (ret)
134 goto out;139 goto out;
kernel/ksysfs.c+15−0
@@ -165,6 +165,18 @@ static ssize_t vmcoreinfo_show(struct kobject *kobj, · 164 unmodified lines
165}165}
166KERNEL_ATTR_RO(vmcoreinfo);166KERNEL_ATTR_RO(vmcoreinfo);
167 167
168#ifdef CONFIG_CRASH_HOTPLUG
169static ssize_t crash_elfcorehdr_size_show(struct kobject *kobj,
170 struct kobj_attribute *attr, char *buf)
171{
172 unsigned int sz = crash_get_elfcorehdr_size();
173
174 return sysfs_emit(buf, "%u\n", sz);
175}
176KERNEL_ATTR_RO(crash_elfcorehdr_size);
177
178#endif
179
168#endif /* CONFIG_CRASH_CORE */180#endif /* CONFIG_CRASH_CORE */
169 181
170/* whether file capabilities are enabled */182/* whether file capabilities are enabled */
@@ -255,6 +267,9 @@ static struct attribute * kernel_attrs[] = { · 84 unmodified lines
255#endif267#endif
256#ifdef CONFIG_CRASH_CORE268#ifdef CONFIG_CRASH_CORE
257 &vmcoreinfo_attr.attr,269 &vmcoreinfo_attr.attr,
270#ifdef CONFIG_CRASH_HOTPLUG
271 &crash_elfcorehdr_size_attr.attr,
272#endif
258#endif273#endif
259#ifndef CONFIG_TINY_RCU274#ifndef CONFIG_TINY_RCU
260 &rcu_expedited_attr.attr,275 &rcu_expedited_attr.attr,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t