Currently, crashkernel parameter supports the below syntax to parse size based on memory range: crashkernel=<range1>:<size1>[,<range2>:<size2>,...] While such parsing is implemented for crashkernel parameter, it applies to other parameters with similar syntax. So, move this code to a more generic place for code reuse. Cc: Eric Biederman <ebiederm at xmission.com> Cc: Vivek Goyal <vgoyal at redhat.com> Cc: Rusty Russell <rusty at rustcorp.com.au> Cc: kexec at lists.infradead.org Signed-off-by: Hari Bathini <hbathini at linux.vnet.ibm.com> --- changes in v2: 1. Rebased to latest upstream. 2. Marked few more people on cc. include/linux/kernel.h | 5 +++ kernel/kexec_core.c | 63 +++----------------------------- kernel/params.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 58 deletions(-) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 94aa10f..72f55e5 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -436,6 +436,11 @@ extern char *get_options(const char *str, int nints, int *ints); extern unsigned long long memparse(const char *ptr, char **retptr); extern bool parse_option_str(const char *str, const char *option); +extern bool __init is_param_range_based(const char *cmdline); +extern unsigned long long __init parse_mem_range_size(const char *param, + char **str, + unsigned long long system_ram); + extern int core_kernel_text(unsigned long addr); extern int core_kernel_data(unsigned long addr); extern int __kernel_text_address(unsigned long addr); diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index 56b3ed0..d43f5cc 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -1083,59 +1083,9 @@ static int __init parse_crashkernel_mem(char *cmdline, char *cur = cmdline, *tmp; /* for each entry of the comma-separated list */ - do { - unsigned long long start, end = ULLONG_MAX, size; - - /* get the start of the range */ - start = memparse(cur, &tmp); - if (cur == tmp) { - pr_warn("crashkernel: Memory value expected\n"); - return -EINVAL; - } - cur = tmp; - if (*cur != '-') { - pr_warn("crashkernel: '-' expected\n"); - return -EINVAL; - } - cur++; - - /* if no ':' is here, than we read the end */ - if (*cur != ':') { - end = memparse(cur, &tmp); - if (cur == tmp) { - pr_warn("crashkernel: Memory value expected\n"); - return -EINVAL; - } - cur = tmp; - if (end <= start) { - pr_warn("crashkernel: end <= start\n"); - return -EINVAL; - } - } - - if (*cur != ':') { - pr_warn("crashkernel: ':' expected\n"); - return -EINVAL; - } - cur++; - - size = memparse(cur, &tmp); - if (cur == tmp) { - pr_warn("Memory value expected\n"); - return -EINVAL; - } - cur = tmp; - if (size >= system_ram) { - pr_warn("crashkernel: invalid size\n"); - return -EINVAL; - } - - /* match ? */ - if (system_ram >= start && system_ram < end) { - *crash_size = size; - break; - } - } while (*cur++ == ','); + *crash_size = parse_mem_range_size("crashkernel", &cur, system_ram); + if (cur == cmdline) + return -EINVAL; if (*crash_size > 0) { while (*cur && *cur != ' ' && *cur != '@') @@ -1272,7 +1222,6 @@ static int __init __parse_crashkernel(char *cmdline, const char *name, const char *suffix) { - char *first_colon, *first_space; char *ck_cmdline; BUG_ON(!crash_size || !crash_base); @@ -1290,12 +1239,10 @@ static int __init __parse_crashkernel(char *cmdline, return parse_crashkernel_suffix(ck_cmdline, crash_size, suffix); /* - * if the commandline contains a ':', then that's the extended + * if the parameter is range based, then that's the extended * syntax -- if not, it must be the classic syntax */ - first_colon = strchr(ck_cmdline, ':'); - first_space = strchr(ck_cmdline, ' '); - if (first_colon && (!first_space || first_colon < first_space)) + if (is_param_range_based(ck_cmdline)) return parse_crashkernel_mem(ck_cmdline, system_ram, crash_size, crash_base); diff --git a/kernel/params.c b/kernel/params.c index a6d6149..84e40ae 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -268,6 +268,102 @@ char *parse_args(const char *doing, return err; } +/* + * is_param_range_based - check if current parameter is range based + * @cmdline: points to the parameter to check + * + * Returns true when the current paramer is range based, false otherwise + */ +bool __init is_param_range_based(const char *cmdline) +{ + char *first_colon, *first_space; + + first_colon = strchr(cmdline, ':'); + first_space = strchr(cmdline, ' '); + if (first_colon && (!first_space || first_colon < first_space)) + return true; + + return false; +} + +/* + * parse_mem_range_size - parse size based on memory range + * @param: the thing being parsed + * @str: (input) where parse begins + * expected format - <range1>:<size1>[,<range2>:<size2>,...] + * (output) On success - next char after parse completes + * On failure - unchanged + * @system_ram: system ram size to check memory range against + * + * Returns the memory size on success and 0 on failure + */ +unsigned long long __init parse_mem_range_size(const char *param, + char **str, + unsigned long long system_ram) +{ + char *cur = *str, *tmp; + unsigned long long mem_size = 0; + + /* for each entry of the comma-separated list */ + do { + unsigned long long start, end = ULLONG_MAX, size; + + /* get the start of the range */ + start = memparse(cur, &tmp); + if (cur == tmp) { + printk(KERN_INFO "%s: Memory value expected\n", param); + return mem_size; + } + cur = tmp; + if (*cur != '-') { + printk(KERN_INFO "%s: '-' expected\n", param); + return mem_size; + } + cur++; + + /* if no ':' is here, than we read the end */ + if (*cur != ':') { + end = memparse(cur, &tmp); + if (cur == tmp) { + printk(KERN_INFO "%s: Memory value expected\n", + param); + return mem_size; + } + cur = tmp; + if (end <= start) { + printk(KERN_INFO "%s: end <= start\n", param); + return mem_size; + } + } + + if (*cur != ':') { + printk(KERN_INFO "%s: ':' expected\n", param); + return mem_size; + } + cur++; + + size = memparse(cur, &tmp); + if (cur == tmp) { + printk(KERN_INFO "%s: Memory value expected\n", param); + return mem_size; + } + cur = tmp; + if (size >= system_ram) { + printk(KERN_INFO "%s: invalid size\n", param); + return mem_size; + } + + /* match ? */ + if (system_ram >= start && system_ram < end) { + mem_size = size; + *str = cur; + break; + } + } while (*cur++ == ','); + + return mem_size; +} + /* Lazy bastard, eh? */ #define STANDARD_PARAM_DEF(name, type, format, strtolfn) \ int param_set_##name(const char *val, const struct kernel_param *kp) \