Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

params: <level>_initcall-like kernel parameters

This patch adds a set of macros that can be used to declare
kernel parameters to be parsed _before_ initcalls at a chosen
level are executed. We rename the now-unused "flags" field of
struct kernel_param as the level. It's signed, for when we
use this for early params as well, in future.

Linker macro collating init calls had to be modified in order
to add additional symbols between levels that are later used
by the init code to split the calls into blocks.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

authored by

Pawel Moll and committed by
Rusty Russell
026cee00 8b825281

+133 -42
+2 -1
arch/powerpc/mm/hugetlbpage.c
··· 310 310 int i; 311 311 312 312 strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE); 313 - parse_args("hugetlb gpages", cmdline, NULL, 0, &do_gpage_early_setup); 313 + parse_args("hugetlb gpages", cmdline, NULL, 0, 0, 0, 314 + &do_gpage_early_setup); 314 315 315 316 /* 316 317 * Walk gpage list in reverse, allocating larger page sizes first.
+14 -21
include/asm-generic/vmlinux.lds.h
··· 616 616 *(.init.setup) \ 617 617 VMLINUX_SYMBOL(__setup_end) = .; 618 618 619 - #define INITCALLS \ 620 - *(.initcallearly.init) \ 621 - VMLINUX_SYMBOL(__early_initcall_end) = .; \ 622 - *(.initcall0.init) \ 623 - *(.initcall0s.init) \ 624 - *(.initcall1.init) \ 625 - *(.initcall1s.init) \ 626 - *(.initcall2.init) \ 627 - *(.initcall2s.init) \ 628 - *(.initcall3.init) \ 629 - *(.initcall3s.init) \ 630 - *(.initcall4.init) \ 631 - *(.initcall4s.init) \ 632 - *(.initcall5.init) \ 633 - *(.initcall5s.init) \ 634 - *(.initcallrootfs.init) \ 635 - *(.initcall6.init) \ 636 - *(.initcall6s.init) \ 637 - *(.initcall7.init) \ 638 - *(.initcall7s.init) 619 + #define INIT_CALLS_LEVEL(level) \ 620 + VMLINUX_SYMBOL(__initcall##level##_start) = .; \ 621 + *(.initcall##level##.init) \ 622 + *(.initcall##level##s.init) \ 639 623 640 624 #define INIT_CALLS \ 641 625 VMLINUX_SYMBOL(__initcall_start) = .; \ 642 - INITCALLS \ 626 + *(.initcallearly.init) \ 627 + INIT_CALLS_LEVEL(0) \ 628 + INIT_CALLS_LEVEL(1) \ 629 + INIT_CALLS_LEVEL(2) \ 630 + INIT_CALLS_LEVEL(3) \ 631 + INIT_CALLS_LEVEL(4) \ 632 + INIT_CALLS_LEVEL(5) \ 633 + INIT_CALLS_LEVEL(rootfs) \ 634 + INIT_CALLS_LEVEL(6) \ 635 + INIT_CALLS_LEVEL(7) \ 643 636 VMLINUX_SYMBOL(__initcall_end) = .; 644 637 645 638 #define CON_INITCALL \
+43 -8
include/linux/moduleparam.h
··· 51 51 const char *name; 52 52 const struct kernel_param_ops *ops; 53 53 u16 perm; 54 - u16 flags; 54 + s16 level; 55 55 union { 56 56 void *arg; 57 57 const struct kparam_string *str; ··· 128 128 * The ops can have NULL set or get functions. 129 129 */ 130 130 #define module_param_cb(name, ops, arg, perm) \ 131 - __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm) 131 + __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, 0) 132 + 133 + /** 134 + * <level>_param_cb - general callback for a module/cmdline parameter 135 + * to be evaluated before certain initcall level 136 + * @name: a valid C identifier which is the parameter name. 137 + * @ops: the set & get operations for this parameter. 138 + * @perm: visibility in sysfs. 139 + * 140 + * The ops can have NULL set or get functions. 141 + */ 142 + #define __level_param_cb(name, ops, arg, perm, level) \ 143 + __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, level) 144 + 145 + #define core_param_cb(name, ops, arg, perm) \ 146 + __level_param_cb(name, ops, arg, perm, 1) 147 + 148 + #define postcore_param_cb(name, ops, arg, perm) \ 149 + __level_param_cb(name, ops, arg, perm, 2) 150 + 151 + #define arch_param_cb(name, ops, arg, perm) \ 152 + __level_param_cb(name, ops, arg, perm, 3) 153 + 154 + #define subsys_param_cb(name, ops, arg, perm) \ 155 + __level_param_cb(name, ops, arg, perm, 4) 156 + 157 + #define fs_param_cb(name, ops, arg, perm) \ 158 + __level_param_cb(name, ops, arg, perm, 5) 159 + 160 + #define device_param_cb(name, ops, arg, perm) \ 161 + __level_param_cb(name, ops, arg, perm, 6) 162 + 163 + #define late_param_cb(name, ops, arg, perm) \ 164 + __level_param_cb(name, ops, arg, perm, 7) 132 165 133 166 /* On alpha, ia64 and ppc64 relocations to global data cannot go into 134 167 read-only sections (which is part of respective UNIX ABI on these ··· 175 142 176 143 /* This is the fundamental function for registering boot/module 177 144 parameters. */ 178 - #define __module_param_call(prefix, name, ops, arg, perm) \ 145 + #define __module_param_call(prefix, name, ops, arg, perm, level) \ 179 146 /* Default value instead of permissions? */ \ 180 147 static int __param_perm_check_##name __attribute__((unused)) = \ 181 148 BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)) \ ··· 184 151 static struct kernel_param __moduleparam_const __param_##name \ 185 152 __used \ 186 153 __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ 187 - = { __param_str_##name, ops, perm, 0, { arg } } 154 + = { __param_str_##name, ops, perm, level, { arg } } 188 155 189 156 /* Obsolete - use module_param_cb() */ 190 157 #define module_param_call(name, set, get, arg, perm) \ ··· 192 159 { (void *)set, (void *)get }; \ 193 160 __module_param_call(MODULE_PARAM_PREFIX, \ 194 161 name, &__param_ops_##name, arg, \ 195 - (perm) + sizeof(__check_old_set_param(set))*0) 162 + (perm) + sizeof(__check_old_set_param(set))*0, 0) 196 163 197 164 /* We don't get oldget: it's often a new-style param_get_uint, etc. */ 198 165 static inline int ··· 272 239 */ 273 240 #define core_param(name, var, type, perm) \ 274 241 param_check_##type(name, &(var)); \ 275 - __module_param_call("", name, &param_ops_##type, &var, perm) 242 + __module_param_call("", name, &param_ops_##type, &var, perm, 0) 276 243 #endif /* !MODULE */ 277 244 278 245 /** ··· 290 257 = { len, string }; \ 291 258 __module_param_call(MODULE_PARAM_PREFIX, name, \ 292 259 &param_ops_string, \ 293 - .str = &__param_string_##name, perm); \ 260 + .str = &__param_string_##name, perm, 0); \ 294 261 __MODULE_PARM_TYPE(name, "string") 295 262 296 263 /** ··· 318 285 char *args, 319 286 const struct kernel_param *params, 320 287 unsigned num, 288 + s16 level_min, 289 + s16 level_max, 321 290 int (*unknown)(char *param, char *val)); 322 291 323 292 /* Called by module remove. */ ··· 431 396 __module_param_call(MODULE_PARAM_PREFIX, name, \ 432 397 &param_array_ops, \ 433 398 .arr = &__param_arr_##name, \ 434 - perm); \ 399 + perm, 0); \ 435 400 __MODULE_PARM_TYPE(name, "array of " #type) 436 401 437 402 extern struct kernel_param_ops param_array_ops;
+60 -7
init/main.c
··· 400 400 401 401 void __init parse_early_options(char *cmdline) 402 402 { 403 - parse_args("early options", cmdline, NULL, 0, do_early_param); 403 + parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param); 404 404 } 405 405 406 406 /* Arch code calls this early on, or if not, just before other parsing. */ ··· 503 503 parse_early_param(); 504 504 parse_args("Booting kernel", static_command_line, __start___param, 505 505 __stop___param - __start___param, 506 - &unknown_bootoption); 506 + 0, 0, &unknown_bootoption); 507 507 508 508 jump_label_init(); 509 509 ··· 699 699 } 700 700 701 701 702 - extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[]; 702 + extern initcall_t __initcall_start[]; 703 + extern initcall_t __initcall0_start[]; 704 + extern initcall_t __initcall1_start[]; 705 + extern initcall_t __initcall2_start[]; 706 + extern initcall_t __initcall3_start[]; 707 + extern initcall_t __initcall4_start[]; 708 + extern initcall_t __initcall5_start[]; 709 + extern initcall_t __initcall6_start[]; 710 + extern initcall_t __initcall7_start[]; 711 + extern initcall_t __initcall_end[]; 712 + 713 + static initcall_t *initcall_levels[] __initdata = { 714 + __initcall0_start, 715 + __initcall1_start, 716 + __initcall2_start, 717 + __initcall3_start, 718 + __initcall4_start, 719 + __initcall5_start, 720 + __initcall6_start, 721 + __initcall7_start, 722 + __initcall_end, 723 + }; 724 + 725 + static char *initcall_level_names[] __initdata = { 726 + "early parameters", 727 + "core parameters", 728 + "postcore parameters", 729 + "arch parameters", 730 + "subsys parameters", 731 + "fs parameters", 732 + "device parameters", 733 + "late parameters", 734 + }; 735 + 736 + static int __init ignore_unknown_bootoption(char *param, char *val) 737 + { 738 + return 0; 739 + } 740 + 741 + static void __init do_initcall_level(int level) 742 + { 743 + extern const struct kernel_param __start___param[], __stop___param[]; 744 + initcall_t *fn; 745 + 746 + strcpy(static_command_line, saved_command_line); 747 + parse_args(initcall_level_names[level], 748 + static_command_line, __start___param, 749 + __stop___param - __start___param, 750 + level, level, 751 + ignore_unknown_bootoption); 752 + 753 + for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++) 754 + do_one_initcall(*fn); 755 + } 703 756 704 757 static void __init do_initcalls(void) 705 758 { 706 - initcall_t *fn; 759 + int level; 707 760 708 - for (fn = __early_initcall_end; fn < __initcall_end; fn++) 709 - do_one_initcall(*fn); 761 + for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) 762 + do_initcall_level(level); 710 763 } 711 764 712 765 /* ··· 785 732 { 786 733 initcall_t *fn; 787 734 788 - for (fn = __initcall_start; fn < __early_initcall_end; fn++) 735 + for (fn = __initcall_start; fn < __initcall0_start; fn++) 789 736 do_one_initcall(*fn); 790 737 } 791 738
+2 -1
kernel/module.c
··· 2923 2923 mutex_unlock(&module_mutex); 2924 2924 2925 2925 /* Module is ready to execute: parsing args may do that. */ 2926 - err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL); 2926 + err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, 2927 + -32768, 32767, NULL); 2927 2928 if (err < 0) 2928 2929 goto unlink; 2929 2930
+12 -4
kernel/params.c
··· 87 87 char *val, 88 88 const struct kernel_param *params, 89 89 unsigned num_params, 90 + s16 min_level, 91 + s16 max_level, 90 92 int (*handle_unknown)(char *param, char *val)) 91 93 { 92 94 unsigned int i; ··· 97 95 /* Find parameter */ 98 96 for (i = 0; i < num_params; i++) { 99 97 if (parameq(param, params[i].name)) { 98 + if (params[i].level < min_level 99 + || params[i].level > max_level) 100 + return 0; 100 101 /* No one handled NULL, so do it here. */ 101 102 if (!val && params[i].ops->set != param_set_bool 102 103 && params[i].ops->set != param_set_bint) ··· 179 174 char *args, 180 175 const struct kernel_param *params, 181 176 unsigned num, 177 + s16 min_level, 178 + s16 max_level, 182 179 int (*unknown)(char *param, char *val)) 183 180 { 184 181 char *param, *val; ··· 196 189 197 190 args = next_arg(args, &param, &val); 198 191 irq_was_disabled = irqs_disabled(); 199 - ret = parse_one(param, val, params, num, unknown); 192 + ret = parse_one(param, val, params, num, 193 + min_level, max_level, unknown); 200 194 if (irq_was_disabled && !irqs_disabled()) { 201 195 printk(KERN_WARNING "parse_args(): option '%s' enabled " 202 196 "irq's!\n", param); ··· 382 374 unsigned int min, unsigned int max, 383 375 void *elem, int elemsize, 384 376 int (*set)(const char *, const struct kernel_param *kp), 385 - u16 flags, 377 + s16 level, 386 378 unsigned int *num) 387 379 { 388 380 int ret; ··· 392 384 /* Get the name right for errors. */ 393 385 kp.name = name; 394 386 kp.arg = elem; 395 - kp.flags = flags; 387 + kp.level = level; 396 388 397 389 *num = 0; 398 390 /* We expect a comma-separated list of values. */ ··· 433 425 unsigned int temp_num; 434 426 435 427 return param_array(kp->name, val, 1, arr->max, arr->elem, 436 - arr->elemsize, arr->ops->set, kp->flags, 428 + arr->elemsize, arr->ops->set, kp->level, 437 429 arr->num ?: &temp_num); 438 430 } 439 431