aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/machine_kexec_file.c
diff options
context:
space:
mode:
authorBenjamin Gwin <bgwin@google.com>2020-11-03 12:11:06 -0800
committerWill Deacon <will@kernel.org>2020-11-05 21:48:05 +0000
commit108aa503657ee2fe8aa071dc620d96372c252ecd (patch)
tree5c3b1dfde74956ffb25d66fd9066b9ca4c88b0e7 /arch/arm64/kernel/machine_kexec_file.c
parentarm64: kprobes: Use BRK instead of single-step when executing instructions out-of-line (diff)
downloadlinux-dev-108aa503657ee2fe8aa071dc620d96372c252ecd.tar.xz
linux-dev-108aa503657ee2fe8aa071dc620d96372c252ecd.zip
arm64: kexec_file: try more regions if loading segments fails
It's possible that the first region picked for the new kernel will make it impossible to fit the other segments in the required 32GB window, especially if we have a very large initrd. Instead of giving up, we can keep testing other regions for the kernel until we find one that works. Suggested-by: Ryan O'Leary <ryanoleary@google.com> Signed-off-by: Benjamin Gwin <bgwin@google.com> Link: https://lore.kernel.org/r/20201103201106.2397844-1-bgwin@google.com Signed-off-by: Will Deacon <will@kernel.org>
Diffstat (limited to '')
-rw-r--r--arch/arm64/kernel/machine_kexec_file.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index 5b0e67b93cdc..03210f644790 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -240,6 +240,11 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
return ret;
}
+/*
+ * Tries to add the initrd and DTB to the image. If it is not possible to find
+ * valid locations, this function will undo changes to the image and return non
+ * zero.
+ */
int load_other_segments(struct kimage *image,
unsigned long kernel_load_addr,
unsigned long kernel_size,
@@ -248,7 +253,8 @@ int load_other_segments(struct kimage *image,
{
struct kexec_buf kbuf;
void *headers, *dtb = NULL;
- unsigned long headers_sz, initrd_load_addr = 0, dtb_len;
+ unsigned long headers_sz, initrd_load_addr = 0, dtb_len,
+ orig_segments = image->nr_segments;
int ret = 0;
kbuf.image = image;
@@ -334,6 +340,7 @@ int load_other_segments(struct kimage *image,
return 0;
out_err:
+ image->nr_segments = orig_segments;
vfree(dtb);
return ret;
}