aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPawel Moll <pawel.moll@arm.com>2012-03-25 22:20:51 -0400
committerRusty Russell <rusty@rustcorp.com.au>2012-03-25 22:20:51 -0400
commit026cee0086fe1df4cf74691cf273062cc769617d (patch)
tree22735ecd2132de4570fbad81e5716f7fee3448d5
parent8b8252813dee8e8cd453bb219731c36b268c69a7 (diff)
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>
-rw-r--r--arch/powerpc/mm/hugetlbpage.c3
-rw-r--r--include/asm-generic/vmlinux.lds.h35
-rw-r--r--include/linux/moduleparam.h51
-rw-r--r--init/main.c65
-rw-r--r--kernel/module.c3
-rw-r--r--kernel/params.c16
6 files changed, 132 insertions, 41 deletions
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 57c7465e656e..a3e628727697 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -310,7 +310,8 @@ void __init reserve_hugetlb_gpages(void)
310 int i; 310 int i;
311 311
312 strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE); 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 * Walk gpage list in reverse, allocating larger page sizes first. 317 * Walk gpage list in reverse, allocating larger page sizes first.
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 798603e8ec38..8aeadf6b553a 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -616,30 +616,23 @@
616 *(.init.setup) \ 616 *(.init.setup) \
617 VMLINUX_SYMBOL(__setup_end) = .; 617 VMLINUX_SYMBOL(__setup_end) = .;
618 618
619#define INITCALLS \ 619#define INIT_CALLS_LEVEL(level) \
620 *(.initcallearly.init) \ 620 VMLINUX_SYMBOL(__initcall##level##_start) = .; \
621 VMLINUX_SYMBOL(__early_initcall_end) = .; \ 621 *(.initcall##level##.init) \
622 *(.initcall0.init) \ 622 *(.initcall##level##s.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)
639 623
640#define INIT_CALLS \ 624#define INIT_CALLS \
641 VMLINUX_SYMBOL(__initcall_start) = .; \ 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 VMLINUX_SYMBOL(__initcall_end) = .; 636 VMLINUX_SYMBOL(__initcall_end) = .;
644 637
645#define CON_INITCALL \ 638#define CON_INITCALL \
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index 4daa895648d9..ea36486378d8 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -51,7 +51,7 @@ struct kernel_param {
51 const char *name; 51 const char *name;
52 const struct kernel_param_ops *ops; 52 const struct kernel_param_ops *ops;
53 u16 perm; 53 u16 perm;
54 u16 flags; 54 s16 level;
55 union { 55 union {
56 void *arg; 56 void *arg;
57 const struct kparam_string *str; 57 const struct kparam_string *str;
@@ -128,7 +128,40 @@ struct kparam_array
128 * The ops can have NULL set or get functions. 128 * The ops can have NULL set or get functions.
129 */ 129 */
130#define module_param_cb(name, ops, arg, perm) \ 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/* On alpha, ia64 and ppc64 relocations to global data cannot go into 166/* On alpha, ia64 and ppc64 relocations to global data cannot go into
134 read-only sections (which is part of respective UNIX ABI on these 167 read-only sections (which is part of respective UNIX ABI on these
@@ -142,7 +175,7 @@ struct kparam_array
142 175
143/* This is the fundamental function for registering boot/module 176/* This is the fundamental function for registering boot/module
144 parameters. */ 177 parameters. */
145#define __module_param_call(prefix, name, ops, arg, perm) \ 178#define __module_param_call(prefix, name, ops, arg, perm, level) \
146 /* Default value instead of permissions? */ \ 179 /* Default value instead of permissions? */ \
147 static int __param_perm_check_##name __attribute__((unused)) = \ 180 static int __param_perm_check_##name __attribute__((unused)) = \
148 BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)) \ 181 BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)) \
@@ -151,7 +184,7 @@ struct kparam_array
151 static struct kernel_param __moduleparam_const __param_##name \ 184 static struct kernel_param __moduleparam_const __param_##name \
152 __used \ 185 __used \
153 __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ 186 __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
154 = { __param_str_##name, ops, perm, 0, { arg } } 187 = { __param_str_##name, ops, perm, level, { arg } }
155 188
156/* Obsolete - use module_param_cb() */ 189/* Obsolete - use module_param_cb() */
157#define module_param_call(name, set, get, arg, perm) \ 190#define module_param_call(name, set, get, arg, perm) \
@@ -159,7 +192,7 @@ struct kparam_array
159 { (void *)set, (void *)get }; \ 192 { (void *)set, (void *)get }; \
160 __module_param_call(MODULE_PARAM_PREFIX, \ 193 __module_param_call(MODULE_PARAM_PREFIX, \
161 name, &__param_ops_##name, arg, \ 194 name, &__param_ops_##name, arg, \
162 (perm) + sizeof(__check_old_set_param(set))*0) 195 (perm) + sizeof(__check_old_set_param(set))*0, 0)
163 196
164/* We don't get oldget: it's often a new-style param_get_uint, etc. */ 197/* We don't get oldget: it's often a new-style param_get_uint, etc. */
165static inline int 198static inline int
@@ -239,7 +272,7 @@ static inline void __kernel_param_unlock(void)
239 */ 272 */
240#define core_param(name, var, type, perm) \ 273#define core_param(name, var, type, perm) \
241 param_check_##type(name, &(var)); \ 274 param_check_##type(name, &(var)); \
242 __module_param_call("", name, &param_ops_##type, &var, perm) 275 __module_param_call("", name, &param_ops_##type, &var, perm, 0)
243#endif /* !MODULE */ 276#endif /* !MODULE */
244 277
245/** 278/**
@@ -257,7 +290,7 @@ static inline void __kernel_param_unlock(void)
257 = { len, string }; \ 290 = { len, string }; \
258 __module_param_call(MODULE_PARAM_PREFIX, name, \ 291 __module_param_call(MODULE_PARAM_PREFIX, name, \
259 &param_ops_string, \ 292 &param_ops_string, \
260 .str = &__param_string_##name, perm); \ 293 .str = &__param_string_##name, perm, 0); \
261 __MODULE_PARM_TYPE(name, "string") 294 __MODULE_PARM_TYPE(name, "string")
262 295
263/** 296/**
@@ -285,6 +318,8 @@ extern int parse_args(const char *name,
285 char *args, 318 char *args,
286 const struct kernel_param *params, 319 const struct kernel_param *params,
287 unsigned num, 320 unsigned num,
321 s16 level_min,
322 s16 level_max,
288 int (*unknown)(char *param, char *val)); 323 int (*unknown)(char *param, char *val));
289 324
290/* Called by module remove. */ 325/* Called by module remove. */
@@ -396,7 +431,7 @@ extern int param_set_bint(const char *val, const struct kernel_param *kp);
396 __module_param_call(MODULE_PARAM_PREFIX, name, \ 431 __module_param_call(MODULE_PARAM_PREFIX, name, \
397 &param_array_ops, \ 432 &param_array_ops, \
398 .arr = &__param_arr_##name, \ 433 .arr = &__param_arr_##name, \
399 perm); \ 434 perm, 0); \
400 __MODULE_PARM_TYPE(name, "array of " #type) 435 __MODULE_PARM_TYPE(name, "array of " #type)
401 436
402extern struct kernel_param_ops param_array_ops; 437extern struct kernel_param_ops param_array_ops;
diff --git a/init/main.c b/init/main.c
index c24805c824b9..439715858ba0 100644
--- a/init/main.c
+++ b/init/main.c
@@ -400,7 +400,7 @@ static int __init do_early_param(char *param, char *val)
400 400
401void __init parse_early_options(char *cmdline) 401void __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/* Arch code calls this early on, or if not, just before other parsing. */ 406/* Arch code calls this early on, or if not, just before other parsing. */
@@ -503,7 +503,7 @@ asmlinkage void __init start_kernel(void)
503 parse_early_param(); 503 parse_early_param();
504 parse_args("Booting kernel", static_command_line, __start___param, 504 parse_args("Booting kernel", static_command_line, __start___param,
505 __stop___param - __start___param, 505 __stop___param - __start___param,
506 &unknown_bootoption); 506 0, 0, &unknown_bootoption);
507 507
508 jump_label_init(); 508 jump_label_init();
509 509
@@ -699,16 +699,69 @@ int __init_or_module do_one_initcall(initcall_t fn)
699} 699}
700 700
701 701
702extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[]; 702extern initcall_t __initcall_start[];
703extern initcall_t __initcall0_start[];
704extern initcall_t __initcall1_start[];
705extern initcall_t __initcall2_start[];
706extern initcall_t __initcall3_start[];
707extern initcall_t __initcall4_start[];
708extern initcall_t __initcall5_start[];
709extern initcall_t __initcall6_start[];
710extern initcall_t __initcall7_start[];
711extern initcall_t __initcall_end[];
712
713static 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
725static 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
736static int __init ignore_unknown_bootoption(char *param, char *val)
737{
738 return 0;
739}
703 740
704static void __init do_initcalls(void) 741static void __init do_initcall_level(int level)
705{ 742{
743 extern const struct kernel_param __start___param[], __stop___param[];
706 initcall_t *fn; 744 initcall_t *fn;
707 745
708 for (fn = __early_initcall_end; fn < __initcall_end; fn++) 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++)
709 do_one_initcall(*fn); 754 do_one_initcall(*fn);
710} 755}
711 756
757static void __init do_initcalls(void)
758{
759 int level;
760
761 for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
762 do_initcall_level(level);
763}
764
712/* 765/*
713 * Ok, the machine is now initialized. None of the devices 766 * Ok, the machine is now initialized. None of the devices
714 * have been touched yet, but the CPU subsystem is up and 767 * have been touched yet, but the CPU subsystem is up and
@@ -732,7 +785,7 @@ static void __init do_pre_smp_initcalls(void)
732{ 785{
733 initcall_t *fn; 786 initcall_t *fn;
734 787
735 for (fn = __initcall_start; fn < __early_initcall_end; fn++) 788 for (fn = __initcall_start; fn < __initcall0_start; fn++)
736 do_one_initcall(*fn); 789 do_one_initcall(*fn);
737} 790}
738 791
diff --git a/kernel/module.c b/kernel/module.c
index 7e31da9750c0..6f6651a54590 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2923,7 +2923,8 @@ static struct module *load_module(void __user *umod,
2923 mutex_unlock(&module_mutex); 2923 mutex_unlock(&module_mutex);
2924 2924
2925 /* Module is ready to execute: parsing args may do that. */ 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 if (err < 0) 2928 if (err < 0)
2928 goto unlink; 2929 goto unlink;
2929 2930
diff --git a/kernel/params.c b/kernel/params.c
index 508828afb874..f37d82631347 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -87,6 +87,8 @@ static int parse_one(char *param,
87 char *val, 87 char *val,
88 const struct kernel_param *params, 88 const struct kernel_param *params,
89 unsigned num_params, 89 unsigned num_params,
90 s16 min_level,
91 s16 max_level,
90 int (*handle_unknown)(char *param, char *val)) 92 int (*handle_unknown)(char *param, char *val))
91{ 93{
92 unsigned int i; 94 unsigned int i;
@@ -95,6 +97,9 @@ static int parse_one(char *param,
95 /* Find parameter */ 97 /* Find parameter */
96 for (i = 0; i < num_params; i++) { 98 for (i = 0; i < num_params; i++) {
97 if (parameq(param, params[i].name)) { 99 if (parameq(param, params[i].name)) {
100 if (params[i].level < min_level
101 || params[i].level > max_level)
102 return 0;
98 /* No one handled NULL, so do it here. */ 103 /* No one handled NULL, so do it here. */
99 if (!val && params[i].ops->set != param_set_bool 104 if (!val && params[i].ops->set != param_set_bool
100 && params[i].ops->set != param_set_bint) 105 && params[i].ops->set != param_set_bint)
@@ -174,6 +179,8 @@ int parse_args(const char *name,
174 char *args, 179 char *args,
175 const struct kernel_param *params, 180 const struct kernel_param *params,
176 unsigned num, 181 unsigned num,
182 s16 min_level,
183 s16 max_level,
177 int (*unknown)(char *param, char *val)) 184 int (*unknown)(char *param, char *val))
178{ 185{
179 char *param, *val; 186 char *param, *val;
@@ -189,7 +196,8 @@ int parse_args(const char *name,
189 196
190 args = next_arg(args, &param, &val); 197 args = next_arg(args, &param, &val);
191 irq_was_disabled = irqs_disabled(); 198 irq_was_disabled = irqs_disabled();
192 ret = parse_one(param, val, params, num, unknown); 199 ret = parse_one(param, val, params, num,
200 min_level, max_level, unknown);
193 if (irq_was_disabled && !irqs_disabled()) { 201 if (irq_was_disabled && !irqs_disabled()) {
194 printk(KERN_WARNING "parse_args(): option '%s' enabled " 202 printk(KERN_WARNING "parse_args(): option '%s' enabled "
195 "irq's!\n", param); 203 "irq's!\n", param);
@@ -374,7 +382,7 @@ static int param_array(const char *name,
374 unsigned int min, unsigned int max, 382 unsigned int min, unsigned int max,
375 void *elem, int elemsize, 383 void *elem, int elemsize,
376 int (*set)(const char *, const struct kernel_param *kp), 384 int (*set)(const char *, const struct kernel_param *kp),
377 u16 flags, 385 s16 level,
378 unsigned int *num) 386 unsigned int *num)
379{ 387{
380 int ret; 388 int ret;
@@ -384,7 +392,7 @@ static int param_array(const char *name,
384 /* Get the name right for errors. */ 392 /* Get the name right for errors. */
385 kp.name = name; 393 kp.name = name;
386 kp.arg = elem; 394 kp.arg = elem;
387 kp.flags = flags; 395 kp.level = level;
388 396
389 *num = 0; 397 *num = 0;
390 /* We expect a comma-separated list of values. */ 398 /* We expect a comma-separated list of values. */
@@ -425,7 +433,7 @@ static int param_array_set(const char *val, const struct kernel_param *kp)
425 unsigned int temp_num; 433 unsigned int temp_num;
426 434
427 return param_array(kp->name, val, 1, arr->max, arr->elem, 435 return param_array(kp->name, val, 1, arr->max, arr->elem,
428 arr->elemsize, arr->ops->set, kp->flags, 436 arr->elemsize, arr->ops->set, kp->level,
429 arr->num ?: &temp_num); 437 arr->num ?: &temp_num);
430} 438}
431 439