Skip to content

Commit

Permalink
kexec: premit reduction of the reserved memory size
Browse files Browse the repository at this point in the history
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 <amwang@redhat.com>
Cc: Neil Horman <nhorman@redhat.com>
Acked-by: Eric W. Biederman <ebiederm@xmission.com>
Cc: Andi Kleen <andi@firstfloor.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Amerigo Wang authored and torvalds committed Dec 16, 2009
1 parent 1f2c19f commit 06a7f71
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/linux/kexec.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
59 changes: 59 additions & 0 deletions kernel/kexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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)
{
Expand Down
21 changes: 21 additions & 0 deletions kernel/ksysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 06a7f71

Please sign in to comment.