Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/kexec_file: fix extra size calculation for kexec FDT

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.

Signed-off-by: Sourabh Jain <sourabhjain@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240510102235.2269496-2-sourabhjain@linux.ibm.com

authored by

Sourabh Jain and committed by
Michael Ellerman
0d3ff067 0300a92e

+33 -38
+2 -4
arch/powerpc/include/asm/kexec.h
··· 103 103 int setup_purgatory_ppc64(struct kimage *image, const void *slave_code, 104 104 const void *fdt, unsigned long kernel_load_addr, 105 105 unsigned long fdt_load_addr); 106 - unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image); 107 - int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, 108 - unsigned long initrd_load_addr, 109 - unsigned long initrd_len, const char *cmdline); 106 + unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem *rmem); 107 + int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, struct crash_mem *rmem); 110 108 #endif /* CONFIG_PPC64 */ 111 109 112 110 #endif /* CONFIG_KEXEC_FILE */
+9 -3
arch/powerpc/kexec/elf_64.c
··· 23 23 #include <linux/of_fdt.h> 24 24 #include <linux/slab.h> 25 25 #include <linux/types.h> 26 + #include <asm/kexec_ranges.h> 26 27 27 28 static void *elf64_load(struct kimage *image, char *kernel_buf, 28 29 unsigned long kernel_len, char *initrd, ··· 37 36 const void *slave_code; 38 37 struct elfhdr ehdr; 39 38 char *modified_cmdline = NULL; 39 + struct crash_mem *rmem = NULL; 40 40 struct kexec_elf_info elf_info; 41 41 struct kexec_buf kbuf = { .image = image, .buf_min = 0, 42 42 .buf_max = ppc64_rma_size }; ··· 104 102 kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_load_addr); 105 103 } 106 104 105 + ret = get_reserved_memory_ranges(&rmem); 106 + if (ret) 107 + goto out; 108 + 107 109 fdt = of_kexec_alloc_and_setup_fdt(image, initrd_load_addr, 108 110 initrd_len, cmdline, 109 - kexec_extra_fdt_size_ppc64(image)); 111 + kexec_extra_fdt_size_ppc64(image, rmem)); 110 112 if (!fdt) { 111 113 pr_err("Error setting up the new device tree.\n"); 112 114 ret = -EINVAL; 113 115 goto out; 114 116 } 115 117 116 - ret = setup_new_fdt_ppc64(image, fdt, initrd_load_addr, 117 - initrd_len, cmdline); 118 + ret = setup_new_fdt_ppc64(image, fdt, rmem); 118 119 if (ret) 119 120 goto out_free_fdt; 120 121 ··· 151 146 out_free_fdt: 152 147 kvfree(fdt); 153 148 out: 149 + kfree(rmem); 154 150 kfree(modified_cmdline); 155 151 kexec_free_elf_info(&elf_info); 156 152
+22 -31
arch/powerpc/kexec/file_load_64.c
··· 803 803 return size; 804 804 } 805 805 806 - static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image) 806 + static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image, unsigned int cpu_nodes) 807 807 { 808 - unsigned int cpu_nodes, extra_size = 0; 809 - struct device_node *dn; 808 + unsigned int extra_size = 0; 810 809 u64 usm_entries; 811 810 #ifdef CONFIG_CRASH_HOTPLUG 812 811 unsigned int possible_cpu_nodes; ··· 824 825 (2 * (resource_size(&crashk_res) / drmem_lmb_size()))); 825 826 extra_size += (unsigned int)(usm_entries * sizeof(u64)); 826 827 } 827 - 828 - /* 829 - * Get the number of CPU nodes in the current DT. This allows to 830 - * reserve places for CPU nodes added since the boot time. 831 - */ 832 - cpu_nodes = 0; 833 - for_each_node_by_type(dn, "cpu") { 834 - cpu_nodes++; 835 - } 836 - 837 - if (cpu_nodes > boot_cpu_node_count) 838 - extra_size += (cpu_nodes - boot_cpu_node_count) * cpu_node_size(); 839 828 840 829 #ifdef CONFIG_CRASH_HOTPLUG 841 830 /* ··· 848 861 * 849 862 * Returns the estimated extra size needed for kexec/kdump kernel FDT. 850 863 */ 851 - unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image) 864 + unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem *rmem) 852 865 { 853 - unsigned int extra_size = 0; 866 + struct device_node *dn; 867 + unsigned int cpu_nodes = 0, extra_size = 0; 854 868 855 869 // Budget some space for the password blob. There's already extra space 856 870 // for the key name 857 871 if (plpks_is_available()) 858 872 extra_size += (unsigned int)plpks_get_passwordlen(); 859 873 860 - return extra_size + kdump_extra_fdt_size_ppc64(image); 874 + /* Get the number of CPU nodes in the current device tree */ 875 + for_each_node_by_type(dn, "cpu") { 876 + cpu_nodes++; 877 + } 878 + 879 + /* Consider extra space for CPU nodes added since the boot time */ 880 + if (cpu_nodes > boot_cpu_node_count) 881 + extra_size += (cpu_nodes - boot_cpu_node_count) * cpu_node_size(); 882 + 883 + /* Consider extra space for reserved memory ranges if any */ 884 + if (rmem->nr_ranges > 0) 885 + extra_size += sizeof(struct fdt_reserve_entry) * rmem->nr_ranges; 886 + 887 + return extra_size + kdump_extra_fdt_size_ppc64(image, cpu_nodes); 861 888 } 862 889 863 890 static int copy_property(void *fdt, int node_offset, const struct device_node *dn, ··· 925 924 * being loaded. 926 925 * @image: kexec image being loaded. 927 926 * @fdt: Flattened device tree for the next kernel. 928 - * @initrd_load_addr: Address where the next initrd will be loaded. 929 - * @initrd_len: Size of the next initrd, or 0 if there will be none. 930 - * @cmdline: Command line for the next kernel, or NULL if there will 931 - * be none. 927 + * @rmem: Reserved memory ranges. 932 928 * 933 929 * Returns 0 on success, negative errno on error. 934 930 */ 935 - int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, 936 - unsigned long initrd_load_addr, 937 - unsigned long initrd_len, const char *cmdline) 931 + int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, struct crash_mem *rmem) 938 932 { 939 - struct crash_mem *umem = NULL, *rmem = NULL; 933 + struct crash_mem *umem = NULL; 940 934 int i, nr_ranges, ret; 941 935 942 936 #ifdef CONFIG_CRASH_DUMP ··· 987 991 goto out; 988 992 989 993 /* Update memory reserve map */ 990 - ret = get_reserved_memory_ranges(&rmem); 991 - if (ret) 992 - goto out; 993 - 994 994 nr_ranges = rmem ? rmem->nr_ranges : 0; 995 995 for (i = 0; i < nr_ranges; i++) { 996 996 u64 base, size; ··· 1006 1014 ret = plpks_populate_fdt(fdt); 1007 1015 1008 1016 out: 1009 - kfree(rmem); 1010 1017 kfree(umem); 1011 1018 return ret; 1012 1019 }