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:
Родитель
914dcaa84c
Коммит
907b29eb41
|
@ -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(¶m_lock);
|
||||
list_add(&p->list, &kmalloced_params);
|
||||
mutex_unlock(¶m_lock);
|
||||
|
||||
return p->val;
|
||||
}
|
||||
|
||||
|
@ -59,7 +58,6 @@ static void maybe_kfree_parameter(void *param)
|
|||
{
|
||||
struct kmalloced_param *p;
|
||||
|
||||
mutex_lock(¶m_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(¶m_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, ¶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 */
|
||||
save = val[len];
|
||||
((char *)val)[len] = '\0';
|
||||
BUG_ON(!mutex_is_locked(¶m_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(¶m_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(¶m_lock);
|
||||
count = attribute->param->ops->get(buf, attribute->param);
|
||||
mutex_unlock(¶m_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(¶m_lock);
|
||||
err = attribute->param->ops->set(buf, attribute->param);
|
||||
mutex_unlock(¶m_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(¶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
|
||||
|
|
Загрузка…
Ссылка в новой задаче