Skip to content

Commit 6c4dcad

Browse files
Baoquan Hectmarinas
authored andcommitted
arm64: kdump: simplify the reservation behaviour of crashkernel=,high
On arm64, reservation for 'crashkernel=xM,high' is taken by searching for suitable memory region top down. If the 'xM' of crashkernel high memory is reserved from high memory successfully, it will try to reserve crashkernel low memory later accoringly. Otherwise, it will try to search low memory area for the 'xM' suitable region. Please see the details in Documentation/admin-guide/kernel-parameters.txt. While we observed an unexpected case where a reserved region crosses the high and low meomry boundary. E.g on a system with 4G as low memory end, user added the kernel parameters like: 'crashkernel=512M,high', it could finally have [4G-126M, 4G+386M], [1G, 1G+128M] regions in running kernel. The crashkernel high region crossing low and high memory boudary will bring issues: 1) For crashkernel=x,high, if getting crashkernel high region across low and high memory boundary, then user will see two memory regions in low memory, and one memory region in high memory. The two crashkernel low memory regions are confusing as shown in above example. 2) If people explicityly specify "crashkernel=x,high crashkernel=y,low" and y <= 128M, when crashkernel high region crosses low and high memory boundary and the part of crashkernel high reservation below boundary is bigger than y, the expected crahskernel low reservation will be skipped. But the expected crashkernel high reservation is shrank and could not satisfy user space requirement. 3) The crossing boundary behaviour of crahskernel high reservation is different than x86 arch. On x86_64, the low memory end is 4G fixedly, and the memory near 4G is reserved by system, e.g for mapping firmware, pci mapping, so the crashkernel reservation crossing boundary never happens. From distros point of view, this brings inconsistency and confusion. Users need to dig into x86 and arm64 system details to find out why. For kernel itself, the impact of issue 3) could be slight. While issue 1) and 2) cause actual impact because it brings obscure semantics and behaviour to crashkernel=,high reservation. Here, for crashkernel=xM,high, search the high memory for the suitable region only in high memory. If failed, try reserving the suitable region only in low memory. Like this, the crashkernel high region will only exist in high memory, and crashkernel low region only exists in low memory. The reservation behaviour for crashkernel=,high is clearer and simpler. Note: RPi4 has different zone ranges than normal memory. Its DMA zone is 0~1G, and DMA32 zone is 1G~4G if CONFIG_ZONE_DMA|DMA32 are enabled by default. The low memory end is 1G in order to validate all devices, high memory starts at 1G memory. However, for being consistent with normal arm64 system, its low memory end is still 1G, while reserving crashkernel high memory from 4G if crashkernel=size,high specified. This will remove confusion. With above change applied, summary of arm64 crashkernel reservation range: 1) RPi4(zone DMA:0~1G; DMA32:1G~4G): crashkernel=size 0~1G: low memory | 1G~top: high memory crashkernel=size,high 0~1G: low memory | 4G~top: high memory 2) Other normal system: crashkernel=size crashkernel=size,high 0~4G: low memory | 4G~top: high memory 3) Systems w/o zone DMA|DMA32 crashkernel=size crashkernel=size,high 0~top: low memory Signed-off-by: Baoquan He <[email protected]> Reviewed-by: Catalin Marinas <[email protected]> Reviewed-by: Zhen Lei <[email protected]> Link: https://lore.kernel.org/r/ZGIBSEoZ7VRVvP8H@MiWiFi-R3L-srv Signed-off-by: Catalin Marinas <[email protected]>
1 parent 44c026a commit 6c4dcad

File tree

1 file changed

+34
-10
lines changed

1 file changed

+34
-10
lines changed

arch/arm64/mm/init.c

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ phys_addr_t __ro_after_init arm64_dma_phys_limit;
6969

7070
#define CRASH_ADDR_LOW_MAX arm64_dma_phys_limit
7171
#define CRASH_ADDR_HIGH_MAX (PHYS_MASK + 1)
72+
#define CRASH_HIGH_SEARCH_BASE SZ_4G
7273

7374
#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)
7475

@@ -101,12 +102,13 @@ static int __init reserve_crashkernel_low(unsigned long long low_size)
101102
*/
102103
static void __init reserve_crashkernel(void)
103104
{
104-
unsigned long long crash_base, crash_size;
105-
unsigned long long crash_low_size = 0;
105+
unsigned long long crash_low_size = 0, search_base = 0;
106106
unsigned long long crash_max = CRASH_ADDR_LOW_MAX;
107+
unsigned long long crash_base, crash_size;
107108
char *cmdline = boot_command_line;
108-
int ret;
109109
bool fixed_base = false;
110+
bool high = false;
111+
int ret;
110112

111113
if (!IS_ENABLED(CONFIG_KEXEC_CORE))
112114
return;
@@ -129,7 +131,9 @@ static void __init reserve_crashkernel(void)
129131
else if (ret)
130132
return;
131133

134+
search_base = CRASH_HIGH_SEARCH_BASE;
132135
crash_max = CRASH_ADDR_HIGH_MAX;
136+
high = true;
133137
} else if (ret || !crash_size) {
134138
/* The specified value is invalid */
135139
return;
@@ -140,31 +144,51 @@ static void __init reserve_crashkernel(void)
140144
/* User specifies base address explicitly. */
141145
if (crash_base) {
142146
fixed_base = true;
147+
search_base = crash_base;
143148
crash_max = crash_base + crash_size;
144149
}
145150

146151
retry:
147152
crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
148-
crash_base, crash_max);
153+
search_base, crash_max);
149154
if (!crash_base) {
150155
/*
151-
* If the first attempt was for low memory, fall back to
152-
* high memory, the minimum required low memory will be
153-
* reserved later.
156+
* For crashkernel=size[KMG]@offset[KMG], print out failure
157+
* message if can't reserve the specified region.
154158
*/
155-
if (!fixed_base && (crash_max == CRASH_ADDR_LOW_MAX)) {
159+
if (fixed_base) {
160+
pr_warn("crashkernel reservation failed - memory is in use.\n");
161+
return;
162+
}
163+
164+
/*
165+
* For crashkernel=size[KMG], if the first attempt was for
166+
* low memory, fall back to high memory, the minimum required
167+
* low memory will be reserved later.
168+
*/
169+
if (!high && crash_max == CRASH_ADDR_LOW_MAX) {
156170
crash_max = CRASH_ADDR_HIGH_MAX;
171+
search_base = CRASH_ADDR_LOW_MAX;
157172
crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
158173
goto retry;
159174
}
160175

176+
/*
177+
* For crashkernel=size[KMG],high, if the first attempt was
178+
* for high memory, fall back to low memory.
179+
*/
180+
if (high && crash_max == CRASH_ADDR_HIGH_MAX) {
181+
crash_max = CRASH_ADDR_LOW_MAX;
182+
search_base = 0;
183+
goto retry;
184+
}
161185
pr_warn("cannot allocate crashkernel (size:0x%llx)\n",
162186
crash_size);
163187
return;
164188
}
165189

166-
if ((crash_base > CRASH_ADDR_LOW_MAX - crash_low_size) &&
167-
crash_low_size && reserve_crashkernel_low(crash_low_size)) {
190+
if ((crash_base >= CRASH_ADDR_LOW_MAX) && crash_low_size &&
191+
reserve_crashkernel_low(crash_low_size)) {
168192
memblock_phys_free(crash_base, crash_size);
169193
return;
170194
}

0 commit comments

Comments
 (0)