Commit 9c15e852 authored by Haren Myneni's avatar Haren Myneni Committed by Linus Torvalds
Browse files

[PATCH] kexec: fix in free initrd when overlapped with crashkernel region

It is possible that the reserved crashkernel region can be overlapped with
initrd since the bootloader sets the initrd location.  When the initrd
region is freed, the second kernel memory will not be contiguous.  The
Kexec_load can cause an oops since there is no contiguous memory to write
the second kernel or this memory could be used in the first kernel itself
and may not be part of the dump.  For example, on powerpc, the initrd is
located at 36MB and the crashkernel starts at 32MB.  The kexec_load caused
panic since writing into non-allocated memory (after 36MB).  We could see
the similar issue even on other archs.

One possibility is to move the initrd outside of crashkernel region.  But,
the initrd region will be freed anyway before the system is up.  This patch
fixes this issue and frees only regions that are not part of crashkernel
memory in case overlaps.
Signed-off-by: default avatarHaren Myneni <>
Acked-by: default avatar"Eric W. Biederman" <>
Cc: Vivek Goyal <>
Signed-off-by: default avatarAndrew Morton <>
Signed-off-by: default avatarLinus Torvalds <>
parent afcd0241
......@@ -6,6 +6,7 @@
#include <linux/list.h>
#include <linux/linkage.h>
#include <linux/compat.h>
#include <linux/ioport.h>
#include <asm/kexec.h>
/* Verify architecture specific macros are defined */
......@@ -466,10 +466,32 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
extern char __initramfs_start[], __initramfs_end[];
#include <linux/initrd.h>
#include <linux/kexec.h>
static void __init free_initrd(void)
free_initrd_mem(initrd_start, initrd_end);
unsigned long crashk_start = (unsigned long)__va(crashk_res.start);
unsigned long crashk_end = (unsigned long)__va(crashk_res.end);
* If the initrd region is overlapped with crashkernel reserved region,
* free only memory that is not part of crashkernel region.
if (initrd_start < crashk_end && initrd_end > crashk_start) {
* Initialize initrd memory region since the kexec boot does
* not do.
memset((void *)initrd_start, 0, initrd_end - initrd_start);
if (initrd_start < crashk_start)
free_initrd_mem(initrd_start, crashk_start);
if (initrd_end > crashk_end)
free_initrd_mem(crashk_end, initrd_end);
} else
free_initrd_mem(initrd_start, initrd_end);
initrd_start = 0;
initrd_end = 0;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment