Skip to content

Commit

Permalink
s390/kexec: fix crash on resize of reserved memory
Browse files Browse the repository at this point in the history
Reducing the size of reserved memory for the crash kernel will result
in an immediate crash on s390. Reason for that is that we do not
create struct pages for memory that is reserved. If that memory is
freed any access to struct pages which correspond to this memory will
result in invalid memory accesses and a kernel panic.

Fix this by properly creating struct pages when the system gets
initialized. Change the code also to make use of set_memory_ro() and
set_memory_rw() so page tables will be split if required.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
  • Loading branch information
heicarst authored and Martin Schwidefsky committed Jun 13, 2016
1 parent 2d0af22 commit 4e042af
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 23 deletions.
33 changes: 11 additions & 22 deletions arch/s390/kernel/machine_kexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <asm/diag.h>
#include <asm/elf.h>
#include <asm/asm-offsets.h>
#include <asm/cacheflush.h>
#include <asm/os_info.h>
#include <asm/switch_to.h>

Expand Down Expand Up @@ -60,8 +61,6 @@ static int machine_kdump_pm_cb(struct notifier_block *nb, unsigned long action,
static int __init machine_kdump_pm_init(void)
{
pm_notifier(machine_kdump_pm_cb, 0);
/* Create initial mapping for crashkernel memory */
arch_kexec_unprotect_crashkres();
return 0;
}
arch_initcall(machine_kdump_pm_init);
Expand Down Expand Up @@ -163,37 +162,27 @@ void crash_free_reserved_phys_range(unsigned long begin, unsigned long end)
os_info_crashkernel_add(0, 0);
}

/*
* Map or unmap crashkernel memory
*/
static void crash_map_pages(int enable)
static void crash_protect_pages(int protect)
{
unsigned long size = resource_size(&crashk_res);
unsigned long size;

BUG_ON(crashk_res.start % KEXEC_CRASH_MEM_ALIGN ||
size % KEXEC_CRASH_MEM_ALIGN);
if (enable)
vmem_add_mapping(crashk_res.start, size);
if (!crashk_res.end)
return;
size = resource_size(&crashk_res);
if (protect)
set_memory_ro(crashk_res.start, size >> PAGE_SHIFT);
else
vmem_remove_mapping(crashk_res.start, size);
set_memory_rw(crashk_res.start, size >> PAGE_SHIFT);
}

/*
* Unmap crashkernel memory
*/
void arch_kexec_protect_crashkres(void)
{
if (crashk_res.end)
crash_map_pages(0);
crash_protect_pages(1);
}

/*
* Map crashkernel memory
*/
void arch_kexec_unprotect_crashkres(void)
{
if (crashk_res.end)
crash_map_pages(1);
crash_protect_pages(0);
}

#endif
Expand Down
15 changes: 14 additions & 1 deletion arch/s390/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,20 @@ static void __init setup_resources(void)
}
}
}
#ifdef CONFIG_CRASH_DUMP
/*
* Re-add removed crash kernel memory as reserved memory. This makes
* sure it will be mapped with the identity mapping and struct pages
* will be created, so it can be resized later on.
* However add it later since the crash kernel resource should not be
* part of the System RAM resource.
*/
if (crashk_res.end) {
memblock_add(crashk_res.start, resource_size(&crashk_res));
memblock_reserve(crashk_res.start, resource_size(&crashk_res));
insert_resource(&iomem_resource, &crashk_res);
}
#endif
}

static void __init setup_memory_end(void)
Expand Down Expand Up @@ -602,7 +616,6 @@ static void __init reserve_crashkernel(void)
diag10_range(PFN_DOWN(crash_base), PFN_DOWN(crash_size));
crashk_res.start = crash_base;
crashk_res.end = crash_base + crash_size - 1;
insert_resource(&iomem_resource, &crashk_res);
memblock_remove(crash_base, crash_size);
pr_info("Reserving %lluMB of memory at %lluMB "
"for crashkernel (System RAM: %luMB)\n",
Expand Down

0 comments on commit 4e042af

Please sign in to comment.