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: Rusty Russell <rusty@rustcorp.com.au> Reviewed-by: Takashi Iwai <tiwai@suse.de> Tested-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
This commit is contained in:
parent
914dcaa84c
commit
907b29eb41
|
@ -130,6 +130,62 @@ __check_old_set_param(int (*oldset)(const char *, struct kernel_param *))
|
||||||
#define module_param(name, type, perm) \
|
#define module_param(name, type, perm) \
|
||||||
module_param_named(name, 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
|
#ifndef MODULE
|
||||||
/**
|
/**
|
||||||
* core_param - define a historical core kernel parameter.
|
* core_param - define a historical core kernel parameter.
|
||||||
|
|
|
@ -31,12 +31,14 @@
|
||||||
#define DEBUGP(fmt, a...)
|
#define DEBUGP(fmt, a...)
|
||||||
#endif
|
#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. */
|
/* This just allows us to keep track of which parameters are kmalloced. */
|
||||||
struct kmalloced_param {
|
struct kmalloced_param {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
char val[];
|
char val[];
|
||||||
};
|
};
|
||||||
static DEFINE_MUTEX(param_lock);
|
|
||||||
static LIST_HEAD(kmalloced_params);
|
static LIST_HEAD(kmalloced_params);
|
||||||
|
|
||||||
static void *kmalloc_parameter(unsigned int size)
|
static void *kmalloc_parameter(unsigned int size)
|
||||||
|
@ -47,10 +49,7 @@ static void *kmalloc_parameter(unsigned int size)
|
||||||
if (!p)
|
if (!p)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
mutex_lock(¶m_lock);
|
|
||||||
list_add(&p->list, &kmalloced_params);
|
list_add(&p->list, &kmalloced_params);
|
||||||
mutex_unlock(¶m_lock);
|
|
||||||
|
|
||||||
return p->val;
|
return p->val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +58,6 @@ static void maybe_kfree_parameter(void *param)
|
||||||
{
|
{
|
||||||
struct kmalloced_param *p;
|
struct kmalloced_param *p;
|
||||||
|
|
||||||
mutex_lock(¶m_lock);
|
|
||||||
list_for_each_entry(p, &kmalloced_params, list) {
|
list_for_each_entry(p, &kmalloced_params, list) {
|
||||||
if (p->val == param) {
|
if (p->val == param) {
|
||||||
list_del(&p->list);
|
list_del(&p->list);
|
||||||
|
@ -67,7 +65,6 @@ static void maybe_kfree_parameter(void *param)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(¶m_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline char dash2underscore(char c)
|
static inline char dash2underscore(char c)
|
||||||
|
@ -93,6 +90,7 @@ static int parse_one(char *param,
|
||||||
int (*handle_unknown)(char *param, char *val))
|
int (*handle_unknown)(char *param, char *val))
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
int err;
|
||||||
|
|
||||||
/* Find parameter */
|
/* Find parameter */
|
||||||
for (i = 0; i < num_params; i++) {
|
for (i = 0; i < num_params; i++) {
|
||||||
|
@ -102,7 +100,10 @@ static int parse_one(char *param,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
DEBUGP("They are equal! Calling %p\n",
|
DEBUGP("They are equal! Calling %p\n",
|
||||||
params[i].ops->set);
|
params[i].ops->set);
|
||||||
return params[i].ops->set(val, ¶ms[i]);
|
mutex_lock(¶m_lock);
|
||||||
|
err = params[i].ops->set(val, ¶ms[i]);
|
||||||
|
mutex_unlock(¶m_lock);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,6 +401,7 @@ static int param_array(const char *name,
|
||||||
/* nul-terminate and parse */
|
/* nul-terminate and parse */
|
||||||
save = val[len];
|
save = val[len];
|
||||||
((char *)val)[len] = '\0';
|
((char *)val)[len] = '\0';
|
||||||
|
BUG_ON(!mutex_is_locked(¶m_lock));
|
||||||
ret = set(val, &kp);
|
ret = set(val, &kp);
|
||||||
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
|
@ -438,6 +440,7 @@ static int param_array_get(char *buffer, const struct kernel_param *kp)
|
||||||
if (i)
|
if (i)
|
||||||
buffer[off++] = ',';
|
buffer[off++] = ',';
|
||||||
p.arg = arr->elem + arr->elemsize * i;
|
p.arg = arr->elem + arr->elemsize * i;
|
||||||
|
BUG_ON(!mutex_is_locked(¶m_lock));
|
||||||
ret = arr->ops->get(buffer + off, &p);
|
ret = arr->ops->get(buffer + off, &p);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -522,7 +525,9 @@ static ssize_t param_attr_show(struct module_attribute *mattr,
|
||||||
if (!attribute->param->ops->get)
|
if (!attribute->param->ops->get)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
|
mutex_lock(¶m_lock);
|
||||||
count = attribute->param->ops->get(buf, attribute->param);
|
count = attribute->param->ops->get(buf, attribute->param);
|
||||||
|
mutex_unlock(¶m_lock);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
strcat(buf, "\n");
|
strcat(buf, "\n");
|
||||||
++count;
|
++count;
|
||||||
|
@ -541,7 +546,9 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
|
||||||
if (!attribute->param->ops->set)
|
if (!attribute->param->ops->set)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
|
mutex_lock(¶m_lock);
|
||||||
err = attribute->param->ops->set(buf, attribute->param);
|
err = attribute->param->ops->set(buf, attribute->param);
|
||||||
|
mutex_unlock(¶m_lock);
|
||||||
if (!err)
|
if (!err)
|
||||||
return len;
|
return len;
|
||||||
return err;
|
return err;
|
||||||
|
@ -555,6 +562,18 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SYSFS
|
#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
|
* add_sysfs_param - add a parameter to sysfs
|
||||||
* @mk: struct module_kobject
|
* @mk: struct module_kobject
|
||||||
|
|
Loading…
Reference in New Issue