While setting up the FDT for kexec, CPU nodes that are added after the
system boots and reserved memory ranges are incorporated into the
initial_boot_params (base FDT).

However, they are not taken into account when determining the additional
size needed for the kexec FDT. As a result, kexec fails to load,
generating the following error:

[1116.774451] Error updating memory reserve map: FDT_ERR_NOSPACE
kexec_file_load failed: No such process

Therefore, consider the extra size for CPU nodes added post-system boot
and reserved memory ranges while preparing the kexec FDT.

While adding a new parameter to the setup_new_fdt_ppc64 function, it was
noticed that there were a couple of unused parameters, so they were
removed.

Cc: Aditya Gupta <adit...@linux.ibm.com>
Cc: Hari Bathini <hbath...@linux.ibm.com>
Cc: Mahesh Salgaonkar <mah...@linux.ibm.com>
Cc: Michael Ellerman <m...@ellerman.id.au>
Cc: "Naveen N. Rao" <naveen.n....@linux.ibm.com>
Signed-off-by: Sourabh Jain <sourabhj...@linux.ibm.com>
---

Changelog:

Since v1:
  - Initialize local variable `cpu_nodes` before using it. 01/02

---

 arch/powerpc/include/asm/kexec.h  |  6 ++--
 arch/powerpc/kexec/elf_64.c       | 12 +++++--
 arch/powerpc/kexec/file_load_64.c | 53 +++++++++++++------------------
 3 files changed, 33 insertions(+), 38 deletions(-)

diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index 95a98b390d62..270ee93a0f7d 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -103,10 +103,8 @@ int load_crashdump_segments_ppc64(struct kimage *image,
 int setup_purgatory_ppc64(struct kimage *image, const void *slave_code,
                          const void *fdt, unsigned long kernel_load_addr,
                          unsigned long fdt_load_addr);
-unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image);
-int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
-                       unsigned long initrd_load_addr,
-                       unsigned long initrd_len, const char *cmdline);
+unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem 
*rmem);
+int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, struct 
crash_mem *rmem);
 #endif /* CONFIG_PPC64 */
 
 #endif /* CONFIG_KEXEC_FILE */
diff --git a/arch/powerpc/kexec/elf_64.c b/arch/powerpc/kexec/elf_64.c
index 214c071c58ed..5d6d616404cf 100644
--- a/arch/powerpc/kexec/elf_64.c
+++ b/arch/powerpc/kexec/elf_64.c
@@ -23,6 +23,7 @@
 #include <linux/of_fdt.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <asm/kexec_ranges.h>
 
 static void *elf64_load(struct kimage *image, char *kernel_buf,
                        unsigned long kernel_len, char *initrd,
@@ -36,6 +37,7 @@ static void *elf64_load(struct kimage *image, char 
*kernel_buf,
        const void *slave_code;
        struct elfhdr ehdr;
        char *modified_cmdline = NULL;
+       struct crash_mem *rmem = NULL;
        struct kexec_elf_info elf_info;
        struct kexec_buf kbuf = { .image = image, .buf_min = 0,
                                  .buf_max = ppc64_rma_size };
@@ -102,17 +104,20 @@ static void *elf64_load(struct kimage *image, char 
*kernel_buf,
                kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_load_addr);
        }
 
+       ret = get_reserved_memory_ranges(&rmem);
+       if (ret)
+               goto out;
+
        fdt = of_kexec_alloc_and_setup_fdt(image, initrd_load_addr,
                                           initrd_len, cmdline,
-                                          kexec_extra_fdt_size_ppc64(image));
+                                          kexec_extra_fdt_size_ppc64(image, 
rmem));
        if (!fdt) {
                pr_err("Error setting up the new device tree.\n");
                ret = -EINVAL;
                goto out;
        }
 
-       ret = setup_new_fdt_ppc64(image, fdt, initrd_load_addr,
-                                 initrd_len, cmdline);
+       ret = setup_new_fdt_ppc64(image, fdt, rmem);
        if (ret)
                goto out_free_fdt;
 
@@ -146,6 +151,7 @@ static void *elf64_load(struct kimage *image, char 
*kernel_buf,
 out_free_fdt:
        kvfree(fdt);
 out:
+       kfree(rmem);
        kfree(modified_cmdline);
        kexec_free_elf_info(&elf_info);
 
diff --git a/arch/powerpc/kexec/file_load_64.c 
b/arch/powerpc/kexec/file_load_64.c
index 925a69ad2468..413c76de283d 100644
--- a/arch/powerpc/kexec/file_load_64.c
+++ b/arch/powerpc/kexec/file_load_64.c
@@ -803,10 +803,9 @@ static unsigned int cpu_node_size(void)
        return size;
 }
 
-static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image)
+static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image, unsigned 
int cpu_nodes)
 {
-       unsigned int cpu_nodes, extra_size = 0;
-       struct device_node *dn;
+       unsigned int extra_size = 0;
        u64 usm_entries;
 #ifdef CONFIG_CRASH_HOTPLUG
        unsigned int possible_cpu_nodes;
@@ -826,18 +825,6 @@ static unsigned int kdump_extra_fdt_size_ppc64(struct 
kimage *image)
                extra_size += (unsigned int)(usm_entries * sizeof(u64));
        }
 
-       /*
-        * Get the number of CPU nodes in the current DT. This allows to
-        * reserve places for CPU nodes added since the boot time.
-        */
-       cpu_nodes = 0;
-       for_each_node_by_type(dn, "cpu") {
-               cpu_nodes++;
-       }
-
-       if (cpu_nodes > boot_cpu_node_count)
-               extra_size += (cpu_nodes - boot_cpu_node_count) * 
cpu_node_size();
-
 #ifdef CONFIG_CRASH_HOTPLUG
        /*
         * Make sure enough space is reserved to accommodate possible CPU nodes
@@ -861,16 +848,30 @@ static unsigned int kdump_extra_fdt_size_ppc64(struct 
kimage *image)
  *
  * Returns the estimated extra size needed for kexec/kdump kernel FDT.
  */
-unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
+unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem 
*rmem)
 {
-       unsigned int extra_size = 0;
+       struct device_node *dn;
+       unsigned int cpu_nodes = 0, extra_size = 0;
 
        // Budget some space for the password blob. There's already extra space
        // for the key name
        if (plpks_is_available())
                extra_size += (unsigned int)plpks_get_passwordlen();
 
-       return extra_size + kdump_extra_fdt_size_ppc64(image);
+       /* Get the number of CPU nodes in the current device tree */
+       for_each_node_by_type(dn, "cpu") {
+               cpu_nodes++;
+       }
+
+       /* Consider extra space for CPU nodes added since the boot time */
+       if (cpu_nodes > boot_cpu_node_count)
+               extra_size += (cpu_nodes - boot_cpu_node_count) * 
cpu_node_size();
+
+       /* Consider extra space for reserved memory ranges if any */
+       if (rmem->nr_ranges > 0)
+               extra_size += sizeof(struct fdt_reserve_entry) * 
rmem->nr_ranges;
+
+       return extra_size + kdump_extra_fdt_size_ppc64(image, cpu_nodes);
 }
 
 static int copy_property(void *fdt, int node_offset, const struct device_node 
*dn,
@@ -924,18 +925,13 @@ static int update_pci_dma_nodes(void *fdt, const char 
*dmapropname)
  *                       being loaded.
  * @image:               kexec image being loaded.
  * @fdt:                 Flattened device tree for the next kernel.
- * @initrd_load_addr:    Address where the next initrd will be loaded.
- * @initrd_len:          Size of the next initrd, or 0 if there will be none.
- * @cmdline:             Command line for the next kernel, or NULL if there 
will
- *                       be none.
+ * @rmem:                Reserved memory ranges.
  *
  * Returns 0 on success, negative errno on error.
  */
-int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
-                       unsigned long initrd_load_addr,
-                       unsigned long initrd_len, const char *cmdline)
+int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, struct 
crash_mem *rmem)
 {
-       struct crash_mem *umem = NULL, *rmem = NULL;
+       struct crash_mem *umem = NULL;
        int i, nr_ranges, ret;
 
 #ifdef CONFIG_CRASH_DUMP
@@ -991,10 +987,6 @@ int setup_new_fdt_ppc64(const struct kimage *image, void 
*fdt,
                goto out;
 
        /* Update memory reserve map */
-       ret = get_reserved_memory_ranges(&rmem);
-       if (ret)
-               goto out;
-
        nr_ranges = rmem ? rmem->nr_ranges : 0;
        for (i = 0; i < nr_ranges; i++) {
                u64 base, size;
@@ -1014,7 +1006,6 @@ int setup_new_fdt_ppc64(const struct kimage *image, void 
*fdt,
                ret = plpks_populate_fdt(fdt);
 
 out:
-       kfree(rmem);
        kfree(umem);
        return ret;
 }
-- 
2.44.0

Reply via email to