Merge branch 'params' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
* 'params' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus: (22 commits) param: don't deref arg in __same_type() checks param: update drivers/acpi/debug.c to new scheme param: use module_param in drivers/message/fusion/mptbase.c ide: use module_param_named rather than module_param_call param: update drivers/char/ipmi/ipmi_watchdog.c to new scheme param: lock if_sdio's lbs_helper_name and lbs_fw_name against sysfs changes. param: lock myri10ge_fw_name against sysfs changes. param: simple locking for sysfs-writable charp parameters param: remove unnecessary writable charp param: add kerneldoc to moduleparam.h param: locking for kernel parameters param: make param sections const. param: use free hook for charp (fix leak of charp parameters) param: add a free hook to kernel_param_ops. param: silence .init.text references from param ops Add param ops struct for hvc_iucv driver. nfs: update for module_param_named API change AppArmor: update for module_param_named API change param: use ops in struct kernel_param, rather than get and set fns directly param: move the EXPORT_SYMBOL to after the definitions. ...
This commit is contained in:
+161
-72
@@ -31,6 +31,42 @@
|
||||
#define DEBUGP(fmt, a...)
|
||||
#endif
|
||||
|
||||
/* Protects all parameters, and incidentally kmalloced_param list. */
|
||||
static DEFINE_MUTEX(param_lock);
|
||||
|
||||
/* This just allows us to keep track of which parameters are kmalloced. */
|
||||
struct kmalloced_param {
|
||||
struct list_head list;
|
||||
char val[];
|
||||
};
|
||||
static LIST_HEAD(kmalloced_params);
|
||||
|
||||
static void *kmalloc_parameter(unsigned int size)
|
||||
{
|
||||
struct kmalloced_param *p;
|
||||
|
||||
p = kmalloc(sizeof(*p) + size, GFP_KERNEL);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
list_add(&p->list, &kmalloced_params);
|
||||
return p->val;
|
||||
}
|
||||
|
||||
/* Does nothing if parameter wasn't kmalloced above. */
|
||||
static void maybe_kfree_parameter(void *param)
|
||||
{
|
||||
struct kmalloced_param *p;
|
||||
|
||||
list_for_each_entry(p, &kmalloced_params, list) {
|
||||
if (p->val == param) {
|
||||
list_del(&p->list);
|
||||
kfree(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline char dash2underscore(char c)
|
||||
{
|
||||
if (c == '-')
|
||||
@@ -49,18 +85,25 @@ static inline int parameq(const char *input, const char *paramname)
|
||||
|
||||
static int parse_one(char *param,
|
||||
char *val,
|
||||
struct kernel_param *params,
|
||||
const struct kernel_param *params,
|
||||
unsigned num_params,
|
||||
int (*handle_unknown)(char *param, char *val))
|
||||
{
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
/* Find parameter */
|
||||
for (i = 0; i < num_params; i++) {
|
||||
if (parameq(param, params[i].name)) {
|
||||
/* Noone handled NULL, so do it here. */
|
||||
if (!val && params[i].ops->set != param_set_bool)
|
||||
return -EINVAL;
|
||||
DEBUGP("They are equal! Calling %p\n",
|
||||
params[i].set);
|
||||
return params[i].set(val, ¶ms[i]);
|
||||
params[i].ops->set);
|
||||
mutex_lock(¶m_lock);
|
||||
err = params[i].ops->set(val, ¶ms[i]);
|
||||
mutex_unlock(¶m_lock);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +171,7 @@ 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,
|
||||
char *args,
|
||||
struct kernel_param *params,
|
||||
const struct kernel_param *params,
|
||||
unsigned num,
|
||||
int (*unknown)(char *param, char *val))
|
||||
{
|
||||
@@ -176,22 +219,29 @@ int parse_args(const char *name,
|
||||
|
||||
/* Lazy bastard, eh? */
|
||||
#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \
|
||||
int param_set_##name(const char *val, struct kernel_param *kp) \
|
||||
int param_set_##name(const char *val, const struct kernel_param *kp) \
|
||||
{ \
|
||||
tmptype l; \
|
||||
int ret; \
|
||||
\
|
||||
if (!val) return -EINVAL; \
|
||||
ret = strtolfn(val, 0, &l); \
|
||||
if (ret == -EINVAL || ((type)l != l)) \
|
||||
return -EINVAL; \
|
||||
*((type *)kp->arg) = l; \
|
||||
return 0; \
|
||||
} \
|
||||
int param_get_##name(char *buffer, struct kernel_param *kp) \
|
||||
int param_get_##name(char *buffer, const struct kernel_param *kp) \
|
||||
{ \
|
||||
return sprintf(buffer, format, *((type *)kp->arg)); \
|
||||
}
|
||||
} \
|
||||
struct kernel_param_ops param_ops_##name = { \
|
||||
.set = param_set_##name, \
|
||||
.get = param_get_##name, \
|
||||
}; \
|
||||
EXPORT_SYMBOL(param_set_##name); \
|
||||
EXPORT_SYMBOL(param_get_##name); \
|
||||
EXPORT_SYMBOL(param_ops_##name)
|
||||
|
||||
|
||||
STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, strict_strtoul);
|
||||
STANDARD_PARAM_DEF(short, short, "%hi", long, strict_strtol);
|
||||
@@ -201,39 +251,50 @@ STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, strict_strtoul);
|
||||
STANDARD_PARAM_DEF(long, long, "%li", long, strict_strtol);
|
||||
STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, strict_strtoul);
|
||||
|
||||
int param_set_charp(const char *val, struct kernel_param *kp)
|
||||
int param_set_charp(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
if (!val) {
|
||||
printk(KERN_ERR "%s: string parameter expected\n",
|
||||
kp->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (strlen(val) > 1024) {
|
||||
printk(KERN_ERR "%s: string parameter too long\n",
|
||||
kp->name);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/* This is a hack. We can't need to strdup in early boot, and we
|
||||
maybe_kfree_parameter(*(char **)kp->arg);
|
||||
|
||||
/* This is a hack. We can't kmalloc in early boot, and we
|
||||
* don't need to; this mangled commandline is preserved. */
|
||||
if (slab_is_available()) {
|
||||
*(char **)kp->arg = kstrdup(val, GFP_KERNEL);
|
||||
*(char **)kp->arg = kmalloc_parameter(strlen(val)+1);
|
||||
if (!*(char **)kp->arg)
|
||||
return -ENOMEM;
|
||||
strcpy(*(char **)kp->arg, val);
|
||||
} else
|
||||
*(const char **)kp->arg = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(param_set_charp);
|
||||
|
||||
int param_get_charp(char *buffer, struct kernel_param *kp)
|
||||
int param_get_charp(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
return sprintf(buffer, "%s", *((char **)kp->arg));
|
||||
}
|
||||
EXPORT_SYMBOL(param_get_charp);
|
||||
|
||||
static void param_free_charp(void *arg)
|
||||
{
|
||||
maybe_kfree_parameter(*((char **)arg));
|
||||
}
|
||||
|
||||
struct kernel_param_ops param_ops_charp = {
|
||||
.set = param_set_charp,
|
||||
.get = param_get_charp,
|
||||
.free = param_free_charp,
|
||||
};
|
||||
EXPORT_SYMBOL(param_ops_charp);
|
||||
|
||||
/* Actually could be a bool or an int, for historical reasons. */
|
||||
int param_set_bool(const char *val, struct kernel_param *kp)
|
||||
int param_set_bool(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
bool v;
|
||||
|
||||
@@ -258,8 +319,9 @@ int param_set_bool(const char *val, struct kernel_param *kp)
|
||||
*(int *)kp->arg = v;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(param_set_bool);
|
||||
|
||||
int param_get_bool(char *buffer, struct kernel_param *kp)
|
||||
int param_get_bool(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
bool val;
|
||||
if (kp->flags & KPARAM_ISBOOL)
|
||||
@@ -270,9 +332,16 @@ int param_get_bool(char *buffer, struct kernel_param *kp)
|
||||
/* Y and N chosen as being relatively non-coder friendly */
|
||||
return sprintf(buffer, "%c", val ? 'Y' : 'N');
|
||||
}
|
||||
EXPORT_SYMBOL(param_get_bool);
|
||||
|
||||
struct kernel_param_ops param_ops_bool = {
|
||||
.set = param_set_bool,
|
||||
.get = param_get_bool,
|
||||
};
|
||||
EXPORT_SYMBOL(param_ops_bool);
|
||||
|
||||
/* This one must be bool. */
|
||||
int param_set_invbool(const char *val, struct kernel_param *kp)
|
||||
int param_set_invbool(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
int ret;
|
||||
bool boolval;
|
||||
@@ -285,18 +354,26 @@ int param_set_invbool(const char *val, struct kernel_param *kp)
|
||||
*(bool *)kp->arg = !boolval;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(param_set_invbool);
|
||||
|
||||
int param_get_invbool(char *buffer, struct kernel_param *kp)
|
||||
int param_get_invbool(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y');
|
||||
}
|
||||
EXPORT_SYMBOL(param_get_invbool);
|
||||
|
||||
struct kernel_param_ops param_ops_invbool = {
|
||||
.set = param_set_invbool,
|
||||
.get = param_get_invbool,
|
||||
};
|
||||
EXPORT_SYMBOL(param_ops_invbool);
|
||||
|
||||
/* 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 *, struct kernel_param *kp),
|
||||
int (*set)(const char *, const struct kernel_param *kp),
|
||||
u16 flags,
|
||||
unsigned int *num)
|
||||
{
|
||||
@@ -309,12 +386,6 @@ static int param_array(const char *name,
|
||||
kp.arg = elem;
|
||||
kp.flags = flags;
|
||||
|
||||
/* No equals sign? */
|
||||
if (!val) {
|
||||
printk(KERN_ERR "%s: expects arguments\n", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*num = 0;
|
||||
/* We expect a comma-separated list of values. */
|
||||
do {
|
||||
@@ -330,6 +401,7 @@ static int param_array(const char *name,
|
||||
/* nul-terminate and parse */
|
||||
save = val[len];
|
||||
((char *)val)[len] = '\0';
|
||||
BUG_ON(!mutex_is_locked(¶m_lock));
|
||||
ret = set(val, &kp);
|
||||
|
||||
if (ret != 0)
|
||||
@@ -347,17 +419,17 @@ static int param_array(const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int param_array_set(const char *val, struct kernel_param *kp)
|
||||
static int param_array_set(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
const struct kparam_array *arr = kp->arr;
|
||||
unsigned int temp_num;
|
||||
|
||||
return param_array(kp->name, val, 1, arr->max, arr->elem,
|
||||
arr->elemsize, arr->set, kp->flags,
|
||||
arr->elemsize, arr->ops->set, kp->flags,
|
||||
arr->num ?: &temp_num);
|
||||
}
|
||||
|
||||
int param_array_get(char *buffer, struct kernel_param *kp)
|
||||
static int param_array_get(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
int i, off, ret;
|
||||
const struct kparam_array *arr = kp->arr;
|
||||
@@ -368,7 +440,8 @@ int param_array_get(char *buffer, struct kernel_param *kp)
|
||||
if (i)
|
||||
buffer[off++] = ',';
|
||||
p.arg = arr->elem + arr->elemsize * i;
|
||||
ret = arr->get(buffer + off, &p);
|
||||
BUG_ON(!mutex_is_locked(¶m_lock));
|
||||
ret = arr->ops->get(buffer + off, &p);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
off += ret;
|
||||
@@ -377,14 +450,27 @@ int param_array_get(char *buffer, struct kernel_param *kp)
|
||||
return off;
|
||||
}
|
||||
|
||||
int param_set_copystring(const char *val, struct kernel_param *kp)
|
||||
static void param_array_free(void *arg)
|
||||
{
|
||||
unsigned int i;
|
||||
const struct kparam_array *arr = arg;
|
||||
|
||||
if (arr->ops->free)
|
||||
for (i = 0; i < (arr->num ? *arr->num : arr->max); i++)
|
||||
arr->ops->free(arr->elem + arr->elemsize * i);
|
||||
}
|
||||
|
||||
struct kernel_param_ops param_array_ops = {
|
||||
.set = param_array_set,
|
||||
.get = param_array_get,
|
||||
.free = param_array_free,
|
||||
};
|
||||
EXPORT_SYMBOL(param_array_ops);
|
||||
|
||||
int param_set_copystring(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
const struct kparam_string *kps = kp->str;
|
||||
|
||||
if (!val) {
|
||||
printk(KERN_ERR "%s: missing param set value\n", kp->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (strlen(val)+1 > kps->maxlen) {
|
||||
printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
|
||||
kp->name, kps->maxlen-1);
|
||||
@@ -393,12 +479,20 @@ int param_set_copystring(const char *val, struct kernel_param *kp)
|
||||
strcpy(kps->string, val);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(param_set_copystring);
|
||||
|
||||
int param_get_string(char *buffer, struct kernel_param *kp)
|
||||
int param_get_string(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
const struct kparam_string *kps = kp->str;
|
||||
return strlcpy(buffer, kps->string, kps->maxlen);
|
||||
}
|
||||
EXPORT_SYMBOL(param_get_string);
|
||||
|
||||
struct kernel_param_ops param_ops_string = {
|
||||
.set = param_set_copystring,
|
||||
.get = param_get_string,
|
||||
};
|
||||
EXPORT_SYMBOL(param_ops_string);
|
||||
|
||||
/* sysfs output in /sys/modules/XYZ/parameters/ */
|
||||
#define to_module_attr(n) container_of(n, struct module_attribute, attr)
|
||||
@@ -409,7 +503,7 @@ extern struct kernel_param __start___param[], __stop___param[];
|
||||
struct param_attribute
|
||||
{
|
||||
struct module_attribute mattr;
|
||||
struct kernel_param *param;
|
||||
const struct kernel_param *param;
|
||||
};
|
||||
|
||||
struct module_param_attrs
|
||||
@@ -428,10 +522,12 @@ static ssize_t param_attr_show(struct module_attribute *mattr,
|
||||
int count;
|
||||
struct param_attribute *attribute = to_param_attr(mattr);
|
||||
|
||||
if (!attribute->param->get)
|
||||
if (!attribute->param->ops->get)
|
||||
return -EPERM;
|
||||
|
||||
count = attribute->param->get(buf, attribute->param);
|
||||
mutex_lock(¶m_lock);
|
||||
count = attribute->param->ops->get(buf, attribute->param);
|
||||
mutex_unlock(¶m_lock);
|
||||
if (count > 0) {
|
||||
strcat(buf, "\n");
|
||||
++count;
|
||||
@@ -447,10 +543,12 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
|
||||
int err;
|
||||
struct param_attribute *attribute = to_param_attr(mattr);
|
||||
|
||||
if (!attribute->param->set)
|
||||
if (!attribute->param->ops->set)
|
||||
return -EPERM;
|
||||
|
||||
err = attribute->param->set(buf, attribute->param);
|
||||
mutex_lock(¶m_lock);
|
||||
err = attribute->param->ops->set(buf, attribute->param);
|
||||
mutex_unlock(¶m_lock);
|
||||
if (!err)
|
||||
return len;
|
||||
return err;
|
||||
@@ -464,6 +562,18 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
void __kernel_param_lock(void)
|
||||
{
|
||||
mutex_lock(¶m_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(__kernel_param_lock);
|
||||
|
||||
void __kernel_param_unlock(void)
|
||||
{
|
||||
mutex_unlock(¶m_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(__kernel_param_unlock);
|
||||
|
||||
/*
|
||||
* add_sysfs_param - add a parameter to sysfs
|
||||
* @mk: struct module_kobject
|
||||
@@ -475,7 +585,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
|
||||
* if there's an error.
|
||||
*/
|
||||
static __modinit int add_sysfs_param(struct module_kobject *mk,
|
||||
struct kernel_param *kp,
|
||||
const struct kernel_param *kp,
|
||||
const char *name)
|
||||
{
|
||||
struct module_param_attrs *new;
|
||||
@@ -557,7 +667,7 @@ static void free_module_param_attrs(struct module_kobject *mk)
|
||||
* /sys/module/[mod->name]/parameters/
|
||||
*/
|
||||
int module_param_sysfs_setup(struct module *mod,
|
||||
struct kernel_param *kparam,
|
||||
const struct kernel_param *kparam,
|
||||
unsigned int num_params)
|
||||
{
|
||||
int i, err;
|
||||
@@ -602,7 +712,11 @@ void module_param_sysfs_remove(struct module *mod)
|
||||
|
||||
void destroy_params(const struct kernel_param *params, unsigned num)
|
||||
{
|
||||
/* FIXME: This should free kmalloced charp parameters. It doesn't. */
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
if (params[i].ops->free)
|
||||
params[i].ops->free(params[i].arg);
|
||||
}
|
||||
|
||||
static void __init kernel_add_sysfs_param(const char *name,
|
||||
@@ -768,28 +882,3 @@ static int __init param_sysfs_init(void)
|
||||
subsys_initcall(param_sysfs_init);
|
||||
|
||||
#endif /* CONFIG_SYSFS */
|
||||
|
||||
EXPORT_SYMBOL(param_set_byte);
|
||||
EXPORT_SYMBOL(param_get_byte);
|
||||
EXPORT_SYMBOL(param_set_short);
|
||||
EXPORT_SYMBOL(param_get_short);
|
||||
EXPORT_SYMBOL(param_set_ushort);
|
||||
EXPORT_SYMBOL(param_get_ushort);
|
||||
EXPORT_SYMBOL(param_set_int);
|
||||
EXPORT_SYMBOL(param_get_int);
|
||||
EXPORT_SYMBOL(param_set_uint);
|
||||
EXPORT_SYMBOL(param_get_uint);
|
||||
EXPORT_SYMBOL(param_set_long);
|
||||
EXPORT_SYMBOL(param_get_long);
|
||||
EXPORT_SYMBOL(param_set_ulong);
|
||||
EXPORT_SYMBOL(param_get_ulong);
|
||||
EXPORT_SYMBOL(param_set_charp);
|
||||
EXPORT_SYMBOL(param_get_charp);
|
||||
EXPORT_SYMBOL(param_set_bool);
|
||||
EXPORT_SYMBOL(param_get_bool);
|
||||
EXPORT_SYMBOL(param_set_invbool);
|
||||
EXPORT_SYMBOL(param_get_invbool);
|
||||
EXPORT_SYMBOL(param_array_set);
|
||||
EXPORT_SYMBOL(param_array_get);
|
||||
EXPORT_SYMBOL(param_set_copystring);
|
||||
EXPORT_SYMBOL(param_get_string);
|
||||
|
||||
Reference in New Issue
Block a user