powerpc/fadump: add reschedule point while releasing memory
Around 95% of memory is reserved by fadump/capture kernel. All this memory is freed, one page at a time, on writing '1' to the node /sys/kernel/fadump_release_mem. On systems with large memory, this can take a long time to complete, leading to soft lockup warning messages. To avoid this, add reschedule points at regular intervals. Also, while memblock_reserve() implicitly takes care of holes in the given memory range while reserving memory, those holes need to be taken care of while releasing memory as memory is freed one page at a time. Add support to skip holes while releasing memory. Suggested-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
a5a05b91c7
commit
68fa6478e3
|
@ -1152,28 +1152,71 @@ void fadump_cleanup(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void fadump_free_reserved_memory(unsigned long start_pfn,
|
||||
unsigned long end_pfn)
|
||||
{
|
||||
unsigned long pfn;
|
||||
unsigned long time_limit = jiffies + HZ;
|
||||
|
||||
pr_info("freeing reserved memory (0x%llx - 0x%llx)\n",
|
||||
PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
|
||||
|
||||
for (pfn = start_pfn; pfn < end_pfn; pfn++) {
|
||||
free_reserved_page(pfn_to_page(pfn));
|
||||
|
||||
if (time_after(jiffies, time_limit)) {
|
||||
cond_resched();
|
||||
time_limit = jiffies + HZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip memory holes and free memory that was actually reserved.
|
||||
*/
|
||||
static void fadump_release_reserved_area(unsigned long start, unsigned long end)
|
||||
{
|
||||
struct memblock_region *reg;
|
||||
unsigned long tstart, tend;
|
||||
unsigned long start_pfn = PHYS_PFN(start);
|
||||
unsigned long end_pfn = PHYS_PFN(end);
|
||||
|
||||
for_each_memblock(memory, reg) {
|
||||
tstart = max(start_pfn, memblock_region_memory_base_pfn(reg));
|
||||
tend = min(end_pfn, memblock_region_memory_end_pfn(reg));
|
||||
if (tstart < tend) {
|
||||
fadump_free_reserved_memory(tstart, tend);
|
||||
|
||||
if (tend == end_pfn)
|
||||
break;
|
||||
|
||||
start_pfn = tend + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Release the memory that was reserved in early boot to preserve the memory
|
||||
* contents. The released memory will be available for general use.
|
||||
*/
|
||||
static void fadump_release_memory(unsigned long begin, unsigned long end)
|
||||
{
|
||||
unsigned long addr;
|
||||
unsigned long ra_start, ra_end;
|
||||
|
||||
ra_start = fw_dump.reserve_dump_area_start;
|
||||
ra_end = ra_start + fw_dump.reserve_dump_area_size;
|
||||
|
||||
for (addr = begin; addr < end; addr += PAGE_SIZE) {
|
||||
/*
|
||||
* exclude the dump reserve area. Will reuse it for next
|
||||
* fadump registration.
|
||||
*/
|
||||
if (addr <= ra_end && ((addr + PAGE_SIZE) > ra_start))
|
||||
continue;
|
||||
|
||||
free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT));
|
||||
}
|
||||
if (begin < ra_end && end > ra_start) {
|
||||
if (begin < ra_start)
|
||||
fadump_release_reserved_area(begin, ra_start);
|
||||
if (end > ra_end)
|
||||
fadump_release_reserved_area(ra_end, end);
|
||||
} else
|
||||
fadump_release_reserved_area(begin, end);
|
||||
}
|
||||
|
||||
static void fadump_invalidate_release_mem(void)
|
||||
|
|
Loading…
Reference in New Issue