Commit 907b29eb authored by Rusty Russell's avatar Rusty Russell

param: locking for kernel parameters

There may be cases (most obviously, sysfs-writable charp parameters) where
a module needs to prevent sysfs access to parameters.

Rather than express this in terms of a big lock, the functions are
expressed in terms of what they protect against.  This is clearer, esp.
if the implementation changes to a module-level or even param-level lock.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Reviewed-by: default avatarTakashi Iwai <tiwai@suse.de>
Tested-by: default avatarPhil Carmody <ext-phil.2.carmody@nokia.com>
parent 914dcaa8
......@@ -130,6 +130,62 @@ __check_old_set_param(int (*oldset)(const char *, struct kernel_param *))
#define module_param(name, type, perm) \
module_param_named(name, name, type, perm)
/**
* kparam_block_sysfs_write - make sure a parameter isn't written via sysfs.
* @name: the name of the parameter
*
* There's no point blocking write on a paramter that isn't writable via sysfs!
*/
#define kparam_block_sysfs_write(name) \
do { \
BUG_ON(!(__param_##name.perm & 0222)); \
__kernel_param_lock(); \
} while (0)
/**
* kparam_unblock_sysfs_write - allows sysfs to write to a parameter again.
* @name: the name of the parameter
*/
#define kparam_unblock_sysfs_write(name) \
do { \
BUG_ON(!(__param_##name.perm & 0222)); \
__kernel_param_unlock(); \
} while (0)
/**
* kparam_block_sysfs_read - make sure a parameter isn't read via sysfs.
* @name: the name of the parameter
*
* This also blocks sysfs writes.
*/
#define kparam_block_sysfs_read(name) \
do { \
BUG_ON(!(__param_##name.perm & 0444)); \
__kernel_param_lock(); \
} while (0)
/**
* kparam_unblock_sysfs_read - allows sysfs to read a parameter again.
* @name: the name of the parameter
*/
#define kparam_unblock_sysfs_read(name) \
do { \
BUG_ON(!(__param_##name.perm & 0444)); \
__kernel_param_unlock(); \
} while (0)
#ifdef CONFIG_SYSFS
extern void __kernel_param_lock(void);
extern void __kernel_param_unlock(void);
#else
static inline void __kernel_param_lock(void)
{
}
static inline void __kernel_param_unlock(void)
{
}
#endif
#ifndef MODULE
/**
* core_param - define a historical core kernel parameter.
......
......@@ -31,12 +31,14 @@
#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 DEFINE_MUTEX(param_lock);
static LIST_HEAD(kmalloced_params);
static void *kmalloc_parameter(unsigned int size)
......@@ -47,10 +49,7 @@ static void *kmalloc_parameter(unsigned int size)
if (!p)
return NULL;
mutex_lock(&param_lock);
list_add(&p->list, &kmalloced_params);
mutex_unlock(&param_lock);
return p->val;
}
......@@ -59,7 +58,6 @@ static void maybe_kfree_parameter(void *param)
{
struct kmalloced_param *p;
mutex_lock(&param_lock);
list_for_each_entry(p, &kmalloced_params, list) {
if (p->val == param) {
list_del(&p->list);
......@@ -67,7 +65,6 @@ static void maybe_kfree_parameter(void *param)
break;
}
}
mutex_unlock(&param_lock);
}
static inline char dash2underscore(char c)
......@@ -93,6 +90,7 @@ static int parse_one(char *param,
int (*handle_unknown)(char *param, char *val))
{
unsigned int i;
int err;
/* Find parameter */
for (i = 0; i < num_params; i++) {
......@@ -102,7 +100,10 @@ static int parse_one(char *param,
return -EINVAL;
DEBUGP("They are equal! Calling %p\n",
params[i].ops->set);
return params[i].ops->set(val, &params[i]);
mutex_lock(&param_lock);
err = params[i].ops->set(val, &params[i]);
mutex_unlock(&param_lock);
return err;
}
}
......@@ -400,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(&param_lock));
ret = set(val, &kp);
if (ret != 0)
......@@ -438,6 +440,7 @@ static int param_array_get(char *buffer, const struct kernel_param *kp)
if (i)
buffer[off++] = ',';
p.arg = arr->elem + arr->elemsize * i;
BUG_ON(!mutex_is_locked(&param_lock));
ret = arr->ops->get(buffer + off, &p);
if (ret < 0)
return ret;
......@@ -522,7 +525,9 @@ static ssize_t param_attr_show(struct module_attribute *mattr,
if (!attribute->param->ops->get)
return -EPERM;
mutex_lock(&param_lock);
count = attribute->param->ops->get(buf, attribute->param);
mutex_unlock(&param_lock);
if (count > 0) {
strcat(buf, "\n");
++count;
......@@ -541,7 +546,9 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
if (!attribute->param->ops->set)
return -EPERM;
mutex_lock(&param_lock);
err = attribute->param->ops->set(buf, attribute->param);
mutex_unlock(&param_lock);
if (!err)
return len;
return err;
......@@ -555,6 +562,18 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
#endif
#ifdef CONFIG_SYSFS
void __kernel_param_lock(void)
{
mutex_lock(&param_lock);
}
EXPORT_SYMBOL(__kernel_param_lock);
void __kernel_param_unlock(void)
{
mutex_unlock(&param_lock);
}
EXPORT_SYMBOL(__kernel_param_unlock);
/*
* add_sysfs_param - add a parameter to sysfs
* @mk: struct module_kobject
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment