[PATCH v9 7/7] x86/crash: Add x86 crash hotplug support

Eric DeVolder posted 7 patches 3 years, 6 months ago
There is a newer version of this series
[PATCH v9 7/7] x86/crash: Add x86 crash hotplug support
Posted by Eric DeVolder 3 years, 6 months ago
For x86_64, when CPU or memory is hot un/plugged, the crash
elfcorehdr, which describes the CPUs and memory in the system,
must also be updated.

When loading the crash kernel via kexec_load or kexec_file_load,
the elfcorehdr is identified at run time in
crash_core:handle_hotplug_event().

To update the elfcorehdr for x86_64, a new elfcorehdr must be
generated from the available CPUs and memory. The new elfcorehdr
is prepared into a buffer, and then installed over the top of
the existing elfcorehdr.

In the patch 'kexec: exclude elfcorehdr from the segment digest'
the need to update purgatory due to the change in elfcorehdr was
eliminated.  As a result, no changes to purgatory or boot_params
(as the elfcorehdr= kernel command line parameter pointer
remains unchanged and correct) are needed, just elfcorehdr.

To accommodate a growing number of resources via hotplug, the
elfcorehdr segment must be sufficiently large enough to accommodate
changes, see the CRASH_MAX_MEMORY_RANGES configure item.

With this change, crash hotplug for kexec_file_load syscall
is supported. The kexec_load is also supported, but also
requires a corresponding change to userspace kexec-tools.

Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
---
 arch/x86/Kconfig        |  11 ++++
 arch/x86/kernel/crash.c | 116 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 127 insertions(+)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 762a0b6ab8b6..e9eecff3b97d 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2082,6 +2082,17 @@ config CRASH_DUMP
 	  (CONFIG_RELOCATABLE=y).
 	  For more details see Documentation/admin-guide/kdump/kdump.rst
 
+config CRASH_MAX_MEMORY_RANGES
+	depends on CRASH_DUMP && KEXEC_FILE && (HOTPLUG_CPU || MEMORY_HOTPLUG)
+	int
+	default 32768
+	help
+	  For the kexec_file_load path, specify the maximum number of
+	  memory regions, eg. as represented by the 'System RAM' entries
+	  in /proc/iomem, that the elfcorehdr buffer/segment can accommodate.
+	  This value is combined with NR_CPUS and multiplied by Elf64_Phdr
+	  size to determine the final buffer size.
+
 config KEXEC_JUMP
 	bool "kexec jump"
 	depends on KEXEC && HIBERNATION
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 9db41cce8d97..b9cdf7a0d868 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/memblock.h>
+#include <linux/highmem.h>
 
 #include <asm/processor.h>
 #include <asm/hardirq.h>
@@ -398,7 +399,17 @@ int crash_load_segments(struct kimage *image)
 	image->elf_headers = kbuf.buffer;
 	image->elf_headers_sz = kbuf.bufsz;
 
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
+	/* Ensure elfcorehdr segment large enough for hotplug changes */
+	kbuf.memsz = (CONFIG_NR_CPUS_DEFAULT + CONFIG_CRASH_MAX_MEMORY_RANGES) * sizeof(Elf64_Phdr);
+	/* For marking as usable to crash kernel */
+	image->elf_headers_sz = kbuf.memsz;
+	/* Record the index of the elfcorehdr segment */
+	image->elfcorehdr_index = image->nr_segments;
+	image->elfcorehdr_index_valid = true;
+#else
 	kbuf.memsz = kbuf.bufsz;
+#endif
 	kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
 	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
 	ret = kexec_add_buffer(&kbuf);
@@ -413,3 +424,108 @@ int crash_load_segments(struct kimage *image)
 	return ret;
 }
 #endif /* CONFIG_KEXEC_FILE */
+
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
+int crash_hotplug_support(void) { return 1; }
+void *arch_map_crash_pages(unsigned long paddr, unsigned long size)
+{
+	/*
+	 * NOTE: The addresses and sizes passed to this routine have
+	 * already been fully aligned on page boundaries. There is no
+	 * need for massaging the address or size.
+	 */
+	void *ptr = NULL;
+
+	/* NOTE: requires arch_kexec_[un]protect_crashkres() for write access */
+	if (size > 0) {
+		struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
+
+		ptr = kmap(page);
+	}
+
+	return ptr;
+}
+
+void arch_unmap_crash_pages(void **ptr)
+{
+	if (ptr) {
+		if (*ptr)
+			kunmap(*ptr);
+		*ptr = NULL;
+	}
+}
+
+/**
+ * arch_crash_handle_hotplug_event() - Handle hotplug elfcorehdr changes
+ * @image: the active struct kimage
+ * @hp_action: the hot un/plug action being handled
+ * @cpu: when KEXEC_CRASH_HP_ADD/REMOVE_CPU, the cpu affected
+ *
+ * To accurately reflect hot un/plug changes, the elfcorehdr (which
+ * is passed to the crash kernel via the elfcorehdr= parameter)
+ * must be updated with the new list of CPUs and memories. The new
+ * elfcorehdr is prepared in a kernel buffer, and then it is
+ * written on top of the existing/old elfcorehdr.
+ *
+ * For hotplug changes to elfcorehdr to work, two conditions are
+ * needed:
+ * First, the segment containing the elfcorehdr must be large enough
+ * to permit a growing number of resources. See the
+ * CONFIG_CRASH_MAX_MEMORY_RANGES description.
+ * Second, purgatory must explicitly exclude the elfcorehdr from the
+ * list of segments it checks (since the elfcorehdr changes and thus
+ * would require an update to purgatory itself to update the digest).
+ *
+ */
+void arch_crash_handle_hotplug_event(struct kimage *image,
+	unsigned int hp_action, unsigned int cpu)
+{
+	struct kexec_segment *ksegment;
+	unsigned char *ptr = NULL;
+	unsigned long elfsz = 0;
+	void *elfbuf = NULL;
+	unsigned long mem, memsz;
+
+	/*
+	 * Elfcorehdr_index_valid checked in crash_core:handle_hotplug_event()
+	 */
+	ksegment = &image->segment[image->elfcorehdr_index];
+	mem = ksegment->mem;
+	memsz = ksegment->memsz;
+
+	/*
+	 * Create the new elfcorehdr reflecting the changes to CPU and/or
+	 * memory resources.
+	 */
+	if (prepare_elf_headers(image, &elfbuf, &elfsz)) {
+		pr_err("crash hp: unable to prepare elfcore headers");
+		goto out;
+	}
+	if (elfsz > memsz) {
+		pr_err("crash hp: update elfcorehdr elfsz %lu > memsz %lu",
+			elfsz, memsz);
+		goto out;
+	}
+
+	/*
+	 * At this point, we are all but assured of success.
+	 * Copy new elfcorehdr into destination.
+	 */
+	ptr = arch_map_crash_pages(mem, memsz);
+	if (ptr) {
+		/*
+		 * Temporarily invalidate the crash image while the
+		 * elfcorehdr is updated.
+		 */
+		xchg(&kexec_crash_image, NULL);
+		memcpy_flushcache((void *)ptr, elfbuf, elfsz);
+		xchg(&kexec_crash_image, image);
+	}
+	arch_unmap_crash_pages((void **)&ptr);
+	pr_debug("crash hp: re-loaded elfcorehdr at 0x%lx\n", mem);
+
+out:
+	if (elfbuf)
+		vfree(elfbuf);
+}
+#endif
-- 
2.31.1
Re: [PATCH v9 7/7] x86/crash: Add x86 crash hotplug support
Posted by Fabio M. De Francesco 3 years, 5 months ago
On martedì 14 giugno 2022 00:42:40 CEST Eric DeVolder wrote:
> For x86_64, when CPU or memory is hot un/plugged, the crash
> elfcorehdr, which describes the CPUs and memory in the system,
> must also be updated.
> 
> When loading the crash kernel via kexec_load or kexec_file_load,
> the elfcorehdr is identified at run time in
> crash_core:handle_hotplug_event().
> 
> To update the elfcorehdr for x86_64, a new elfcorehdr must be
> generated from the available CPUs and memory. The new elfcorehdr
> is prepared into a buffer, and then installed over the top of
> the existing elfcorehdr.
> 
> In the patch 'kexec: exclude elfcorehdr from the segment digest'
> the need to update purgatory due to the change in elfcorehdr was
> eliminated.  As a result, no changes to purgatory or boot_params
> (as the elfcorehdr= kernel command line parameter pointer
> remains unchanged and correct) are needed, just elfcorehdr.
> 
> To accommodate a growing number of resources via hotplug, the
> elfcorehdr segment must be sufficiently large enough to accommodate
> changes, see the CRASH_MAX_MEMORY_RANGES configure item.
> 
> With this change, crash hotplug for kexec_file_load syscall
> is supported. The kexec_load is also supported, but also
> requires a corresponding change to userspace kexec-tools.
> 
> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
> ---
>  arch/x86/Kconfig        |  11 ++++
>  arch/x86/kernel/crash.c | 116 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 127 insertions(+)
> 
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 762a0b6ab8b6..e9eecff3b97d 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -2082,6 +2082,17 @@ config CRASH_DUMP
>  	  (CONFIG_RELOCATABLE=y).
>  	  For more details see Documentation/admin-guide/kdump/kdump.rst
>  
> +config CRASH_MAX_MEMORY_RANGES
> +	depends on CRASH_DUMP && KEXEC_FILE && (HOTPLUG_CPU || 
MEMORY_HOTPLUG)
> +	int
> +	default 32768
> +	help
> +	  For the kexec_file_load path, specify the maximum number of
> +	  memory regions, eg. as represented by the 'System RAM' entries
> +	  in /proc/iomem, that the elfcorehdr buffer/segment can 
accommodate.
> +	  This value is combined with NR_CPUS and multiplied by 
Elf64_Phdr
> +	  size to determine the final buffer size.
> +
>  config KEXEC_JUMP
>  	bool "kexec jump"
>  	depends on KEXEC && HIBERNATION
> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
> index 9db41cce8d97..b9cdf7a0d868 100644
> --- a/arch/x86/kernel/crash.c
> +++ b/arch/x86/kernel/crash.c
> @@ -25,6 +25,7 @@
>  #include <linux/slab.h>
>  #include <linux/vmalloc.h>
>  #include <linux/memblock.h>
> +#include <linux/highmem.h>
>  
>  #include <asm/processor.h>
>  #include <asm/hardirq.h>
> @@ -398,7 +399,17 @@ int crash_load_segments(struct kimage *image)
>  	image->elf_headers = kbuf.buffer;
>  	image->elf_headers_sz = kbuf.bufsz;
>  
> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
> +	/* Ensure elfcorehdr segment large enough for hotplug changes */
> +	kbuf.memsz = (CONFIG_NR_CPUS_DEFAULT + 
CONFIG_CRASH_MAX_MEMORY_RANGES) * sizeof(Elf64_Phdr);
> +	/* For marking as usable to crash kernel */
> +	image->elf_headers_sz = kbuf.memsz;
> +	/* Record the index of the elfcorehdr segment */
> +	image->elfcorehdr_index = image->nr_segments;
> +	image->elfcorehdr_index_valid = true;
> +#else
>  	kbuf.memsz = kbuf.bufsz;
> +#endif
>  	kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
>  	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
>  	ret = kexec_add_buffer(&kbuf);
> @@ -413,3 +424,108 @@ int crash_load_segments(struct kimage *image)
>  	return ret;
>  }
>  #endif /* CONFIG_KEXEC_FILE */
> +
> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
> +int crash_hotplug_support(void) { return 1; }
> +void *arch_map_crash_pages(unsigned long paddr, unsigned long size)
> +{
> +	/*
> +	 * NOTE: The addresses and sizes passed to this routine have
> +	 * already been fully aligned on page boundaries. There is no
> +	 * need for massaging the address or size.
> +	 */
> +	void *ptr = NULL;
> +
> +	/* NOTE: requires arch_kexec_[un]protect_crashkres() for write 
access */
> +	if (size > 0) {
> +		struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
> +
> +		ptr = kmap(page);
> +	}

kmap_local_page() is preferred over kmap() which should be avoided in new 
code (please take a look at highmem.rst which I recently updated).

Can you please check if you can easily avoid using kmap()? Otherwise, this 
code will be added to my (long) queue and changed one day or the other :-)

Thanks,

Fabio

> +
> +	return ptr;
> +}
> +
> +void arch_unmap_crash_pages(void **ptr)
> +{
> +	if (ptr) {
> +		if (*ptr)
> +			kunmap(*ptr);
> +		*ptr = NULL;
> +	}
> +}
> +
> +/**
> + * arch_crash_handle_hotplug_event() - Handle hotplug elfcorehdr changes
> + * @image: the active struct kimage
> + * @hp_action: the hot un/plug action being handled
> + * @cpu: when KEXEC_CRASH_HP_ADD/REMOVE_CPU, the cpu affected
> + *
> + * To accurately reflect hot un/plug changes, the elfcorehdr (which
> + * is passed to the crash kernel via the elfcorehdr= parameter)
> + * must be updated with the new list of CPUs and memories. The new
> + * elfcorehdr is prepared in a kernel buffer, and then it is
> + * written on top of the existing/old elfcorehdr.
> + *
> + * For hotplug changes to elfcorehdr to work, two conditions are
> + * needed:
> + * First, the segment containing the elfcorehdr must be large enough
> + * to permit a growing number of resources. See the
> + * CONFIG_CRASH_MAX_MEMORY_RANGES description.
> + * Second, purgatory must explicitly exclude the elfcorehdr from the
> + * list of segments it checks (since the elfcorehdr changes and thus
> + * would require an update to purgatory itself to update the digest).
> + *
> + */
> +void arch_crash_handle_hotplug_event(struct kimage *image,
> +	unsigned int hp_action, unsigned int cpu)
> +{
> +	struct kexec_segment *ksegment;
> +	unsigned char *ptr = NULL;
> +	unsigned long elfsz = 0;
> +	void *elfbuf = NULL;
> +	unsigned long mem, memsz;
> +
> +	/*
> +	 * Elfcorehdr_index_valid checked in 
crash_core:handle_hotplug_event()
> +	 */
> +	ksegment = &image->segment[image->elfcorehdr_index];
> +	mem = ksegment->mem;
> +	memsz = ksegment->memsz;
> +
> +	/*
> +	 * Create the new elfcorehdr reflecting the changes to CPU and/or
> +	 * memory resources.
> +	 */
> +	if (prepare_elf_headers(image, &elfbuf, &elfsz)) {
> +		pr_err("crash hp: unable to prepare elfcore headers");
> +		goto out;
> +	}
> +	if (elfsz > memsz) {
> +		pr_err("crash hp: update elfcorehdr elfsz %lu > memsz 
%lu",
> +			elfsz, memsz);
> +		goto out;
> +	}
> +
> +	/*
> +	 * At this point, we are all but assured of success.
> +	 * Copy new elfcorehdr into destination.
> +	 */
> +	ptr = arch_map_crash_pages(mem, memsz);
> +	if (ptr) {
> +		/*
> +		 * Temporarily invalidate the crash image while the
> +		 * elfcorehdr is updated.
> +		 */
> +		xchg(&kexec_crash_image, NULL);
> +		memcpy_flushcache((void *)ptr, elfbuf, elfsz);
> +		xchg(&kexec_crash_image, image);
> +	}
> +	arch_unmap_crash_pages((void **)&ptr);
> +	pr_debug("crash hp: re-loaded elfcorehdr at 0x%lx\n", mem);
> +
> +out:
> +	if (elfbuf)
> +		vfree(elfbuf);
> +}
> +#endif
> -- 
> 2.31.1
> 
> 
Re: [PATCH v9 7/7] x86/crash: Add x86 crash hotplug support
Posted by Eric DeVolder 3 years, 5 months ago

On 7/8/22 14:38, Fabio M. De Francesco wrote:
> On martedì 14 giugno 2022 00:42:40 CEST Eric DeVolder wrote:
>> For x86_64, when CPU or memory is hot un/plugged, the crash
>> elfcorehdr, which describes the CPUs and memory in the system,
>> must also be updated.
>>
>> When loading the crash kernel via kexec_load or kexec_file_load,
>> the elfcorehdr is identified at run time in
>> crash_core:handle_hotplug_event().
>>
>> To update the elfcorehdr for x86_64, a new elfcorehdr must be
>> generated from the available CPUs and memory. The new elfcorehdr
>> is prepared into a buffer, and then installed over the top of
>> the existing elfcorehdr.
>>
>> In the patch 'kexec: exclude elfcorehdr from the segment digest'
>> the need to update purgatory due to the change in elfcorehdr was
>> eliminated.  As a result, no changes to purgatory or boot_params
>> (as the elfcorehdr= kernel command line parameter pointer
>> remains unchanged and correct) are needed, just elfcorehdr.
>>
>> To accommodate a growing number of resources via hotplug, the
>> elfcorehdr segment must be sufficiently large enough to accommodate
>> changes, see the CRASH_MAX_MEMORY_RANGES configure item.
>>
>> With this change, crash hotplug for kexec_file_load syscall
>> is supported. The kexec_load is also supported, but also
>> requires a corresponding change to userspace kexec-tools.
>>
>> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
>> ---
>>   arch/x86/Kconfig        |  11 ++++
>>   arch/x86/kernel/crash.c | 116 ++++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 127 insertions(+)
>>
>> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
>> index 762a0b6ab8b6..e9eecff3b97d 100644
>> --- a/arch/x86/Kconfig
>> +++ b/arch/x86/Kconfig
>> @@ -2082,6 +2082,17 @@ config CRASH_DUMP
>>   	  (CONFIG_RELOCATABLE=y).
>>   	  For more details see Documentation/admin-guide/kdump/kdump.rst
>>   
>> +config CRASH_MAX_MEMORY_RANGES
>> +	depends on CRASH_DUMP && KEXEC_FILE && (HOTPLUG_CPU ||
> MEMORY_HOTPLUG)
>> +	int
>> +	default 32768
>> +	help
>> +	  For the kexec_file_load path, specify the maximum number of
>> +	  memory regions, eg. as represented by the 'System RAM' entries
>> +	  in /proc/iomem, that the elfcorehdr buffer/segment can
> accommodate.
>> +	  This value is combined with NR_CPUS and multiplied by
> Elf64_Phdr
>> +	  size to determine the final buffer size.
>> +
>>   config KEXEC_JUMP
>>   	bool "kexec jump"
>>   	depends on KEXEC && HIBERNATION
>> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
>> index 9db41cce8d97..b9cdf7a0d868 100644
>> --- a/arch/x86/kernel/crash.c
>> +++ b/arch/x86/kernel/crash.c
>> @@ -25,6 +25,7 @@
>>   #include <linux/slab.h>
>>   #include <linux/vmalloc.h>
>>   #include <linux/memblock.h>
>> +#include <linux/highmem.h>
>>   
>>   #include <asm/processor.h>
>>   #include <asm/hardirq.h>
>> @@ -398,7 +399,17 @@ int crash_load_segments(struct kimage *image)
>>   	image->elf_headers = kbuf.buffer;
>>   	image->elf_headers_sz = kbuf.bufsz;
>>   
>> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
>> +	/* Ensure elfcorehdr segment large enough for hotplug changes */
>> +	kbuf.memsz = (CONFIG_NR_CPUS_DEFAULT +
> CONFIG_CRASH_MAX_MEMORY_RANGES) * sizeof(Elf64_Phdr);
>> +	/* For marking as usable to crash kernel */
>> +	image->elf_headers_sz = kbuf.memsz;
>> +	/* Record the index of the elfcorehdr segment */
>> +	image->elfcorehdr_index = image->nr_segments;
>> +	image->elfcorehdr_index_valid = true;
>> +#else
>>   	kbuf.memsz = kbuf.bufsz;
>> +#endif
>>   	kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
>>   	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
>>   	ret = kexec_add_buffer(&kbuf);
>> @@ -413,3 +424,108 @@ int crash_load_segments(struct kimage *image)
>>   	return ret;
>>   }
>>   #endif /* CONFIG_KEXEC_FILE */
>> +
>> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
>> +int crash_hotplug_support(void) { return 1; }
>> +void *arch_map_crash_pages(unsigned long paddr, unsigned long size)
>> +{
>> +	/*
>> +	 * NOTE: The addresses and sizes passed to this routine have
>> +	 * already been fully aligned on page boundaries. There is no
>> +	 * need for massaging the address or size.
>> +	 */
>> +	void *ptr = NULL;
>> +
>> +	/* NOTE: requires arch_kexec_[un]protect_crashkres() for write
> access */
>> +	if (size > 0) {
>> +		struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
>> +
>> +		ptr = kmap(page);
>> +	}
> 
> kmap_local_page() is preferred over kmap() which should be avoided in new
> code (please take a look at highmem.rst which I recently updated).
> 
> Can you please check if you can easily avoid using kmap()? Otherwise, this
> code will be added to my (long) queue and changed one day or the other :-)
> 
> Thanks,
> 
> Fabio
Fabio,
I converted this to kmap_local_page()!
Thanks!
eric

> 
>> +
>> +	return ptr;
>> +}
>> +
>> +void arch_unmap_crash_pages(void **ptr)
>> +{
>> +	if (ptr) {
>> +		if (*ptr)
>> +			kunmap(*ptr);
>> +		*ptr = NULL;
>> +	}
>> +}
>> +
>> +/**
>> + * arch_crash_handle_hotplug_event() - Handle hotplug elfcorehdr changes
>> + * @image: the active struct kimage
>> + * @hp_action: the hot un/plug action being handled
>> + * @cpu: when KEXEC_CRASH_HP_ADD/REMOVE_CPU, the cpu affected
>> + *
>> + * To accurately reflect hot un/plug changes, the elfcorehdr (which
>> + * is passed to the crash kernel via the elfcorehdr= parameter)
>> + * must be updated with the new list of CPUs and memories. The new
>> + * elfcorehdr is prepared in a kernel buffer, and then it is
>> + * written on top of the existing/old elfcorehdr.
>> + *
>> + * For hotplug changes to elfcorehdr to work, two conditions are
>> + * needed:
>> + * First, the segment containing the elfcorehdr must be large enough
>> + * to permit a growing number of resources. See the
>> + * CONFIG_CRASH_MAX_MEMORY_RANGES description.
>> + * Second, purgatory must explicitly exclude the elfcorehdr from the
>> + * list of segments it checks (since the elfcorehdr changes and thus
>> + * would require an update to purgatory itself to update the digest).
>> + *
>> + */
>> +void arch_crash_handle_hotplug_event(struct kimage *image,
>> +	unsigned int hp_action, unsigned int cpu)
>> +{
>> +	struct kexec_segment *ksegment;
>> +	unsigned char *ptr = NULL;
>> +	unsigned long elfsz = 0;
>> +	void *elfbuf = NULL;
>> +	unsigned long mem, memsz;
>> +
>> +	/*
>> +	 * Elfcorehdr_index_valid checked in
> crash_core:handle_hotplug_event()
>> +	 */
>> +	ksegment = &image->segment[image->elfcorehdr_index];
>> +	mem = ksegment->mem;
>> +	memsz = ksegment->memsz;
>> +
>> +	/*
>> +	 * Create the new elfcorehdr reflecting the changes to CPU and/or
>> +	 * memory resources.
>> +	 */
>> +	if (prepare_elf_headers(image, &elfbuf, &elfsz)) {
>> +		pr_err("crash hp: unable to prepare elfcore headers");
>> +		goto out;
>> +	}
>> +	if (elfsz > memsz) {
>> +		pr_err("crash hp: update elfcorehdr elfsz %lu > memsz
> %lu",
>> +			elfsz, memsz);
>> +		goto out;
>> +	}
>> +
>> +	/*
>> +	 * At this point, we are all but assured of success.
>> +	 * Copy new elfcorehdr into destination.
>> +	 */
>> +	ptr = arch_map_crash_pages(mem, memsz);
>> +	if (ptr) {
>> +		/*
>> +		 * Temporarily invalidate the crash image while the
>> +		 * elfcorehdr is updated.
>> +		 */
>> +		xchg(&kexec_crash_image, NULL);
>> +		memcpy_flushcache((void *)ptr, elfbuf, elfsz);
>> +		xchg(&kexec_crash_image, image);
>> +	}
>> +	arch_unmap_crash_pages((void **)&ptr);
>> +	pr_debug("crash hp: re-loaded elfcorehdr at 0x%lx\n", mem);
>> +
>> +out:
>> +	if (elfbuf)
>> +		vfree(elfbuf);
>> +}
>> +#endif
>> -- 
>> 2.31.1
>>
>>
> 
> 
> 
> 
Re: [PATCH v9 7/7] x86/crash: Add x86 crash hotplug support
Posted by Fabio M. De Francesco 3 years, 5 months ago
On venerdì 8 luglio 2022 23:07:20 CEST Eric DeVolder wrote:
> 
> On 7/8/22 14:38, Fabio M. De Francesco wrote:
> > On martedì 14 giugno 2022 00:42:40 CEST Eric DeVolder wrote:
> >> For x86_64, when CPU or memory is hot un/plugged, the crash
> >> elfcorehdr, which describes the CPUs and memory in the system,
> >> must also be updated.
> >>
> >> When loading the crash kernel via kexec_load or kexec_file_load,
> >> the elfcorehdr is identified at run time in
> >> crash_core:handle_hotplug_event().
> >>
> >> To update the elfcorehdr for x86_64, a new elfcorehdr must be
> >> generated from the available CPUs and memory. The new elfcorehdr
> >> is prepared into a buffer, and then installed over the top of
> >> the existing elfcorehdr.
> >>
> >> In the patch 'kexec: exclude elfcorehdr from the segment digest'
> >> the need to update purgatory due to the change in elfcorehdr was
> >> eliminated.  As a result, no changes to purgatory or boot_params
> >> (as the elfcorehdr= kernel command line parameter pointer
> >> remains unchanged and correct) are needed, just elfcorehdr.
> >>
> >> To accommodate a growing number of resources via hotplug, the
> >> elfcorehdr segment must be sufficiently large enough to accommodate
> >> changes, see the CRASH_MAX_MEMORY_RANGES configure item.
> >>
> >> With this change, crash hotplug for kexec_file_load syscall
> >> is supported. The kexec_load is also supported, but also
> >> requires a corresponding change to userspace kexec-tools.
> >>
> >> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
> >> ---
> >>   arch/x86/Kconfig        |  11 ++++
> >>   arch/x86/kernel/crash.c | 116 ++++++++++++++++++++++++++++++++++++++
++
> >>   2 files changed, 127 insertions(+)
> >>
> >> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> >> index 762a0b6ab8b6..e9eecff3b97d 100644
> >> --- a/arch/x86/Kconfig
> >> +++ b/arch/x86/Kconfig
> >> @@ -2082,6 +2082,17 @@ config CRASH_DUMP
> >>   	  (CONFIG_RELOCATABLE=y).
> >>   	  For more details see Documentation/admin-guide/kdump/kdump.rst
> >>   
> >> +config CRASH_MAX_MEMORY_RANGES
> >> +	depends on CRASH_DUMP && KEXEC_FILE && (HOTPLUG_CPU ||
> > MEMORY_HOTPLUG)
> >> +	int
> >> +	default 32768
> >> +	help
> >> +	  For the kexec_file_load path, specify the maximum number of
> >> +	  memory regions, eg. as represented by the 'System RAM' entries
> >> +	  in /proc/iomem, that the elfcorehdr buffer/segment can
> > accommodate.
> >> +	  This value is combined with NR_CPUS and multiplied by
> > Elf64_Phdr
> >> +	  size to determine the final buffer size.
> >> +
> >>   config KEXEC_JUMP
> >>   	bool "kexec jump"
> >>   	depends on KEXEC && HIBERNATION
> >> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
> >> index 9db41cce8d97..b9cdf7a0d868 100644
> >> --- a/arch/x86/kernel/crash.c
> >> +++ b/arch/x86/kernel/crash.c
> >> @@ -25,6 +25,7 @@
> >>   #include <linux/slab.h>
> >>   #include <linux/vmalloc.h>
> >>   #include <linux/memblock.h>
> >> +#include <linux/highmem.h>
> >>   
> >>   #include <asm/processor.h>
> >>   #include <asm/hardirq.h>
> >> @@ -398,7 +399,17 @@ int crash_load_segments(struct kimage *image)
> >>   	image->elf_headers = kbuf.buffer;
> >>   	image->elf_headers_sz = kbuf.bufsz;
> >>   
> >> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
> >> +	/* Ensure elfcorehdr segment large enough for hotplug changes */
> >> +	kbuf.memsz = (CONFIG_NR_CPUS_DEFAULT +
> > CONFIG_CRASH_MAX_MEMORY_RANGES) * sizeof(Elf64_Phdr);
> >> +	/* For marking as usable to crash kernel */
> >> +	image->elf_headers_sz = kbuf.memsz;
> >> +	/* Record the index of the elfcorehdr segment */
> >> +	image->elfcorehdr_index = image->nr_segments;
> >> +	image->elfcorehdr_index_valid = true;
> >> +#else
> >>   	kbuf.memsz = kbuf.bufsz;
> >> +#endif
> >>   	kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
> >>   	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> >>   	ret = kexec_add_buffer(&kbuf);
> >> @@ -413,3 +424,108 @@ int crash_load_segments(struct kimage *image)
> >>   	return ret;
> >>   }
> >>   #endif /* CONFIG_KEXEC_FILE */
> >> +
> >> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
> >> +int crash_hotplug_support(void) { return 1; }
> >> +void *arch_map_crash_pages(unsigned long paddr, unsigned long size)
> >> +{
> >> +	/*
> >> +	 * NOTE: The addresses and sizes passed to this routine have
> >> +	 * already been fully aligned on page boundaries. There is no
> >> +	 * need for massaging the address or size.
> >> +	 */
> >> +	void *ptr = NULL;
> >> +
> >> +	/* NOTE: requires arch_kexec_[un]protect_crashkres() for write
> > access */
> >> +	if (size > 0) {
> >> +		struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
> >> +
> >> +		ptr = kmap(page);
> >> +	}
> > 
> > kmap_local_page() is preferred over kmap() which should be avoided in 
new
> > code (please take a look at highmem.rst which I recently updated).
> > 
> > Can you please check if you can easily avoid using kmap()? Otherwise, 
this
> > code will be added to my (long) queue and changed one day or the other 
:-)
> > 
> > Thanks,
> > 
> > Fabio
> Fabio,
> I converted this to kmap_local_page()!
> Thanks!
> eric
> 
> > 
Eric,

Thanks for the very quick reaction to my suggestion.

Fabio
Re: [PATCH v9 7/7] x86/crash: Add x86 crash hotplug support
Posted by Sourabh Jain 3 years, 5 months ago
Hello Eric,

On 14/06/22 04:12, Eric DeVolder wrote:
> For x86_64, when CPU or memory is hot un/plugged, the crash
> elfcorehdr, which describes the CPUs and memory in the system,
> must also be updated.
>
> When loading the crash kernel via kexec_load or kexec_file_load,
> the elfcorehdr is identified at run time in
> crash_core:handle_hotplug_event().
>
> To update the elfcorehdr for x86_64, a new elfcorehdr must be
> generated from the available CPUs and memory. The new elfcorehdr
> is prepared into a buffer, and then installed over the top of
> the existing elfcorehdr.
>
> In the patch 'kexec: exclude elfcorehdr from the segment digest'
> the need to update purgatory due to the change in elfcorehdr was
> eliminated.  As a result, no changes to purgatory or boot_params
> (as the elfcorehdr= kernel command line parameter pointer
> remains unchanged and correct) are needed, just elfcorehdr.
>
> To accommodate a growing number of resources via hotplug, the
> elfcorehdr segment must be sufficiently large enough to accommodate
> changes, see the CRASH_MAX_MEMORY_RANGES configure item.
>
> With this change, crash hotplug for kexec_file_load syscall
> is supported. The kexec_load is also supported, but also
> requires a corresponding change to userspace kexec-tools.
>
> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
> ---
>   arch/x86/Kconfig        |  11 ++++
>   arch/x86/kernel/crash.c | 116 ++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 127 insertions(+)
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 762a0b6ab8b6..e9eecff3b97d 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -2082,6 +2082,17 @@ config CRASH_DUMP
>   	  (CONFIG_RELOCATABLE=y).
>   	  For more details see Documentation/admin-guide/kdump/kdump.rst
>   
> +config CRASH_MAX_MEMORY_RANGES
> +	depends on CRASH_DUMP && KEXEC_FILE && (HOTPLUG_CPU || MEMORY_HOTPLUG)
> +	int
> +	default 32768
> +	help
> +	  For the kexec_file_load path, specify the maximum number of
> +	  memory regions, eg. as represented by the 'System RAM' entries
> +	  in /proc/iomem, that the elfcorehdr buffer/segment can accommodate.
> +	  This value is combined with NR_CPUS and multiplied by Elf64_Phdr
> +	  size to determine the final buffer size.
> +
>   config KEXEC_JUMP
>   	bool "kexec jump"
>   	depends on KEXEC && HIBERNATION
> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
> index 9db41cce8d97..b9cdf7a0d868 100644
> --- a/arch/x86/kernel/crash.c
> +++ b/arch/x86/kernel/crash.c
> @@ -25,6 +25,7 @@
>   #include <linux/slab.h>
>   #include <linux/vmalloc.h>
>   #include <linux/memblock.h>
> +#include <linux/highmem.h>
>   
>   #include <asm/processor.h>
>   #include <asm/hardirq.h>
> @@ -398,7 +399,17 @@ int crash_load_segments(struct kimage *image)
>   	image->elf_headers = kbuf.buffer;
>   	image->elf_headers_sz = kbuf.bufsz;
>   
> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
> +	/* Ensure elfcorehdr segment large enough for hotplug changes */
> +	kbuf.memsz = (CONFIG_NR_CPUS_DEFAULT + CONFIG_CRASH_MAX_MEMORY_RANGES) * sizeof(Elf64_Phdr);
> +	/* For marking as usable to crash kernel */
> +	image->elf_headers_sz = kbuf.memsz;
> +	/* Record the index of the elfcorehdr segment */
> +	image->elfcorehdr_index = image->nr_segments;
> +	image->elfcorehdr_index_valid = true;
> +#else
>   	kbuf.memsz = kbuf.bufsz;
> +#endif
>   	kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
>   	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
>   	ret = kexec_add_buffer(&kbuf);
> @@ -413,3 +424,108 @@ int crash_load_segments(struct kimage *image)
>   	return ret;
>   }
>   #endif /* CONFIG_KEXEC_FILE */
> +
> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
> +int crash_hotplug_support(void) { return 1; }
> +void *arch_map_crash_pages(unsigned long paddr, unsigned long size)
> +{
> +	/*
> +	 * NOTE: The addresses and sizes passed to this routine have
> +	 * already been fully aligned on page boundaries. There is no
> +	 * need for massaging the address or size.
> +	 */
> +	void *ptr = NULL;
> +
> +	/* NOTE: requires arch_kexec_[un]protect_crashkres() for write access */
> +	if (size > 0) {
> +		struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
> +
> +		ptr = kmap(page);
> +	}
> +
> +	return ptr;
> +}
> +
> +void arch_unmap_crash_pages(void **ptr)
> +{
> +	if (ptr) {
> +		if (*ptr)
> +			kunmap(*ptr);
> +		*ptr = NULL;
> +	}
> +}

Aren't arch will have build issue if arch_[un]map_crash_pages methods 
are not defined?

Thanks,
Sourabh Jain
Re: [PATCH v9 7/7] x86/crash: Add x86 crash hotplug support
Posted by Eric DeVolder 3 years, 5 months ago

On 6/20/22 00:06, Sourabh Jain wrote:
> Hello Eric,
> 
> On 14/06/22 04:12, Eric DeVolder wrote:
>> For x86_64, when CPU or memory is hot un/plugged, the crash
>> elfcorehdr, which describes the CPUs and memory in the system,
>> must also be updated.
>>
>> When loading the crash kernel via kexec_load or kexec_file_load,
>> the elfcorehdr is identified at run time in
>> crash_core:handle_hotplug_event().
>>
>> To update the elfcorehdr for x86_64, a new elfcorehdr must be
>> generated from the available CPUs and memory. The new elfcorehdr
>> is prepared into a buffer, and then installed over the top of
>> the existing elfcorehdr.
>>
>> In the patch 'kexec: exclude elfcorehdr from the segment digest'
>> the need to update purgatory due to the change in elfcorehdr was
>> eliminated.  As a result, no changes to purgatory or boot_params
>> (as the elfcorehdr= kernel command line parameter pointer
>> remains unchanged and correct) are needed, just elfcorehdr.
>>
>> To accommodate a growing number of resources via hotplug, the
>> elfcorehdr segment must be sufficiently large enough to accommodate
>> changes, see the CRASH_MAX_MEMORY_RANGES configure item.
>>
>> With this change, crash hotplug for kexec_file_load syscall
>> is supported. The kexec_load is also supported, but also
>> requires a corresponding change to userspace kexec-tools.
>>
>> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
>> ---
>>   arch/x86/Kconfig        |  11 ++++
>>   arch/x86/kernel/crash.c | 116 ++++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 127 insertions(+)
>>
>> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
>> index 762a0b6ab8b6..e9eecff3b97d 100644
>> --- a/arch/x86/Kconfig
>> +++ b/arch/x86/Kconfig
>> @@ -2082,6 +2082,17 @@ config CRASH_DUMP
>>         (CONFIG_RELOCATABLE=y).
>>         For more details see Documentation/admin-guide/kdump/kdump.rst
>> +config CRASH_MAX_MEMORY_RANGES
>> +    depends on CRASH_DUMP && KEXEC_FILE && (HOTPLUG_CPU || MEMORY_HOTPLUG)
>> +    int
>> +    default 32768
>> +    help
>> +      For the kexec_file_load path, specify the maximum number of
>> +      memory regions, eg. as represented by the 'System RAM' entries
>> +      in /proc/iomem, that the elfcorehdr buffer/segment can accommodate.
>> +      This value is combined with NR_CPUS and multiplied by Elf64_Phdr
>> +      size to determine the final buffer size.
>> +
>>   config KEXEC_JUMP
>>       bool "kexec jump"
>>       depends on KEXEC && HIBERNATION
>> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
>> index 9db41cce8d97..b9cdf7a0d868 100644
>> --- a/arch/x86/kernel/crash.c
>> +++ b/arch/x86/kernel/crash.c
>> @@ -25,6 +25,7 @@
>>   #include <linux/slab.h>
>>   #include <linux/vmalloc.h>
>>   #include <linux/memblock.h>
>> +#include <linux/highmem.h>
>>   #include <asm/processor.h>
>>   #include <asm/hardirq.h>
>> @@ -398,7 +399,17 @@ int crash_load_segments(struct kimage *image)
>>       image->elf_headers = kbuf.buffer;
>>       image->elf_headers_sz = kbuf.bufsz;
>> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
>> +    /* Ensure elfcorehdr segment large enough for hotplug changes */
>> +    kbuf.memsz = (CONFIG_NR_CPUS_DEFAULT + CONFIG_CRASH_MAX_MEMORY_RANGES) * sizeof(Elf64_Phdr);
>> +    /* For marking as usable to crash kernel */
>> +    image->elf_headers_sz = kbuf.memsz;
>> +    /* Record the index of the elfcorehdr segment */
>> +    image->elfcorehdr_index = image->nr_segments;
>> +    image->elfcorehdr_index_valid = true;
>> +#else
>>       kbuf.memsz = kbuf.bufsz;
>> +#endif
>>       kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
>>       kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
>>       ret = kexec_add_buffer(&kbuf);
>> @@ -413,3 +424,108 @@ int crash_load_segments(struct kimage *image)
>>       return ret;
>>   }
>>   #endif /* CONFIG_KEXEC_FILE */
>> +
>> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
>> +int crash_hotplug_support(void) { return 1; }
>> +void *arch_map_crash_pages(unsigned long paddr, unsigned long size)
>> +{
>> +    /*
>> +     * NOTE: The addresses and sizes passed to this routine have
>> +     * already been fully aligned on page boundaries. There is no
>> +     * need for massaging the address or size.
>> +     */
>> +    void *ptr = NULL;
>> +
>> +    /* NOTE: requires arch_kexec_[un]protect_crashkres() for write access */
>> +    if (size > 0) {
>> +        struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
>> +
>> +        ptr = kmap(page);
>> +    }
>> +
>> +    return ptr;
>> +}
>> +
>> +void arch_unmap_crash_pages(void **ptr)
>> +{
>> +    if (ptr) {
>> +        if (*ptr)
>> +            kunmap(*ptr);
>> +        *ptr = NULL;
>> +    }
>> +}
> 
> Aren't arch will have build issue if arch_[un]map_crash_pages methods are not defined?
Sourabh,
Yes, you are correct. I'll add __weak versions of each in crash_core.c in the next patch.
Thanks!
Eric

> 
> Thanks,
> Sourabh Jain
> 
Re: [PATCH v9 7/7] x86/crash: Add x86 crash hotplug support
Posted by Baoquan He 3 years, 5 months ago
On 07/07/22 at 07:55am, Eric DeVolder wrote:
> 
> 
> On 6/20/22 00:06, Sourabh Jain wrote:
> > Hello Eric,
> > 
> > On 14/06/22 04:12, Eric DeVolder wrote:
> > > For x86_64, when CPU or memory is hot un/plugged, the crash
> > > elfcorehdr, which describes the CPUs and memory in the system,
> > > must also be updated.
> > > 
> > > When loading the crash kernel via kexec_load or kexec_file_load,
> > > the elfcorehdr is identified at run time in
> > > crash_core:handle_hotplug_event().
> > > 
> > > To update the elfcorehdr for x86_64, a new elfcorehdr must be
> > > generated from the available CPUs and memory. The new elfcorehdr
> > > is prepared into a buffer, and then installed over the top of
> > > the existing elfcorehdr.
> > > 
> > > In the patch 'kexec: exclude elfcorehdr from the segment digest'
> > > the need to update purgatory due to the change in elfcorehdr was
> > > eliminated.  As a result, no changes to purgatory or boot_params
> > > (as the elfcorehdr= kernel command line parameter pointer
> > > remains unchanged and correct) are needed, just elfcorehdr.
> > > 
> > > To accommodate a growing number of resources via hotplug, the
> > > elfcorehdr segment must be sufficiently large enough to accommodate
> > > changes, see the CRASH_MAX_MEMORY_RANGES configure item.
> > > 
> > > With this change, crash hotplug for kexec_file_load syscall
> > > is supported. The kexec_load is also supported, but also
> > > requires a corresponding change to userspace kexec-tools.
> > > 
> > > Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
> > > ---
> > >   arch/x86/Kconfig        |  11 ++++
> > >   arch/x86/kernel/crash.c | 116 ++++++++++++++++++++++++++++++++++++++++
> > >   2 files changed, 127 insertions(+)
> > > 
> > > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> > > index 762a0b6ab8b6..e9eecff3b97d 100644
> > > --- a/arch/x86/Kconfig
> > > +++ b/arch/x86/Kconfig
> > > @@ -2082,6 +2082,17 @@ config CRASH_DUMP
> > >         (CONFIG_RELOCATABLE=y).
> > >         For more details see Documentation/admin-guide/kdump/kdump.rst
> > > +config CRASH_MAX_MEMORY_RANGES
> > > +    depends on CRASH_DUMP && KEXEC_FILE && (HOTPLUG_CPU || MEMORY_HOTPLUG)
> > > +    int
> > > +    default 32768
> > > +    help
> > > +      For the kexec_file_load path, specify the maximum number of
> > > +      memory regions, eg. as represented by the 'System RAM' entries
> > > +      in /proc/iomem, that the elfcorehdr buffer/segment can accommodate.
> > > +      This value is combined with NR_CPUS and multiplied by Elf64_Phdr
> > > +      size to determine the final buffer size.
> > > +
> > >   config KEXEC_JUMP
> > >       bool "kexec jump"
> > >       depends on KEXEC && HIBERNATION
> > > diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
> > > index 9db41cce8d97..b9cdf7a0d868 100644
> > > --- a/arch/x86/kernel/crash.c
> > > +++ b/arch/x86/kernel/crash.c
> > > @@ -25,6 +25,7 @@
> > >   #include <linux/slab.h>
> > >   #include <linux/vmalloc.h>
> > >   #include <linux/memblock.h>
> > > +#include <linux/highmem.h>
> > >   #include <asm/processor.h>
> > >   #include <asm/hardirq.h>
> > > @@ -398,7 +399,17 @@ int crash_load_segments(struct kimage *image)
> > >       image->elf_headers = kbuf.buffer;
> > >       image->elf_headers_sz = kbuf.bufsz;
> > > +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
> > > +    /* Ensure elfcorehdr segment large enough for hotplug changes */
> > > +    kbuf.memsz = (CONFIG_NR_CPUS_DEFAULT + CONFIG_CRASH_MAX_MEMORY_RANGES) * sizeof(Elf64_Phdr);
> > > +    /* For marking as usable to crash kernel */
> > > +    image->elf_headers_sz = kbuf.memsz;
> > > +    /* Record the index of the elfcorehdr segment */
> > > +    image->elfcorehdr_index = image->nr_segments;
> > > +    image->elfcorehdr_index_valid = true;
> > > +#else
> > >       kbuf.memsz = kbuf.bufsz;
> > > +#endif
> > >       kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
> > >       kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> > >       ret = kexec_add_buffer(&kbuf);
> > > @@ -413,3 +424,108 @@ int crash_load_segments(struct kimage *image)
> > >       return ret;
> > >   }
> > >   #endif /* CONFIG_KEXEC_FILE */
> > > +
> > > +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
> > > +int crash_hotplug_support(void) { return 1; }
> > > +void *arch_map_crash_pages(unsigned long paddr, unsigned long size)
> > > +{
> > > +    /*
> > > +     * NOTE: The addresses and sizes passed to this routine have
> > > +     * already been fully aligned on page boundaries. There is no
> > > +     * need for massaging the address or size.
> > > +     */
> > > +    void *ptr = NULL;
> > > +
> > > +    /* NOTE: requires arch_kexec_[un]protect_crashkres() for write access */
> > > +    if (size > 0) {
> > > +        struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
> > > +
> > > +        ptr = kmap(page);
> > > +    }
> > > +
> > > +    return ptr;
> > > +}
> > > +
> > > +void arch_unmap_crash_pages(void **ptr)
> > > +{
> > > +    if (ptr) {
> > > +        if (*ptr)
> > > +            kunmap(*ptr);
> > > +        *ptr = NULL;
> > > +    }
> > > +}
> > 
> > Aren't arch will have build issue if arch_[un]map_crash_pages methods are not defined?
> Sourabh,
> Yes, you are correct. I'll add __weak versions of each in crash_core.c in the next patch.

Just a reminder, __weak is deprecated and has been cleaned up in
kernel/kexec*.c in below patch.

[PATCH 0/2] kexec: Drop __weak attributes from functions
Re: [PATCH v9 7/7] x86/crash: Add x86 crash hotplug support
Posted by Eric DeVolder 3 years, 5 months ago

On 7/11/22 04:57, Baoquan He wrote:
> On 07/07/22 at 07:55am, Eric DeVolder wrote:
>>
>>
>> On 6/20/22 00:06, Sourabh Jain wrote:
>>> Hello Eric,
>>>
>>> On 14/06/22 04:12, Eric DeVolder wrote:
>>>> For x86_64, when CPU or memory is hot un/plugged, the crash
>>>> elfcorehdr, which describes the CPUs and memory in the system,
>>>> must also be updated.
>>>>
>>>> When loading the crash kernel via kexec_load or kexec_file_load,
>>>> the elfcorehdr is identified at run time in
>>>> crash_core:handle_hotplug_event().
>>>>
>>>> To update the elfcorehdr for x86_64, a new elfcorehdr must be
>>>> generated from the available CPUs and memory. The new elfcorehdr
>>>> is prepared into a buffer, and then installed over the top of
>>>> the existing elfcorehdr.
>>>>
>>>> In the patch 'kexec: exclude elfcorehdr from the segment digest'
>>>> the need to update purgatory due to the change in elfcorehdr was
>>>> eliminated.  As a result, no changes to purgatory or boot_params
>>>> (as the elfcorehdr= kernel command line parameter pointer
>>>> remains unchanged and correct) are needed, just elfcorehdr.
>>>>
>>>> To accommodate a growing number of resources via hotplug, the
>>>> elfcorehdr segment must be sufficiently large enough to accommodate
>>>> changes, see the CRASH_MAX_MEMORY_RANGES configure item.
>>>>
>>>> With this change, crash hotplug for kexec_file_load syscall
>>>> is supported. The kexec_load is also supported, but also
>>>> requires a corresponding change to userspace kexec-tools.
>>>>
>>>> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
>>>> ---
>>>>    arch/x86/Kconfig        |  11 ++++
>>>>    arch/x86/kernel/crash.c | 116 ++++++++++++++++++++++++++++++++++++++++
>>>>    2 files changed, 127 insertions(+)
>>>>
>>>> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
>>>> index 762a0b6ab8b6..e9eecff3b97d 100644
>>>> --- a/arch/x86/Kconfig
>>>> +++ b/arch/x86/Kconfig
>>>> @@ -2082,6 +2082,17 @@ config CRASH_DUMP
>>>>          (CONFIG_RELOCATABLE=y).
>>>>          For more details see Documentation/admin-guide/kdump/kdump.rst
>>>> +config CRASH_MAX_MEMORY_RANGES
>>>> +    depends on CRASH_DUMP && KEXEC_FILE && (HOTPLUG_CPU || MEMORY_HOTPLUG)
>>>> +    int
>>>> +    default 32768
>>>> +    help
>>>> +      For the kexec_file_load path, specify the maximum number of
>>>> +      memory regions, eg. as represented by the 'System RAM' entries
>>>> +      in /proc/iomem, that the elfcorehdr buffer/segment can accommodate.
>>>> +      This value is combined with NR_CPUS and multiplied by Elf64_Phdr
>>>> +      size to determine the final buffer size.
>>>> +
>>>>    config KEXEC_JUMP
>>>>        bool "kexec jump"
>>>>        depends on KEXEC && HIBERNATION
>>>> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
>>>> index 9db41cce8d97..b9cdf7a0d868 100644
>>>> --- a/arch/x86/kernel/crash.c
>>>> +++ b/arch/x86/kernel/crash.c
>>>> @@ -25,6 +25,7 @@
>>>>    #include <linux/slab.h>
>>>>    #include <linux/vmalloc.h>
>>>>    #include <linux/memblock.h>
>>>> +#include <linux/highmem.h>
>>>>    #include <asm/processor.h>
>>>>    #include <asm/hardirq.h>
>>>> @@ -398,7 +399,17 @@ int crash_load_segments(struct kimage *image)
>>>>        image->elf_headers = kbuf.buffer;
>>>>        image->elf_headers_sz = kbuf.bufsz;
>>>> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
>>>> +    /* Ensure elfcorehdr segment large enough for hotplug changes */
>>>> +    kbuf.memsz = (CONFIG_NR_CPUS_DEFAULT + CONFIG_CRASH_MAX_MEMORY_RANGES) * sizeof(Elf64_Phdr);
>>>> +    /* For marking as usable to crash kernel */
>>>> +    image->elf_headers_sz = kbuf.memsz;
>>>> +    /* Record the index of the elfcorehdr segment */
>>>> +    image->elfcorehdr_index = image->nr_segments;
>>>> +    image->elfcorehdr_index_valid = true;
>>>> +#else
>>>>        kbuf.memsz = kbuf.bufsz;
>>>> +#endif
>>>>        kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
>>>>        kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
>>>>        ret = kexec_add_buffer(&kbuf);
>>>> @@ -413,3 +424,108 @@ int crash_load_segments(struct kimage *image)
>>>>        return ret;
>>>>    }
>>>>    #endif /* CONFIG_KEXEC_FILE */
>>>> +
>>>> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
>>>> +int crash_hotplug_support(void) { return 1; }
>>>> +void *arch_map_crash_pages(unsigned long paddr, unsigned long size)
>>>> +{
>>>> +    /*
>>>> +     * NOTE: The addresses and sizes passed to this routine have
>>>> +     * already been fully aligned on page boundaries. There is no
>>>> +     * need for massaging the address or size.
>>>> +     */
>>>> +    void *ptr = NULL;
>>>> +
>>>> +    /* NOTE: requires arch_kexec_[un]protect_crashkres() for write access */
>>>> +    if (size > 0) {
>>>> +        struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
>>>> +
>>>> +        ptr = kmap(page);
>>>> +    }
>>>> +
>>>> +    return ptr;
>>>> +}
>>>> +
>>>> +void arch_unmap_crash_pages(void **ptr)
>>>> +{
>>>> +    if (ptr) {
>>>> +        if (*ptr)
>>>> +            kunmap(*ptr);
>>>> +        *ptr = NULL;
>>>> +    }
>>>> +}
>>>
>>> Aren't arch will have build issue if arch_[un]map_crash_pages methods are not defined?
>> Sourabh,
>> Yes, you are correct. I'll add __weak versions of each in crash_core.c in the next patch.
> 
> Just a reminder, __weak is deprecated and has been cleaned up in
> kernel/kexec*.c in below patch.
> 
> [PATCH 0/2] kexec: Drop __weak attributes from functions
> 
Baoquan,
Thanks for the pointer! I have corrected this code to do away with __weak and use the style 
presented in the kexec patch.
Eric