diff options
author | Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> | 2013-02-12 16:17:16 +0530 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2013-03-05 11:11:03 +0900 |
commit | a69f5b5a432fc0abf6655a8b0bc667a900511f7d (patch) | |
tree | 11c38e63a4f5dcfb40afbd98aaa7a2dfbc41d2cb | |
parent | e35aa29fb40b37bf86d980b2e19af5e01c2d2549 (diff) | |
download | kexec-tools-a69f5b5a432fc0abf6655a8b0bc667a900511f7d.tar.gz |
kexec: Respect memory limit while building crash memory ranges on ppc32.
So far powerpc kernel never exported memory limit information which is
reflected by mem= kernel cmdline option. Hence, kexec-tools always used
to build ELF header for entire system RAM generating a dump bigger than
the actual memory used by the first kernel.
This patch now reads the memory limit information from device-tree file and
limits the crash memory ranges accordingly.
Suzuki tested this patch on ppc32(ppc440) with a kernel patch by Suzuki.
The following are the upstream kernel commits that exports memory limit
information through /proc/device-tree file:
4bc77a5ed - powerpc: Export memory limit via device tree
a84fcd468 - powerpc: Change memory_limit from phys_addr_t to unsigned
long long
Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Tested-by: Suzuki K. Poulose <suzuki@in.ibm.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
-rw-r--r-- | kexec/arch/ppc/crashdump-powerpc.c | 14 | ||||
-rw-r--r-- | kexec/arch/ppc/crashdump-powerpc.h | 1 | ||||
-rw-r--r-- | kexec/arch/ppc/kexec-ppc.c | 51 |
3 files changed, 63 insertions, 3 deletions
diff --git a/kexec/arch/ppc/crashdump-powerpc.c b/kexec/arch/ppc/crashdump-powerpc.c index 4c8c75d7..d367643f 100644 --- a/kexec/arch/ppc/crashdump-powerpc.c +++ b/kexec/arch/ppc/crashdump-powerpc.c @@ -132,8 +132,9 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges) goto err; } n = read_memory_region_limits(fd, &start, &end); + /* We are done with fd, close it. */ + close(fd); if (n != 0) { - close(fd); closedir(dmem); closedir(dir); goto err; @@ -153,8 +154,16 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges) cstart = crash_base; cend = crash_base + crash_size; /* - * Exclude the region that lies within crashkernel + * Exclude the region that lies within crashkernel. + * If memory limit is set then exclude memory region + * above it. */ + if (memory_limit) { + if (start >= memory_limit) + continue; + if (end > memory_limit) + end = memory_limit; + } if (cstart < end && cend > start) { if (start < cstart && end > cend) { crash_memory_range[memory_ranges].start @@ -195,7 +204,6 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges) = RANGE_RAM; memory_ranges++; } - close(fd); } closedir(dmem); } diff --git a/kexec/arch/ppc/crashdump-powerpc.h b/kexec/arch/ppc/crashdump-powerpc.h index a3771465..84a73aac 100644 --- a/kexec/arch/ppc/crashdump-powerpc.h +++ b/kexec/arch/ppc/crashdump-powerpc.h @@ -42,5 +42,6 @@ extern unsigned long long crash_base; extern unsigned long long crash_size; extern unsigned int rtas_base; extern unsigned int rtas_size; +extern uint64_t memory_limit; #endif /* CRASHDUMP_POWERPC_H */ diff --git a/kexec/arch/ppc/kexec-ppc.c b/kexec/arch/ppc/kexec-ppc.c index 6075477b..5a2966e2 100644 --- a/kexec/arch/ppc/kexec-ppc.c +++ b/kexec/arch/ppc/kexec-ppc.c @@ -29,6 +29,7 @@ unsigned long dt_address_cells = 0, dt_size_cells = 0; uint64_t rmo_top; +uint64_t memory_limit; unsigned long long crash_base = 0, crash_size = 0; unsigned long long initrd_base = 0, initrd_size = 0; unsigned long long ramdisk_base = 0, ramdisk_size = 0; @@ -384,6 +385,44 @@ static int get_base_ranges(void) return 0; } +static int read_kernel_memory_limit(char *fname, char *buf) +{ + FILE *file; + int n; + + if (!fname || !buf) + return -1; + + file = fopen(fname, "r"); + if (file == NULL) { + if (errno != ENOENT) { + perror(fname); + return -1; + } + errno = 0; + /* + * fall through. On older kernel this file + * is not present. Hence return success. + */ + } else { + /* Memory limit property is of u64 type. */ + if ((n = fread(&memory_limit, 1, sizeof(uint64_t), file)) < 0) { + perror(fname); + goto err_out; + } + if (n != sizeof(uint64_t)) { + fprintf(stderr, "%s node has invalid size: %d\n", + fname, n); + goto err_out; + } + fclose(file); + } + return 0; +err_out: + fclose(file); + return -1; +} + /* Get devtree details and create exclude_range array * Also create usablemem_ranges for KEXEC_ON_CRASH */ @@ -511,6 +550,18 @@ static int get_devtree_details(unsigned long kexec_flags) add_usable_mem_rgns(crash_base, crash_size); #endif } + /* + * Read the first kernel's memory limit. + * If the first kernel is booted with mem= option then + * it would export "linux,memory-limit" file + * reflecting value for the same. + */ + memset(fname, 0, sizeof(fname)); + snprintf(fname, sizeof(fname), "%s%s%s", device_tree, + dentry->d_name, "/linux,memory-limit"); + if (read_kernel_memory_limit(fname, buf) < 0) + goto error_opencdir; + /* reserve the initrd_start and end locations. */ memset(fname, 0, sizeof(fname)); sprintf(fname, "%s%s%s", |