kexec: premit reduction of the reserved memory size

Implement shrinking the reserved memory for crash kernel, if it is more
than enough.

For example, if you have already reserved 128M, now you just want 100M,
you can do:

# echo $((100*1024*1024)) > /sys/kernel/kexec_crash_size

Note, you can only do this before loading the crash kernel.

Signed-off-by: WANG Cong <[email protected]>
Cc: Neil Horman <[email protected]>
Acked-by: Eric W. Biederman <[email protected]>
Cc: Andi Kleen <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
Amerigo Wang 2009-12-15 16:47:46 -08:00 • committed by Linus Torvalds
commit 06a7f71124
3 changed files with 82 additions and 0 deletions

View file

@ -31,6 +31,7 @@
#include <linux/cpu.h>
#include <linux/console.h>
#include <linux/vmalloc.h>
#include <linux/swap.h>
#include <asm/page.h>
#include <asm/uaccess.h>
@ -1082,6 +1083,64 @@ void crash_kexec(struct pt_regs *regs)
}
}
size_t crash_get_memory_size(void)
{
size_t size;
mutex_lock(&kexec_mutex);
size = crashk_res.end - crashk_res.start + 1;
mutex_unlock(&kexec_mutex);
return size;
}
static void free_reserved_phys_range(unsigned long begin, unsigned long end)
{
unsigned long addr;
for (addr = begin; addr < end; addr += PAGE_SIZE) {
ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT));
init_page_count(pfn_to_page(addr >> PAGE_SHIFT));
free_page((unsigned long)__va(addr));
totalram_pages++;
}
}
int crash_shrink_memory(unsigned long new_size)
{
int ret = 0;
unsigned long start, end;
mutex_lock(&kexec_mutex);
if (kexec_crash_image) {
ret = -ENOENT;
goto unlock;
}
start = crashk_res.start;
end = crashk_res.end;
if (new_size >= end - start + 1) {
ret = -EINVAL;
if (new_size == end - start + 1)
ret = 0;
goto unlock;
}
start = roundup(start, PAGE_SIZE);
end = roundup(start + new_size, PAGE_SIZE);
free_reserved_phys_range(end, crashk_res.end);
if (start == end) {
crashk_res.end = end;
release_resource(&crashk_res);
} else
crashk_res.end = end - 1;
unlock:
mutex_unlock(&kexec_mutex);
return ret;
}
static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
size_t data_len)
{