UBUNTU: SAUCE: add option to hand off all kernel parameters to init
authorAndy Whitcroft <apw@canonical.com>
Thu, 17 Jun 2010 09:46:47 +0000 (10:46 +0100)
committerLeann Ogasawara <leann.ogasawara@canonical.com>
Mon, 28 Mar 2011 13:48:47 +0000 (06:48 -0700)
BugLink: http://bugs.launchpad.net/bugs/586386

Some init packages such as upstart find having all of the kernel parameters
passed in useful.  Currently they have to open up /proc/cmdline and
reparse that to obtain this information.  Add a kernel configuration
option to enable passing of all options.

Note, enabling this option will reduce the chances that a fallback from
/sbin/init to /bin/bash or /bin/sh will succeed.  Though it should be
noted that there are commonly unknown options present which would already
break this fallback.  init=/bin/foo provides explicit control over options
which is unaffected by this change.

Signed-off-by: Andy Whitcroft <apw@canonical.com>
Signed-off-by: Leann Ogasawara <leann.ogasawara@canonical.com>

include/linux/moduleparam.h
init/Kconfig
init/main.c
kernel/params.c

index 07b4195..d0f6335 100644 (file)
@@ -267,7 +267,7 @@ extern int parse_args(const char *name,
                      char *args,
                      const struct kernel_param *params,
                      unsigned num,
                      char *args,
                      const struct kernel_param *params,
                      unsigned num,
-                     int (*unknown)(char *param, char *val));
+                     int (*handle)(char *param, char *val, int known));
 
 /* Called by module remove. */
 #ifdef CONFIG_SYSFS
 
 /* Called by module remove. */
 #ifdef CONFIG_SYSFS
index 464c84a..d1d4acb 100644 (file)
@@ -82,6 +82,13 @@ config INIT_ENV_ARG_LIMIT
          Maximum of each of the number of arguments and environment
          variables passed to init from the kernel command line.
 
          Maximum of each of the number of arguments and environment
          variables passed to init from the kernel command line.
 
+config INIT_PASS_ALL_PARAMS
+       bool "Pass all (known and unknown) kernel parameters to init"
+       default n
+       help
+         Pass all kernel command line parameters to init, this includes
+         those consumed by kernel modules.  This is useful for upstart
+         based systems.  If in doubt say N.
 
 config CROSS_COMPILE
        string "Cross-compiler tool prefix"
 
 config CROSS_COMPILE
        string "Cross-compiler tool prefix"
index be103bf..bfc0a03 100644 (file)
@@ -113,6 +113,11 @@ EXPORT_SYMBOL(system_state);
  */
 #define MAX_INIT_ARGS CONFIG_INIT_ENV_ARG_LIMIT
 #define MAX_INIT_ENVS CONFIG_INIT_ENV_ARG_LIMIT
  */
 #define MAX_INIT_ARGS CONFIG_INIT_ENV_ARG_LIMIT
 #define MAX_INIT_ENVS CONFIG_INIT_ENV_ARG_LIMIT
+#ifdef CONFIG_INIT_PASS_ALL_PARAMS
+#define INIT_PASS_FUNCTION pass_all_bootoptions
+#else
+#define INIT_PASS_FUNCTION pass_unknown_bootoptions
+#endif
 
 extern void time_init(void);
 /* Default late time init is NULL. archs can override this later. */
 
 extern void time_init(void);
 /* Default late time init is NULL. archs can override this later. */
@@ -273,10 +278,11 @@ static int __init loglevel(char *str)
 early_param("loglevel", loglevel);
 
 /*
 early_param("loglevel", loglevel);
 
 /*
- * Unknown boot options get handed to init, unless they look like
- * unused parameters (modprobe will find them in /proc/cmdline).
+ * Select boot options to hand to init.  If all is set hand off them all
+ * otherwise only hand off unused ones which do not apply to modules
+ * (modprobe will find them in /proc/cmdline).
  */
  */
-static int __init unknown_bootoption(char *param, char *val)
+static int __init pass_bootoption(char *param, char *val, int all)
 {
        /* Change NUL term back to "=", to make "param" the whole string. */
        if (val) {
 {
        /* Change NUL term back to "=", to make "param" the whole string. */
        if (val) {
@@ -292,11 +298,11 @@ static int __init unknown_bootoption(char *param, char *val)
        }
 
        /* Handle obsolete-style parameters */
        }
 
        /* Handle obsolete-style parameters */
-       if (obsolete_checksetup(param))
+       if (obsolete_checksetup(param) && !all)
                return 0;
 
        /* Unused module parameter. */
                return 0;
 
        /* Unused module parameter. */
-       if (strchr(param, '.') && (!val || strchr(param, '.') < val))
+       if (!all && strchr(param, '.') && (!val || strchr(param, '.') < val))
                return 0;
 
        if (panic_later)
                return 0;
 
        if (panic_later)
@@ -327,6 +333,16 @@ static int __init unknown_bootoption(char *param, char *val)
        }
        return 0;
 }
        }
        return 0;
 }
+static int __init pass_unknown_bootoptions(char *param, char *val, int known)
+{
+       if (known)
+               return 0;
+       return pass_bootoption(param, val, 0);
+}
+static int __init pass_all_bootoptions(char *param, char *val, int known)
+{
+       return pass_bootoption(param, val, 1);
+}
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
 int __read_mostly debug_pagealloc_enabled = 0;
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
 int __read_mostly debug_pagealloc_enabled = 0;
@@ -464,10 +480,13 @@ static noinline void __init_refok rest_init(void)
 }
 
 /* Check for early params. */
 }
 
 /* Check for early params. */
-static int __init do_early_param(char *param, char *val)
+static int __init do_early_param(char *param, char *val, int known)
 {
        const struct obs_kernel_param *p;
 
 {
        const struct obs_kernel_param *p;
 
+       if (known)
+               return 0;
+
        for (p = __setup_start; p < __setup_end; p++) {
                if ((p->early && strcmp(param, p->str) == 0) ||
                    (strcmp(param, "console") == 0 &&
        for (p = __setup_start; p < __setup_end; p++) {
                if ((p->early && strcmp(param, p->str) == 0) ||
                    (strcmp(param, "console") == 0 &&
@@ -587,7 +606,7 @@ asmlinkage void __init start_kernel(void)
        parse_early_param();
        parse_args("Booting kernel", static_command_line, __start___param,
                   __stop___param - __start___param,
        parse_early_param();
        parse_args("Booting kernel", static_command_line, __start___param,
                   __stop___param - __start___param,
-                  &unknown_bootoption);
+                  &INIT_PASS_FUNCTION);
        /*
         * These use large bootmem allocations and must precede
         * kmem_cache_init()
        /*
         * These use large bootmem allocations and must precede
         * kmem_cache_init()
index 0da1411..dcb711d 100644 (file)
@@ -87,7 +87,7 @@ static int parse_one(char *param,
                     char *val,
                     const struct kernel_param *params,
                     unsigned num_params,
                     char *val,
                     const struct kernel_param *params,
                     unsigned num_params,
-                    int (*handle_unknown)(char *param, char *val))
+                    int (*handle_arg)(char *param, char *val, int known))
 {
        unsigned int i;
        int err;
 {
        unsigned int i;
        int err;
@@ -98,6 +98,14 @@ static int parse_one(char *param,
                        /* Noone handled NULL, so do it here. */
                        if (!val && params[i].ops->set != param_set_bool)
                                return -EINVAL;
                        /* Noone handled NULL, so do it here. */
                        if (!val && params[i].ops->set != param_set_bool)
                                return -EINVAL;
+                       if (handle_arg) {
+                               int ret;
+                               DEBUGP("Valid argument: calling %p\n",
+                                      handle_arg);
+                               ret = handle_arg(param, val, 1);
+                               if (ret)
+                                       return ret;
+                       }
                        DEBUGP("They are equal!  Calling %p\n",
                               params[i].ops->set);
                        mutex_lock(&param_lock);
                        DEBUGP("They are equal!  Calling %p\n",
                               params[i].ops->set);
                        mutex_lock(&param_lock);
@@ -107,9 +115,9 @@ static int parse_one(char *param,
                }
        }
 
                }
        }
 
-       if (handle_unknown) {
-               DEBUGP("Unknown argument: calling %p\n", handle_unknown);
-               return handle_unknown(param, val);
+       if (handle_arg) {
+               DEBUGP("Unknown argument: calling %p\n", handle_arg);
+               return handle_arg(param, val, 0);
        }
 
        DEBUGP("Unknown argument `%s'\n", param);
        }
 
        DEBUGP("Unknown argument `%s'\n", param);
@@ -173,7 +181,7 @@ int parse_args(const char *name,
               char *args,
               const struct kernel_param *params,
               unsigned num,
               char *args,
               const struct kernel_param *params,
               unsigned num,
-              int (*unknown)(char *param, char *val))
+              int (*handle_arg)(char *param, char *val, int arg))
 {
        char *param, *val;
 
 {
        char *param, *val;
 
@@ -188,7 +196,7 @@ int parse_args(const char *name,
 
                args = next_arg(args, &param, &val);
                irq_was_disabled = irqs_disabled();
 
                args = next_arg(args, &param, &val);
                irq_was_disabled = irqs_disabled();
-               ret = parse_one(param, val, params, num, unknown);
+               ret = parse_one(param, val, params, num, handle_arg);
                if (irq_was_disabled && !irqs_disabled()) {
                        printk(KERN_WARNING "parse_args(): option '%s' enabled "
                                        "irq's!\n", param);
                if (irq_was_disabled && !irqs_disabled()) {
                        printk(KERN_WARNING "parse_args(): option '%s' enabled "
                                        "irq's!\n", param);