Skip to content

Commit 026cee0

Browse files
pawelmollrustyrussell
authored andcommitted
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 <[email protected]> Signed-off-by: Rusty Russell <[email protected]>
1 parent 8b82528 commit 026cee0

File tree

6 files changed

+132
-41
lines changed

6 files changed

+132
-41
lines changed

arch/powerpc/mm/hugetlbpage.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,8 @@ void __init reserve_hugetlb_gpages(void)
310310
int i;
311311

312312
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);
314315

315316
/*
316317
* Walk gpage list in reverse, allocating larger page sizes first.

include/asm-generic/vmlinux.lds.h

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -616,30 +616,23 @@
616616
*(.init.setup) \
617617
VMLINUX_SYMBOL(__setup_end) = .;
618618

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) \
639623

640624
#define INIT_CALLS \
641625
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) \
643636
VMLINUX_SYMBOL(__initcall_end) = .;
644637

645638
#define CON_INITCALL \

include/linux/moduleparam.h

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ struct kernel_param {
5151
const char *name;
5252
const struct kernel_param_ops *ops;
5353
u16 perm;
54-
u16 flags;
54+
s16 level;
5555
union {
5656
void *arg;
5757
const struct kparam_string *str;
@@ -128,7 +128,40 @@ struct kparam_array
128128
* The ops can have NULL set or get functions.
129129
*/
130130
#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)
132165

133166
/* On alpha, ia64 and ppc64 relocations to global data cannot go into
134167
read-only sections (which is part of respective UNIX ABI on these
@@ -142,7 +175,7 @@ struct kparam_array
142175

143176
/* This is the fundamental function for registering boot/module
144177
parameters. */
145-
#define __module_param_call(prefix, name, ops, arg, perm) \
178+
#define __module_param_call(prefix, name, ops, arg, perm, level) \
146179
/* Default value instead of permissions? */ \
147180
static int __param_perm_check_##name __attribute__((unused)) = \
148181
BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)) \
@@ -151,15 +184,15 @@ struct kparam_array
151184
static struct kernel_param __moduleparam_const __param_##name \
152185
__used \
153186
__attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
154-
= { __param_str_##name, ops, perm, 0, { arg } }
187+
= { __param_str_##name, ops, perm, level, { arg } }
155188

156189
/* Obsolete - use module_param_cb() */
157190
#define module_param_call(name, set, get, arg, perm) \
158191
static struct kernel_param_ops __param_ops_##name = \
159192
{ (void *)set, (void *)get }; \
160193
__module_param_call(MODULE_PARAM_PREFIX, \
161194
name, &__param_ops_##name, arg, \
162-
(perm) + sizeof(__check_old_set_param(set))*0)
195+
(perm) + sizeof(__check_old_set_param(set))*0, 0)
163196

164197
/* We don't get oldget: it's often a new-style param_get_uint, etc. */
165198
static inline int
@@ -239,7 +272,7 @@ static inline void __kernel_param_unlock(void)
239272
*/
240273
#define core_param(name, var, type, perm) \
241274
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)
243276
#endif /* !MODULE */
244277

245278
/**
@@ -257,7 +290,7 @@ static inline void __kernel_param_unlock(void)
257290
= { len, string }; \
258291
__module_param_call(MODULE_PARAM_PREFIX, name, \
259292
&param_ops_string, \
260-
.str = &__param_string_##name, perm); \
293+
.str = &__param_string_##name, perm, 0); \
261294
__MODULE_PARM_TYPE(name, "string")
262295

263296
/**
@@ -285,6 +318,8 @@ extern int parse_args(const char *name,
285318
char *args,
286319
const struct kernel_param *params,
287320
unsigned num,
321+
s16 level_min,
322+
s16 level_max,
288323
int (*unknown)(char *param, char *val));
289324

290325
/* Called by module remove. */
@@ -396,7 +431,7 @@ extern int param_set_bint(const char *val, const struct kernel_param *kp);
396431
__module_param_call(MODULE_PARAM_PREFIX, name, \
397432
&param_array_ops, \
398433
.arr = &__param_arr_##name, \
399-
perm); \
434+
perm, 0); \
400435
__MODULE_PARM_TYPE(name, "array of " #type)
401436

402437
extern struct kernel_param_ops param_array_ops;

init/main.c

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ static int __init do_early_param(char *param, char *val)
400400

401401
void __init parse_early_options(char *cmdline)
402402
{
403-
parse_args("early options", cmdline, NULL, 0, do_early_param);
403+
parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param);
404404
}
405405

406406
/* Arch code calls this early on, or if not, just before other parsing. */
@@ -503,7 +503,7 @@ asmlinkage void __init start_kernel(void)
503503
parse_early_param();
504504
parse_args("Booting kernel", static_command_line, __start___param,
505505
__stop___param - __start___param,
506-
&unknown_bootoption);
506+
0, 0, &unknown_bootoption);
507507

508508
jump_label_init();
509509

@@ -699,16 +699,69 @@ int __init_or_module do_one_initcall(initcall_t fn)
699699
}
700700

701701

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+
}
703740

704-
static void __init do_initcalls(void)
741+
static void __init do_initcall_level(int level)
705742
{
743+
extern const struct kernel_param __start___param[], __stop___param[];
706744
initcall_t *fn;
707745

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++)
709754
do_one_initcall(*fn);
710755
}
711756

757+
static 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+
712765
/*
713766
* Ok, the machine is now initialized. None of the devices
714767
* have been touched yet, but the CPU subsystem is up and
@@ -732,7 +785,7 @@ static void __init do_pre_smp_initcalls(void)
732785
{
733786
initcall_t *fn;
734787

735-
for (fn = __initcall_start; fn < __early_initcall_end; fn++)
788+
for (fn = __initcall_start; fn < __initcall0_start; fn++)
736789
do_one_initcall(*fn);
737790
}
738791

kernel/module.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2923,7 +2923,8 @@ static struct module *load_module(void __user *umod,
29232923
mutex_unlock(&module_mutex);
29242924

29252925
/* 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);
29272928
if (err < 0)
29282929
goto unlink;
29292930

kernel/params.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ static int parse_one(char *param,
8787
char *val,
8888
const struct kernel_param *params,
8989
unsigned num_params,
90+
s16 min_level,
91+
s16 max_level,
9092
int (*handle_unknown)(char *param, char *val))
9193
{
9294
unsigned int i;
@@ -95,6 +97,9 @@ static int parse_one(char *param,
9597
/* Find parameter */
9698
for (i = 0; i < num_params; i++) {
9799
if (parameq(param, params[i].name)) {
100+
if (params[i].level < min_level
101+
|| params[i].level > max_level)
102+
return 0;
98103
/* No one handled NULL, so do it here. */
99104
if (!val && params[i].ops->set != param_set_bool
100105
&& params[i].ops->set != param_set_bint)
@@ -174,6 +179,8 @@ int parse_args(const char *name,
174179
char *args,
175180
const struct kernel_param *params,
176181
unsigned num,
182+
s16 min_level,
183+
s16 max_level,
177184
int (*unknown)(char *param, char *val))
178185
{
179186
char *param, *val;
@@ -189,7 +196,8 @@ int parse_args(const char *name,
189196

190197
args = next_arg(args, &param, &val);
191198
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);
193201
if (irq_was_disabled && !irqs_disabled()) {
194202
printk(KERN_WARNING "parse_args(): option '%s' enabled "
195203
"irq's!\n", param);
@@ -374,7 +382,7 @@ static int param_array(const char *name,
374382
unsigned int min, unsigned int max,
375383
void *elem, int elemsize,
376384
int (*set)(const char *, const struct kernel_param *kp),
377-
u16 flags,
385+
s16 level,
378386
unsigned int *num)
379387
{
380388
int ret;
@@ -384,7 +392,7 @@ static int param_array(const char *name,
384392
/* Get the name right for errors. */
385393
kp.name = name;
386394
kp.arg = elem;
387-
kp.flags = flags;
395+
kp.level = level;
388396

389397
*num = 0;
390398
/* 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)
425433
unsigned int temp_num;
426434

427435
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,
429437
arr->num ?: &temp_num);
430438
}
431439

0 commit comments

Comments
 (0)