hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I6Y5Y1
-------------------------------
We call reserve_crashkernel_high() before map_mem() to reserve high memory in advance, which in turn can avoid using page level mapping for all memory above 4G to optimize performance. And after reserve_crashkernel_high(), reserve_crashkernel_low() is also needed to reserve low memory. But when the system RAM is less than 4G, the memory reserved by reserve_crashkernel_high() is already low memory (less than 4G), reserve_crashkernel_low() may reserve low memory again and the memory it reserves may be higher than that reserved by reserve_crashkernel_high(). Looking at /proc/iomem would have:
# cat /proc/iomem | grep -i crash 65400000-953fffff : Crash kernel ==> crashk_res a7800000-b77fffff : Crash kernel ==> crashk_res_low
At this point kexec-tools will incorrectly use the second memory segment for the kdump kernel image load, causing the kernel load address check to fail during kexec load (see sanity_check_segment_list()).
When the memory reserved by reserve_crashkernel_high() meets the low memory requirement, reserve_crashkernel_low() is no longer called to reserve memory and avoid introducing problems with duplicate reservations.
Fixes: baac34dd89ca ("arm64: kdump: Use page-level mapping for the high memory of crashkernel") Signed-off-by: Li Huafei lihuafei1@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com --- kernel/crash_core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/kernel/crash_core.c b/kernel/crash_core.c index 0865f816b57a..d1402585bf84 100644 --- a/kernel/crash_core.c +++ b/kernel/crash_core.c @@ -440,6 +440,13 @@ static void __init free_reserved_high_mem(void) memblock_free(crashk_res_high.start, resource_size(&crashk_res_high)); }
+static bool __init within_low_mem(unsigned long long crash_base, + unsigned long long crash_size) +{ + return crash_base < CRASH_ADDR_LOW_MAX && + CRASH_ADDR_LOW_MAX - crash_base >= crash_size; +} + /* * reserve_crashkernel() - reserves memory for crash kernel * @@ -469,6 +476,8 @@ void __init reserve_crashkernel(void)
if (crash_high_mem_reserved) { take_reserved_high_mem(&crash_base, &crash_size); + if (within_low_mem(crash_base, crash_size)) + goto reserve_ok; goto reserve_low; } } @@ -490,6 +499,8 @@ void __init reserve_crashkernel(void) CRASH_ALIGN); if (!crash_base && crash_high_mem_reserved) { take_reserved_high_mem(&crash_base, &crash_size); + if (within_low_mem(crash_base, crash_size)) + goto reserve_ok; goto reserve_low; } } @@ -539,6 +550,7 @@ void __init reserve_crashkernel(void) free_reserved_high_mem(); }
+reserve_ok: pr_info("Reserving %ldMB of memory at %ldMB for crashkernel (System RAM: %ldMB)\n", (unsigned long)(crash_size >> 20), (unsigned long)(crash_base >> 20),