Merge tag 'lsk-v3.10-15.09-android'
[firefly-linux-kernel-4.4.55.git] / kernel / params.c
index c29d12381213adbd7db10754e8bf08847071b284..53b958fcd639eb2d93d9bed73cffbb9250df7c06 100644 (file)
@@ -15,7 +15,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/ctype.h>
 
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt, a...)
-#endif
-
 /* Protects all parameters, and incidentally kmalloced_param list. */
 static DEFINE_MUTEX(param_lock);
 
@@ -67,27 +60,38 @@ static void maybe_kfree_parameter(void *param)
        }
 }
 
-static inline char dash2underscore(char c)
+static char dash2underscore(char c)
 {
        if (c == '-')
                return '_';
        return c;
 }
 
-static inline int parameq(const char *input, const char *paramname)
+bool parameqn(const char *a, const char *b, size_t n)
 {
-       unsigned int i;
-       for (i = 0; dash2underscore(input[i]) == paramname[i]; i++)
-               if (input[i] == '\0')
-                       return 1;
-       return 0;
+       size_t i;
+
+       for (i = 0; i < n; i++) {
+               if (dash2underscore(a[i]) != dash2underscore(b[i]))
+                       return false;
+       }
+       return true;
+}
+
+bool parameq(const char *a, const char *b)
+{
+       return parameqn(a, b, strlen(a)+1);
 }
 
 static int parse_one(char *param,
                     char *val,
+                    const char *doing,
                     const struct kernel_param *params,
                     unsigned num_params,
-                    int (*handle_unknown)(char *param, char *val))
+                    s16 min_level,
+                    s16 max_level,
+                    int (*handle_unknown)(char *param, char *val,
+                                    const char *doing))
 {
        unsigned int i;
        int err;
@@ -95,11 +99,15 @@ static int parse_one(char *param,
        /* Find parameter */
        for (i = 0; i < num_params; i++) {
                if (parameq(param, params[i].name)) {
+                       if (params[i].level < min_level
+                           || params[i].level > max_level)
+                               return 0;
                        /* No one handled NULL, so do it here. */
-                       if (!val && params[i].ops->set != param_set_bool)
+                       if (!val && params[i].ops->set != param_set_bool
+                           && params[i].ops->set != param_set_bint)
                                return -EINVAL;
-                       DEBUGP("They are equal!  Calling %p\n",
-                              params[i].ops->set);
+                       pr_debug("handling %s with %p\n", param,
+                               params[i].ops->set);
                        mutex_lock(&param_lock);
                        err = params[i].ops->set(val, &params[i]);
                        mutex_unlock(&param_lock);
@@ -108,11 +116,11 @@ static int parse_one(char *param,
        }
 
        if (handle_unknown) {
-               DEBUGP("Unknown argument: calling %p\n", handle_unknown);
-               return handle_unknown(param, val);
+               pr_debug("doing %s: %s='%s'\n", doing, param, val);
+               return handle_unknown(param, val, doing);
        }
 
-       DEBUGP("Unknown argument `%s'\n", param);
+       pr_debug("Unknown argument '%s'\n", param);
        return -ENOENT;
 }
 
@@ -169,46 +177,47 @@ static char *next_arg(char *args, char **param, char **val)
 }
 
 /* Args looks like "foo=bar,bar2 baz=fuz wiz". */
-int parse_args(const char *name,
+int parse_args(const char *doing,
               char *args,
               const struct kernel_param *params,
               unsigned num,
-              int (*unknown)(char *param, char *val))
+              s16 min_level,
+              s16 max_level,
+              int (*unknown)(char *param, char *val, const char *doing))
 {
        char *param, *val;
 
-       DEBUGP("Parsing ARGS: %s\n", args);
-
        /* Chew leading spaces */
        args = skip_spaces(args);
 
+       if (*args)
+               pr_debug("doing %s, parsing ARGS: '%s'\n", doing, args);
+
        while (*args) {
                int ret;
                int irq_was_disabled;
 
                args = next_arg(args, &param, &val);
                irq_was_disabled = irqs_disabled();
-               ret = parse_one(param, val, params, num, unknown);
-               if (irq_was_disabled && !irqs_disabled()) {
-                       printk(KERN_WARNING "parse_args(): option '%s' enabled "
-                                       "irq's!\n", param);
-               }
+               ret = parse_one(param, val, doing, params, num,
+                               min_level, max_level, unknown);
+               if (irq_was_disabled && !irqs_disabled())
+                       pr_warn("%s: option '%s' enabled irq's!\n",
+                               doing, param);
+
                switch (ret) {
                case -ENOENT:
-                       printk(KERN_ERR "%s: Unknown parameter `%s'\n",
-                              name, param);
+                       pr_err("%s: Unknown parameter `%s'\n", doing, param);
                        return ret;
                case -ENOSPC:
-                       printk(KERN_ERR
-                              "%s: `%s' too large for parameter `%s'\n",
-                              name, val ?: "", param);
+                       pr_err("%s: `%s' too large for parameter `%s'\n",
+                              doing, val ?: "", param);
                        return ret;
                case 0:
                        break;
                default:
-                       printk(KERN_ERR
-                              "%s: `%s' invalid for parameter `%s'\n",
-                              name, val ?: "", param);
+                       pr_err("%s: `%s' invalid for parameter `%s'\n",
+                              doing, val ?: "", param);
                        return ret;
                }
        }
@@ -217,48 +226,6 @@ int parse_args(const char *name,
        return 0;
 }
 
-#ifdef CONFIG_RK_CONFIG
-static int ignore_unknown(char *param, char *val)
-{
-       return 0;
-}
-
-int module_parse_kernel_cmdline(const char *name, const struct kernel_param *params, unsigned num)
-{
-       int ret;
-       unsigned i;
-       size_t name_len = strlen(name);
-       struct kernel_param new_params[num];
-       char args[strlen(saved_command_line) + 1];
-
-       if (!num)
-               return 0;
-
-       strcpy(args, saved_command_line);
-       memcpy(new_params, params, sizeof(struct kernel_param) * num);
-
-       for (i = 0; i < num; i++)
-               new_params[i].name = NULL;
-       for (i = 0; i < num; i++) {
-               char *new_name = kmalloc(strlen(params[i].name) + name_len + 2, GFP_KERNEL);
-               if (!new_name) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               sprintf(new_name, "%s.%s", name, params[i].name);
-               new_params[i].name = new_name;
-       }
-
-       ret = parse_args(name, args, new_params, num, ignore_unknown);
-
-out:
-       for (i = 0; i < num; i++)
-               if (new_params[i].name)
-                       kfree(new_params[i].name);
-       return ret;
-}
-#endif
-
 /* Lazy bastard, eh? */
 #define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn)              \
        int param_set_##name(const char *val, const struct kernel_param *kp) \
@@ -267,8 +234,8 @@ out:
                int ret;                                                \
                                                                        \
                ret = strtolfn(val, 0, &l);                             \
-               if (ret == -EINVAL || ((type)l != l))                   \
-                       return -EINVAL;                                 \
+               if (ret < 0 || ((type)l != l))                          \
+                       return ret < 0 ? ret : -EINVAL;                 \
                *((type *)kp->arg) = l;                                 \
                return 0;                                               \
        }                                                               \
@@ -296,8 +263,7 @@ STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, strict_strtoul);
 int param_set_charp(const char *val, const struct kernel_param *kp)
 {
        if (strlen(val) > 1024) {
-               printk(KERN_ERR "%s: string parameter too long\n",
-                      kp->name);
+               pr_err("%s: string parameter too long\n", kp->name);
                return -ENOSPC;
        }
 
@@ -338,35 +304,18 @@ EXPORT_SYMBOL(param_ops_charp);
 /* Actually could be a bool or an int, for historical reasons. */
 int param_set_bool(const char *val, const struct kernel_param *kp)
 {
-       bool v;
-       int ret;
-
        /* No equals means "set"... */
        if (!val) val = "1";
 
        /* One of =[yYnN01] */
-       ret = strtobool(val, &v);
-       if (ret)
-               return ret;
-
-       if (kp->flags & KPARAM_ISBOOL)
-               *(bool *)kp->arg = v;
-       else
-               *(int *)kp->arg = v;
-       return 0;
+       return strtobool(val, kp->arg);
 }
 EXPORT_SYMBOL(param_set_bool);
 
 int param_get_bool(char *buffer, const struct kernel_param *kp)
 {
-       bool val;
-       if (kp->flags & KPARAM_ISBOOL)
-               val = *(bool *)kp->arg;
-       else
-               val = *(int *)kp->arg;
-
        /* Y and N chosen as being relatively non-coder friendly */
-       return sprintf(buffer, "%c", val ? 'Y' : 'N');
+       return sprintf(buffer, "%c", *(bool *)kp->arg ? 'Y' : 'N');
 }
 EXPORT_SYMBOL(param_get_bool);
 
@@ -384,7 +333,6 @@ int param_set_invbool(const char *val, const struct kernel_param *kp)
        struct kernel_param dummy;
 
        dummy.arg = &boolval;
-       dummy.flags = KPARAM_ISBOOL;
        ret = param_set_bool(val, &dummy);
        if (ret == 0)
                *(bool *)kp->arg = !boolval;
@@ -404,13 +352,36 @@ struct kernel_param_ops param_ops_invbool = {
 };
 EXPORT_SYMBOL(param_ops_invbool);
 
+int param_set_bint(const char *val, const struct kernel_param *kp)
+{
+       struct kernel_param boolkp;
+       bool v;
+       int ret;
+
+       /* Match bool exactly, by re-using it. */
+       boolkp = *kp;
+       boolkp.arg = &v;
+
+       ret = param_set_bool(val, &boolkp);
+       if (ret == 0)
+               *(int *)kp->arg = v;
+       return ret;
+}
+EXPORT_SYMBOL(param_set_bint);
+
+struct kernel_param_ops param_ops_bint = {
+       .set = param_set_bint,
+       .get = param_get_int,
+};
+EXPORT_SYMBOL(param_ops_bint);
+
 /* We break the rule and mangle the string. */
 static int param_array(const char *name,
                       const char *val,
                       unsigned int min, unsigned int max,
                       void *elem, int elemsize,
                       int (*set)(const char *, const struct kernel_param *kp),
-                      u16 flags,
+                      s16 level,
                       unsigned int *num)
 {
        int ret;
@@ -420,7 +391,7 @@ static int param_array(const char *name,
        /* Get the name right for errors. */
        kp.name = name;
        kp.arg = elem;
-       kp.flags = flags;
+       kp.level = level;
 
        *num = 0;
        /* We expect a comma-separated list of values. */
@@ -428,8 +399,7 @@ static int param_array(const char *name,
                int len;
 
                if (*num == max) {
-                       printk(KERN_ERR "%s: can only take %i arguments\n",
-                              name, max);
+                       pr_err("%s: can only take %i arguments\n", name, max);
                        return -EINVAL;
                }
                len = strcspn(val, ",");
@@ -448,8 +418,7 @@ static int param_array(const char *name,
        } while (save == ',');
 
        if (*num < min) {
-               printk(KERN_ERR "%s: needs at least %i arguments\n",
-                      name, min);
+               pr_err("%s: needs at least %i arguments\n", name, min);
                return -EINVAL;
        }
        return 0;
@@ -461,7 +430,7 @@ static int param_array_set(const char *val, const struct kernel_param *kp)
        unsigned int temp_num;
 
        return param_array(kp->name, val, 1, arr->max, arr->elem,
-                          arr->elemsize, arr->ops->set, kp->flags,
+                          arr->elemsize, arr->ops->set, kp->level,
                           arr->num ?: &temp_num);
 }
 
@@ -508,7 +477,7 @@ int param_set_copystring(const char *val, const struct kernel_param *kp)
        const struct kparam_string *kps = kp->str;
 
        if (strlen(val)+1 > kps->maxlen) {
-               printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
+               pr_err("%s: string doesn't fit in %u chars.\n",
                       kp->name, kps->maxlen-1);
                return -ENOSPC;
        }
@@ -553,7 +522,7 @@ struct module_param_attrs
 #define to_param_attr(n) container_of(n, struct param_attribute, mattr)
 
 static ssize_t param_attr_show(struct module_attribute *mattr,
-                              struct module *mod, char *buf)
+                              struct module_kobject *mk, char *buf)
 {
        int count;
        struct param_attribute *attribute = to_param_attr(mattr);
@@ -573,7 +542,7 @@ static ssize_t param_attr_show(struct module_attribute *mattr,
 
 /* sysfs always hands a nul-terminated string in buf.  We rely on that. */
 static ssize_t param_attr_store(struct module_attribute *mattr,
-                               struct module *owner,
+                               struct module_kobject *km,
                                const char *buf, size_t len)
 {
        int err;
@@ -644,10 +613,13 @@ static __modinit int add_sysfs_param(struct module_kobject *mk,
                       sizeof(*mk->mp) + sizeof(mk->mp->attrs[0]) * (num+1),
                       GFP_KERNEL);
        if (!new) {
-               kfree(mk->mp);
+               kfree(attrs);
                err = -ENOMEM;
                goto fail;
        }
+       /* Despite looking like the typical realloc() bug, this is safe.
+        * We *want* the old 'attrs' to be freed either way, and we'll store
+        * the new one in the success case. */
        attrs = krealloc(attrs, sizeof(new->grp.attrs[0])*(num+2), GFP_KERNEL);
        if (!attrs) {
                err = -ENOMEM;
@@ -772,13 +744,14 @@ static struct module_kobject * __init locate_module_kobject(const char *name)
                mk->kobj.kset = module_kset;
                err = kobject_init_and_add(&mk->kobj, &module_ktype, NULL,
                                           "%s", name);
+#ifdef CONFIG_MODULES
+               if (!err)
+                       err = sysfs_create_file(&mk->kobj, &module_uevent.attr);
+#endif
                if (err) {
                        kobject_put(&mk->kobj);
-                       printk(KERN_ERR
-                               "Module '%s' failed add to sysfs, error number %d\n",
+                       pr_crit("Adding module '%s' to sysfs failed (%d), the system may be unstable.\n",
                                name, err);
-                       printk(KERN_ERR
-                               "The system will be unstable now.\n");
                        return NULL;
                }
 
@@ -849,7 +822,7 @@ static void __init param_sysfs_builtin(void)
 }
 
 ssize_t __modver_version_show(struct module_attribute *mattr,
-                             struct module *mod, char *buf)
+                             struct module_kobject *mk, char *buf)
 {
        struct module_version_attribute *vattr =
                container_of(mattr, struct module_version_attribute, mattr);
@@ -894,7 +867,7 @@ static ssize_t module_attr_show(struct kobject *kobj,
        if (!attribute->show)
                return -EIO;
 
-       ret = attribute->show(attribute, mk->mod, buf);
+       ret = attribute->show(attribute, mk, buf);
 
        return ret;
 }
@@ -913,7 +886,7 @@ static ssize_t module_attr_store(struct kobject *kobj,
        if (!attribute->store)
                return -EIO;
 
-       ret = attribute->store(attribute, mk->mod, buf, len);
+       ret = attribute->store(attribute, mk, buf, len);
 
        return ret;
 }