[RFC v4 PATCH 4/5] powerpc/crash hp: add crash hotplug support for kexec_file_load

Eric DeVolder eric.devolder at oracle.com
Thu Apr 21 08:33:26 PDT 2022



On 4/19/22 03:31, Sourabh Jain wrote:
> 
> On 14/04/22 22:02, Laurent Dufour wrote:
>> On 11/04/2022, 10:43:56, Sourabh Jain wrote:
>>> Two major changes are done to enable the crash CPU hotplug handler.
>>> Firstly, updated the kexec load path to prepare kimage for hotplug
>>> changes, and secondly, implemented the crash hotplug handler.
>>>
>>> On the kexec load path, the memsz allocation of the crash FDT segment
>>> is updated to ensure that it has sufficient buffer space to accommodate
>>> future hot add CPUs. Initialized the kimage members to track the kexec
>>> FDT segment.
>>>
>>> The crash hotplug handler updates the cpus node of crash FDT. While we
>>> update crash FDT the kexec_crash_image is marked invalid and restored
>>> after FDT update to avoid race.
>>>
>>> Since memory crash hotplug support is not there yet the crash hotplug
>>> the handler simply warns the user and returns.
>>>
>>> Signed-off-by: Sourabh Jain <sourabhjain at linux.ibm.com>
>>> ---
>>>   arch/powerpc/kexec/core_64.c | 46 ++++++++++++++++++++++
>>>   arch/powerpc/kexec/elf_64.c  | 74 ++++++++++++++++++++++++++++++++++++
>>>   2 files changed, 120 insertions(+)
>>>
>>> diff --git a/arch/powerpc/kexec/core_64.c b/arch/powerpc/kexec/core_64.c
>>> index 249d2632526d..62f77cc86407 100644
>>> --- a/arch/powerpc/kexec/core_64.c
>>> +++ b/arch/powerpc/kexec/core_64.c
>>> @@ -466,6 +466,52 @@ int update_cpus_node(void *fdt)
>>>       return ret;
>>>   }
>>> +#ifdef CONFIG_CRASH_HOTPLUG
>>> +/**
>>> + * arch_crash_hotplug_handler() - Handle hotplug FDT changes
>>> + * @image: the active struct kimage
>>> + * @hp_action: the hot un/plug action being handled
>>> + * @a: first parameter dependent upon hp_action
>>> + * @b: first parameter dependent upon hp_action
>>> + *
>>> + * To accurately reflect CPU hot un/plug changes, the FDT
>>> + * must be updated with the new list of CPUs and memories.
>>> + */
>>> +void arch_crash_hotplug_handler(struct kimage *image, unsigned int hp_action,
>>> +                unsigned long a, unsigned long b)
>>> +{
>>> +    void *fdt;
>>> +
>>> +    /* No action needed for CPU hot-unplug */
>>> +    if (hp_action == KEXEC_CRASH_HP_REMOVE_CPU)
>>> +        return;
>> I should have report since in the previous version too, why nothing is done
>> when CPU are removed?
> 
> Since CPU note addresses are already available for all possible CPUs
> (regardless they are online or not) the PHDR is allocated for all possible
> CPUs during elfcorehdr creation. At least for the kexec_load system call.
> 
> Now on the crash path, the crashing CPU initiates an IPI call to update
> the CPU data of all online CPUs and jumps to the purgatory. Hence no
> action is needed for the remove case.
> 
> With the above logic, we shouldn't be taking any action for the CPU add
> case too, right? But on PowerPC early boot path there is validation that
> checks the boot CPU is part of the  Flattened Device Tree (FDT) or not.
> If the boot CPU is not found in FDT the boot fails. Hence FDT needs to be
> updated for every new CPU added to the system but not needed when
> CPU is removed.
> 
> 
> Thanks
> Sourabh Jain
> 
>>
>>> +
>>> +    /* crash update on memory hotplug is not support yet */
>>> +    if (hp_action == KEXEC_CRASH_HP_REMOVE_MEMORY || hp_action == KEXEC_CRASH_HP_ADD_MEMORY) {
>>> +        pr_info_once("crash hp: crash update is not supported with memory hotplug\n");
>>> +        return;
>>> +    }

Sourabh,

Baoquan's preference is to do away with the hp_action (and a and b) parameters to
this function. As x86_64 has no need for them, I have no reason to argue for keeping
them.

If you really need hp_action, then please respond to Baoquan's concern in the
"[PATCH v7 4/8] crash: add generic infrastructure for crash hotplug support"
thread.

Thanks,
eric


>>> +
>>> +    /* Must have valid FDT index */
>>> +    if (!image->arch.fdt_index_valid) {
>>> +        pr_err("crash hp: unable to locate FDT segment");
>>> +        return;
>>> +    }
>>> +
>>> +    fdt = __va((void *)image->segment[image->arch.fdt_index].mem);
>>> +
>>> +    /* Temporarily invalidate the crash image while it is replaced */
>>> +    xchg(&kexec_crash_image, NULL);
>>> +
>>> +    /* update FDT to refelect changes to CPU resrouces */
>>> +    if (update_cpus_node(fdt))
>>> +        pr_err("crash hp: failed to update crash FDT");
>>> +
>>> +    /* The crash image is now valid once again */
>>> +    xchg(&kexec_crash_image, image);
>>> +}
>>> +#endif /* CONFIG_CRASH_HOTPLUG */
>>> +
>>>   #ifdef CONFIG_PPC_64S_HASH_MMU
>>>   /* Values we need to export to the second kernel via the device tree. */
>>>   static unsigned long htab_base;
>>> diff --git a/arch/powerpc/kexec/elf_64.c b/arch/powerpc/kexec/elf_64.c
>>> index eeb258002d1e..9dc774548ce4 100644
>>> --- a/arch/powerpc/kexec/elf_64.c
>>> +++ b/arch/powerpc/kexec/elf_64.c
>>> @@ -24,6 +24,67 @@
>>>   #include <linux/slab.h>
>>>   #include <linux/types.h>
>>> +#include <asm/kvm_book3s.h>
>>> +#include <asm/kvm_ppc.h>
>>> +
>>> +#ifdef CONFIG_CRASH_HOTPLUG
>>> +
>>> +/**
>>> + * get_cpu_node_sz() - Calculate the space needed to store a CPU device type node
>>> + *                     in FDT. The calculation is done based on the existing CPU
>>> + *                     node in unflatten device tree. Loop through all the
>>> + *                     properties of the very first CPU type device node found in
>>> + *                     unflatten device tree and returns the sum of the property
>>> + *                     length and property string size of all properties of a CPU
>>> + *                     node.
>>> + */
>> I don't think this is following the indent rules.
>>
>>> +static int get_cpu_node_sz(void) {
>>> +    struct device_node *dn = NULL;
>>> +    struct property *pp;
>>> +    int cpu_node_size = 0;
>>> +
>>> +    dn = of_find_node_by_type(NULL, "cpu");
>>> +
>>> +    if (!dn) {
>>> +        pr_warn("Unable to locate cpu device_type node.\n");
>>> +        goto out;
>>> +    }
>>> +
>>> +    /* Every node in FDT starts with FDT_BEGIN_NODE and ends with
>>> +     * FDT_END_NODE that takes one byte each.
>>> +     */
>>> +    cpu_node_size = 2;
>>> +
>>> +    for_each_property_of_node(dn, pp) {
>>> +        /* For each property add two bytes extra. One for string null
>>> +         * character for property name and other for FDT property start
>>> +         * tag FDT_PROP.
>>> +         */
>> Coding style request to start with a blank comment line for multiple
>> comment lines.
>>
>>> +        cpu_node_size = cpu_node_size + pp->length + strlen(pp->name) + 2;
>>> +    }
>>> +
>>> +out:
>>> +    return cpu_node_size;
>>> +}
>>> +
>>> +/**
>>> + * get_crash_fdt_mem_sz() - calcuate mem size for crash kernel FDT
>>> + * @fdt: pointer to crash kernel FDT
>>> + *
>>> + * Calculate the buffer space needed to add more CPU nodes in crash FDT
>>> + * post capture kenrel load due to CPU hotplug events.
>>> + */
>>> +static unsigned int get_crash_fdt_mem_sz(void *fdt)
>>> +{
>>> +    int fdt_cpu_nodes_sz, offline_cpu_cnt;
>>> +
>>> +    offline_cpu_cnt = (num_possible_cpus() - num_present_cpus()) / MAX_SMT_THREADS;
>>> +    fdt_cpu_nodes_sz = get_cpu_node_sz() * offline_cpu_cnt;
>>> +
>>> +    return fdt_totalsize(fdt) + fdt_cpu_nodes_sz;
>>> +}
>>> +#endif
>>> +
>>>   static void *elf64_load(struct kimage *image, char *kernel_buf,
>>>               unsigned long kernel_len, char *initrd,
>>>               unsigned long initrd_len, char *cmdline,
>>> @@ -123,6 +184,19 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
>>>       kbuf.buf_align = PAGE_SIZE;
>>>       kbuf.top_down = true;
>>>       kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
>>> +
>>> +#ifdef CONFIG_CRASH_HOTPLUG
>>> +    if (image->type == KEXEC_TYPE_CRASH) {
>>> +        kbuf.memsz = get_crash_fdt_mem_sz(fdt);
>>> +        fdt_set_totalsize(fdt, kbuf.memsz);
>>> +        image->arch.fdt_index = image->nr_segments;
>>> +        image->arch.fdt_index_valid = true;
>>> +    } else
>>> +#endif
>>> +    {
>>> +        kbuf.memsz = fdt_totalsize(fdt);
>>> +    }
>>> +
>>>       ret = kexec_add_buffer(&kbuf);
>>>       if (ret)
>>>           goto out_free_fdt;



More information about the kexec mailing list