core_param: call these really, really early.

From: Rusty Russell
Date: Wed Nov 19 2008 - 09:53:57 EST


As soon as we have command line, so even before early_param. They
just set vars, so it makes sense to do them as early as possible.

This allows them to replace early_param, and fixes a bug in the new
cpu_alloc implementation patches which was a complete PITA to find.

Signed-off-by: Rusty Russell <rusty@xxxxxxxxxxxxxxx>
---
include/asm-generic/vmlinux.lds.h | 3 +++
include/linux/moduleparam.h | 26 ++++++++++++++++----------
init/main.c | 25 ++++++++++++++++++++++++-
kernel/params.c | 20 ++++++++++----------
4 files changed, 53 insertions(+), 21 deletions(-)

diff -r 65aebfe44ef1 include/asm-generic/vmlinux.lds.h
--- a/include/asm-generic/vmlinux.lds.h Wed Nov 19 22:47:52 2008 +1030
+++ b/include/asm-generic/vmlinux.lds.h Wed Nov 19 23:58:08 2008 +1030
@@ -213,6 +213,9 @@
VMLINUX_SYMBOL(__start___param) = .; \
*(__param) \
VMLINUX_SYMBOL(__stop___param) = .; \
+ VMLINUX_SYMBOL(__start___core_param) = .; \
+ *(__core_param) \
+ VMLINUX_SYMBOL(__stop___core_param) = .; \
. = ALIGN((align)); \
VMLINUX_SYMBOL(__end_rodata) = .; \
} \
diff -r 65aebfe44ef1 include/linux/moduleparam.h
--- a/include/linux/moduleparam.h Wed Nov 19 22:47:52 2008 +1030
+++ b/include/linux/moduleparam.h Wed Nov 19 23:58:08 2008 +1030
@@ -79,7 +79,7 @@
parameters. perm sets the visibility in sysfs: 000 means it's
not there, read bits mean it's readable, write bits mean it's
writable. */
-#define __module_param_call(prefix, name, set, get, arg, perm) \
+#define __module_param_call(prefix, section, name, set, get, arg, perm) \
/* Default value instead of permissions? */ \
static int __param_perm_check_##name __attribute__((unused)) = \
BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)) \
@@ -87,11 +87,12 @@
static const char __param_str_##name[] = prefix #name; \
static struct kernel_param __moduleparam_const __param_##name \
__used \
- __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
+ __attribute__ ((unused, __section__(section), aligned(sizeof(void *)))) \
= { __param_str_##name, perm, set, get, { arg } }

#define module_param_call(name, set, get, arg, perm) \
- __module_param_call(MODULE_PARAM_PREFIX, name, set, get, arg, perm)
+ __module_param_call(MODULE_PARAM_PREFIX, "__param", \
+ name, set, get, arg, perm)

/* Helper functions: type is byte, short, ushort, int, uint, long,
ulong, charp, bool or invbool, or XXX if you define param_get_XXX,
@@ -106,21 +107,22 @@

#ifndef MODULE
/**
- * core_param - define a historical core kernel parameter.
+ * core_param - define a core kernel parameter to be set very early
* @name: the name of the cmdline and sysfs parameter (often the same as var)
* @var: the variable
* @type: the type (for param_set_##type and param_get_##type)
* @perm: visibility in sysfs
*
- * core_param is just like module_param(), but cannot be modular and
- * doesn't add a prefix (such as "printk."). This is for compatibility
- * with __setup(), and it makes sense as truly core parameters aren't
- * tied to the particular file they're in.
+ * core_param is just like module_param(), but cannot be modular,
+ * doesn't add a prefix (such as "printk.") and is called insanely
+ * early in boot. This is for compatibility with __setup(), and it
+ * makes sense as truly core parameters aren't tied to the particular
+ * file they're in.
*/
#define core_param(name, var, type, perm) \
param_check_##type(name, &(var)); \
- __module_param_call("", name, param_set_##type, param_get_##type, \
- &var, perm)
+ __module_param_call("", "__core_param", name, param_set_##type, \
+ param_get_##type, &var, perm)
#endif /* !MODULE */

/* Actually copy string: maxlen param is usually sizeof(string). */
@@ -224,4 +226,8 @@
{ }
#endif

+/* Created by include/asm-generic/vmlinux.lds.h */
+extern struct kernel_param __start___core_param[], __stop___core_param[];
+extern struct kernel_param __start___param[], __stop___param[];
+
#endif /* _LINUX_MODULE_PARAMS_H */
diff -r 65aebfe44ef1 init/main.c
--- a/init/main.c Wed Nov 19 22:47:52 2008 +1030
+++ b/init/main.c Wed Nov 19 23:58:08 2008 +1030
@@ -256,12 +256,32 @@

early_param("loglevel", loglevel);

+static bool __init is_core_param(const char *param)
+{
+ const struct kernel_param *i;
+
+ for (i = __start___core_param; i < __stop___core_param; i++)
+ if (strcmp(param, i->name) == 0)
+ return true;
+ return false;
+}
+
+/* We can ignore options not found in core params. */
+static int __init unknown_core_ok(char *param, char *val)
+{
+ return 0;
+}
+
/*
* Unknown boot options get handed to init, unless they look like
* failed parameters
*/
static int __init unknown_bootoption(char *param, char *val)
{
+ /* Already handled as a core param? */
+ if (is_core_param(param))
+ return 0;
+
/* Change NUL term back to "=", to make "param" the whole string. */
if (val) {
/* param=val or param="val"? */
@@ -539,7 +559,6 @@
asmlinkage void __init start_kernel(void)
{
char * command_line;
- extern struct kernel_param __start___param[], __stop___param[];

smp_setup_processor_id();

@@ -569,6 +588,10 @@
setup_arch(&command_line);
mm_init_owner(&init_mm, &init_task);
setup_command_line(command_line);
+ parse_args("Core params", command_line, __start___core_param,
+ __stop___core_param - __start___core_param,
+ unknown_core_ok);
+
unwind_setup();
setup_per_cpu_areas();
setup_nr_cpu_ids();
diff -r 65aebfe44ef1 kernel/params.c
--- a/kernel/params.c Wed Nov 19 22:47:52 2008 +1030
+++ b/kernel/params.c Wed Nov 19 23:58:08 2008 +1030
@@ -376,8 +376,6 @@
#define to_module_attr(n) container_of(n, struct module_attribute, attr);
#define to_module_kobject(n) container_of(n, struct module_kobject, kobj);

-extern struct kernel_param __start___param[], __stop___param[];
-
struct param_attribute
{
struct module_attribute mattr;
@@ -636,15 +634,17 @@
continue;

dot = strchr(kp->name, '.');
- if (!dot) {
- /* This happens for core_param() */
- strcpy(modname, "kernel");
- name_len = 0;
- } else {
- name_len = dot - kp->name + 1;
- strlcpy(modname, kp->name, name_len);
- }
+ BUG_ON(!dot);
+ name_len = dot - kp->name + 1;
+ strlcpy(modname, kp->name, name_len);
kernel_add_sysfs_param(modname, kp, name_len);
+ }
+
+ for (kp = __start___core_param; kp < __stop___core_param; kp++) {
+ if (kp->perm == 0)
+ continue;
+
+ kernel_add_sysfs_param("kernel", kp, 0);
}
}


¢éì®&Þ~º&¶¬–+-±éÝ¥Šw®žË±Êâmébžìdz¹Þ)í…æèw*jg¬±¨¶‰šŽŠÝj/êäz¹ÞŠà2ŠÞ¨è­Ú&¢)ß«a¶Úþø®G«éh®æj:+v‰¨Šwè†Ù>Wš±êÞiÛaxPjØm¶Ÿÿà -»+ƒùdš_