Skip to content

Commit a2e9a95

Browse files
lian-boIngo Molnar
authored andcommitted
kexec: Improve & fix crash_exclude_mem_range() to handle overlapping ranges
The crash_exclude_mem_range() function can only handle one memory region a time. It will fail in the case in which the passed in area covers several memory regions. In this case, it will only exclude the first region, then return, but leave the later regions unsolved. E.g in a NEC system with two usable RAM regions inside the low 1M: ... BIOS-e820: [mem 0x0000000000000000-0x000000000003efff] usable BIOS-e820: [mem 0x000000000003f000-0x000000000003ffff] reserved BIOS-e820: [mem 0x0000000000040000-0x000000000009ffff] usable It will only exclude the memory region [0, 0x3efff], the memory region [0x40000, 0x9ffff] will still be added into /proc/vmcore, which may cause the following failure when dumping vmcore: ioremap on RAM at 0x0000000000040000 - 0x0000000000040fff WARNING: CPU: 0 PID: 665 at arch/x86/mm/ioremap.c:186 __ioremap_caller+0x2c7/0x2e0 ... RIP: 0010:__ioremap_caller+0x2c7/0x2e0 ... cp: error reading '/proc/vmcore': Cannot allocate memory kdump: saving vmcore failed In order to fix this bug, let's extend the crash_exclude_mem_range() to handle the overlapping ranges. [ mingo: Amended the changelog. ] Signed-off-by: Lianbo Jiang <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Acked-by: Dave Young <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent a3e1c3b commit a2e9a95

File tree

1 file changed

+23
-12
lines changed

1 file changed

+23
-12
lines changed

kernel/kexec_file.c

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,24 +1157,26 @@ int crash_exclude_mem_range(struct crash_mem *mem,
11571157
unsigned long long mstart, unsigned long long mend)
11581158
{
11591159
int i, j;
1160-
unsigned long long start, end;
1160+
unsigned long long start, end, p_start, p_end;
11611161
struct crash_mem_range temp_range = {0, 0};
11621162

11631163
for (i = 0; i < mem->nr_ranges; i++) {
11641164
start = mem->ranges[i].start;
11651165
end = mem->ranges[i].end;
1166+
p_start = mstart;
1167+
p_end = mend;
11661168

11671169
if (mstart > end || mend < start)
11681170
continue;
11691171

11701172
/* Truncate any area outside of range */
11711173
if (mstart < start)
1172-
mstart = start;
1174+
p_start = start;
11731175
if (mend > end)
1174-
mend = end;
1176+
p_end = end;
11751177

11761178
/* Found completely overlapping range */
1177-
if (mstart == start && mend == end) {
1179+
if (p_start == start && p_end == end) {
11781180
mem->ranges[i].start = 0;
11791181
mem->ranges[i].end = 0;
11801182
if (i < mem->nr_ranges - 1) {
@@ -1185,20 +1187,29 @@ int crash_exclude_mem_range(struct crash_mem *mem,
11851187
mem->ranges[j].end =
11861188
mem->ranges[j+1].end;
11871189
}
1190+
1191+
/*
1192+
* Continue to check if there are another overlapping ranges
1193+
* from the current position because of shifting the above
1194+
* mem ranges.
1195+
*/
1196+
i--;
1197+
mem->nr_ranges--;
1198+
continue;
11881199
}
11891200
mem->nr_ranges--;
11901201
return 0;
11911202
}
11921203

1193-
if (mstart > start && mend < end) {
1204+
if (p_start > start && p_end < end) {
11941205
/* Split original range */
1195-
mem->ranges[i].end = mstart - 1;
1196-
temp_range.start = mend + 1;
1206+
mem->ranges[i].end = p_start - 1;
1207+
temp_range.start = p_end + 1;
11971208
temp_range.end = end;
1198-
} else if (mstart != start)
1199-
mem->ranges[i].end = mstart - 1;
1209+
} else if (p_start != start)
1210+
mem->ranges[i].end = p_start - 1;
12001211
else
1201-
mem->ranges[i].start = mend + 1;
1212+
mem->ranges[i].start = p_end + 1;
12021213
break;
12031214
}
12041215

@@ -1243,7 +1254,7 @@ int crash_prepare_elf64_headers(struct crash_mem *mem, int kernel_map,
12431254
* kexec-tools creates an extra PT_LOAD phdr for kernel text mapping
12441255
* area (for example, ffffffff80000000 - ffffffffa0000000 on x86_64).
12451256
* I think this is required by tools like gdb. So same physical
1246-
* memory will be mapped in two elf headers. One will contain kernel
1257+
* memory will be mapped in two elf headers. One will contain kernel
12471258
* text virtual addresses and other will have __va(physical) addresses.
12481259
*/
12491260

@@ -1270,7 +1281,7 @@ int crash_prepare_elf64_headers(struct crash_mem *mem, int kernel_map,
12701281
ehdr->e_ehsize = sizeof(Elf64_Ehdr);
12711282
ehdr->e_phentsize = sizeof(Elf64_Phdr);
12721283

1273-
/* Prepare one phdr of type PT_NOTE for each present cpu */
1284+
/* Prepare one phdr of type PT_NOTE for each present CPU */
12741285
for_each_present_cpu(cpu) {
12751286
phdr->p_type = PT_NOTE;
12761287
notes_addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpu));

0 commit comments

Comments
 (0)