Commit 06a7f711 authored by Amerigo Wang's avatar Amerigo Wang Committed by Linus Torvalds

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: default avatarWANG Cong <amwang@redhat.com>
Cc: Neil Horman <nhorman@redhat.com>
Acked-by: default avatarEric W. Biederman <ebiederm@xmission.com>
Cc: Andi Kleen <andi@firstfloor.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 1f2c19f8
......@@ -206,6 +206,8 @@ extern size_t vmcoreinfo_max_size;
int __init parse_crashkernel(char *cmdline, unsigned long long system_ram,
unsigned long long *crash_size, unsigned long long *crash_base);
int crash_shrink_memory(unsigned long new_size);
size_t crash_get_memory_size(void);
#else /* !CONFIG_KEXEC */
struct pt_regs;
......
......@@ -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)
{
......
......@@ -100,6 +100,26 @@ static ssize_t kexec_crash_loaded_show(struct kobject *kobj,
}
KERNEL_ATTR_RO(kexec_crash_loaded);
static ssize_t kexec_crash_size_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%zu\n", crash_get_memory_size());
}
static ssize_t kexec_crash_size_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
unsigned long cnt;
int ret;
if (strict_strtoul(buf, 0, &cnt))
return -EINVAL;
ret = crash_shrink_memory(cnt);
return ret < 0 ? ret : count;
}
KERNEL_ATTR_RW(kexec_crash_size);
static ssize_t vmcoreinfo_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
......@@ -147,6 +167,7 @@ static struct attribute * kernel_attrs[] = {
#ifdef CONFIG_KEXEC
&kexec_loaded_attr.attr,
&kexec_crash_loaded_attr.attr,
&kexec_crash_size_attr.attr,
&vmcoreinfo_attr.attr,
#endif
NULL
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment