mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
Merge tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux
Pull module updates from Rusty Russell: "Main excitement here is Peter Zijlstra's lockless rbtree optimization to speed module address lookup. He found some abusers of the module lock doing that too. A little bit of parameter work here too; including Dan Streetman's breaking up the big param mutex so writing a parameter can load another module (yeah, really). Unfortunately that broke the usual suspects, !CONFIG_MODULES and !CONFIG_SYSFS, so those fixes were appended too" * tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: (26 commits) modules: only use mod->param_lock if CONFIG_MODULES param: fix module param locks when !CONFIG_SYSFS. rcu: merge fix for Convert ACCESS_ONCE() to READ_ONCE() and WRITE_ONCE() module: add per-module param_lock module: make perm const params: suppress unused variable error, warn once just in case code changes. modules: clarify CONFIG_MODULE_COMPRESS help, suggest 'N'. kernel/module.c: avoid ifdefs for sig_enforce declaration kernel/workqueue.c: remove ifdefs over wq_power_efficient kernel/params.c: export param_ops_bool_enable_only kernel/params.c: generalize bool_enable_only kernel/module.c: use generic module param operaters for sig_enforce kernel/params: constify struct kernel_param_ops uses sysfs: tightened sysfs permission checks module: Rework module_addr_{min,max} module: Use __module_address() for module_address_lookup() module: Make the mod_tree stuff conditional on PERF_EVENTS || TRACING module: Optimize __module_address() using a latched RB-tree rbtree: Implement generic latch_tree seqlock: Introduce raw_read_seqcount_latch() ...
This commit is contained in:
116
kernel/params.c
116
kernel/params.c
@@ -25,15 +25,34 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
/* Protects all parameters, and incidentally kmalloced_param list. */
|
||||
#ifdef CONFIG_SYSFS
|
||||
/* Protects all built-in parameters, modules use their own param_lock */
|
||||
static DEFINE_MUTEX(param_lock);
|
||||
|
||||
/* Use the module's mutex, or if built-in use the built-in mutex */
|
||||
#ifdef CONFIG_MODULES
|
||||
#define KPARAM_MUTEX(mod) ((mod) ? &(mod)->param_lock : ¶m_lock)
|
||||
#else
|
||||
#define KPARAM_MUTEX(mod) (¶m_lock)
|
||||
#endif
|
||||
|
||||
static inline void check_kparam_locked(struct module *mod)
|
||||
{
|
||||
BUG_ON(!mutex_is_locked(KPARAM_MUTEX(mod)));
|
||||
}
|
||||
#else
|
||||
static inline void check_kparam_locked(struct module *mod)
|
||||
{
|
||||
}
|
||||
#endif /* !CONFIG_SYSFS */
|
||||
|
||||
/* 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 DEFINE_SPINLOCK(kmalloced_params_lock);
|
||||
|
||||
static void *kmalloc_parameter(unsigned int size)
|
||||
{
|
||||
@@ -43,7 +62,10 @@ static void *kmalloc_parameter(unsigned int size)
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
spin_lock(&kmalloced_params_lock);
|
||||
list_add(&p->list, &kmalloced_params);
|
||||
spin_unlock(&kmalloced_params_lock);
|
||||
|
||||
return p->val;
|
||||
}
|
||||
|
||||
@@ -52,6 +74,7 @@ static void maybe_kfree_parameter(void *param)
|
||||
{
|
||||
struct kmalloced_param *p;
|
||||
|
||||
spin_lock(&kmalloced_params_lock);
|
||||
list_for_each_entry(p, &kmalloced_params, list) {
|
||||
if (p->val == param) {
|
||||
list_del(&p->list);
|
||||
@@ -59,6 +82,7 @@ static void maybe_kfree_parameter(void *param)
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&kmalloced_params_lock);
|
||||
}
|
||||
|
||||
static char dash2underscore(char c)
|
||||
@@ -119,10 +143,10 @@ static int parse_one(char *param,
|
||||
return -EINVAL;
|
||||
pr_debug("handling %s with %p\n", param,
|
||||
params[i].ops->set);
|
||||
mutex_lock(¶m_lock);
|
||||
kernel_param_lock(params[i].mod);
|
||||
param_check_unsafe(¶ms[i]);
|
||||
err = params[i].ops->set(val, ¶ms[i]);
|
||||
mutex_unlock(¶m_lock);
|
||||
kernel_param_unlock(params[i].mod);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
@@ -254,7 +278,7 @@ char *parse_args(const char *doing,
|
||||
return scnprintf(buffer, PAGE_SIZE, format, \
|
||||
*((type *)kp->arg)); \
|
||||
} \
|
||||
struct kernel_param_ops param_ops_##name = { \
|
||||
const struct kernel_param_ops param_ops_##name = { \
|
||||
.set = param_set_##name, \
|
||||
.get = param_get_##name, \
|
||||
}; \
|
||||
@@ -306,7 +330,7 @@ static void param_free_charp(void *arg)
|
||||
maybe_kfree_parameter(*((char **)arg));
|
||||
}
|
||||
|
||||
struct kernel_param_ops param_ops_charp = {
|
||||
const struct kernel_param_ops param_ops_charp = {
|
||||
.set = param_set_charp,
|
||||
.get = param_get_charp,
|
||||
.free = param_free_charp,
|
||||
@@ -331,13 +355,44 @@ int param_get_bool(char *buffer, const struct kernel_param *kp)
|
||||
}
|
||||
EXPORT_SYMBOL(param_get_bool);
|
||||
|
||||
struct kernel_param_ops param_ops_bool = {
|
||||
const struct kernel_param_ops param_ops_bool = {
|
||||
.flags = KERNEL_PARAM_OPS_FL_NOARG,
|
||||
.set = param_set_bool,
|
||||
.get = param_get_bool,
|
||||
};
|
||||
EXPORT_SYMBOL(param_ops_bool);
|
||||
|
||||
int param_set_bool_enable_only(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
int err = 0;
|
||||
bool new_value;
|
||||
bool orig_value = *(bool *)kp->arg;
|
||||
struct kernel_param dummy_kp = *kp;
|
||||
|
||||
dummy_kp.arg = &new_value;
|
||||
|
||||
err = param_set_bool(val, &dummy_kp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Don't let them unset it once it's set! */
|
||||
if (!new_value && orig_value)
|
||||
return -EROFS;
|
||||
|
||||
if (new_value)
|
||||
err = param_set_bool(val, kp);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(param_set_bool_enable_only);
|
||||
|
||||
const struct kernel_param_ops param_ops_bool_enable_only = {
|
||||
.flags = KERNEL_PARAM_OPS_FL_NOARG,
|
||||
.set = param_set_bool_enable_only,
|
||||
.get = param_get_bool,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(param_ops_bool_enable_only);
|
||||
|
||||
/* This one must be bool. */
|
||||
int param_set_invbool(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
@@ -359,7 +414,7 @@ int param_get_invbool(char *buffer, const struct kernel_param *kp)
|
||||
}
|
||||
EXPORT_SYMBOL(param_get_invbool);
|
||||
|
||||
struct kernel_param_ops param_ops_invbool = {
|
||||
const struct kernel_param_ops param_ops_invbool = {
|
||||
.set = param_set_invbool,
|
||||
.get = param_get_invbool,
|
||||
};
|
||||
@@ -367,12 +422,11 @@ EXPORT_SYMBOL(param_ops_invbool);
|
||||
|
||||
int param_set_bint(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
struct kernel_param boolkp;
|
||||
/* Match bool exactly, by re-using it. */
|
||||
struct kernel_param boolkp = *kp;
|
||||
bool v;
|
||||
int ret;
|
||||
|
||||
/* Match bool exactly, by re-using it. */
|
||||
boolkp = *kp;
|
||||
boolkp.arg = &v;
|
||||
|
||||
ret = param_set_bool(val, &boolkp);
|
||||
@@ -382,7 +436,7 @@ int param_set_bint(const char *val, const struct kernel_param *kp)
|
||||
}
|
||||
EXPORT_SYMBOL(param_set_bint);
|
||||
|
||||
struct kernel_param_ops param_ops_bint = {
|
||||
const struct kernel_param_ops param_ops_bint = {
|
||||
.flags = KERNEL_PARAM_OPS_FL_NOARG,
|
||||
.set = param_set_bint,
|
||||
.get = param_get_int,
|
||||
@@ -390,7 +444,8 @@ struct kernel_param_ops param_ops_bint = {
|
||||
EXPORT_SYMBOL(param_ops_bint);
|
||||
|
||||
/* We break the rule and mangle the string. */
|
||||
static int param_array(const char *name,
|
||||
static int param_array(struct module *mod,
|
||||
const char *name,
|
||||
const char *val,
|
||||
unsigned int min, unsigned int max,
|
||||
void *elem, int elemsize,
|
||||
@@ -421,7 +476,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));
|
||||
check_kparam_locked(mod);
|
||||
ret = set(val, &kp);
|
||||
|
||||
if (ret != 0)
|
||||
@@ -443,7 +498,7 @@ 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,
|
||||
return param_array(kp->mod, kp->name, val, 1, arr->max, arr->elem,
|
||||
arr->elemsize, arr->ops->set, kp->level,
|
||||
arr->num ?: &temp_num);
|
||||
}
|
||||
@@ -452,14 +507,13 @@ static int param_array_get(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
int i, off, ret;
|
||||
const struct kparam_array *arr = kp->arr;
|
||||
struct kernel_param p;
|
||||
struct kernel_param p = *kp;
|
||||
|
||||
p = *kp;
|
||||
for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) {
|
||||
if (i)
|
||||
buffer[off++] = ',';
|
||||
p.arg = arr->elem + arr->elemsize * i;
|
||||
BUG_ON(!mutex_is_locked(¶m_lock));
|
||||
check_kparam_locked(p.mod);
|
||||
ret = arr->ops->get(buffer + off, &p);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -479,7 +533,7 @@ static void param_array_free(void *arg)
|
||||
arr->ops->free(arr->elem + arr->elemsize * i);
|
||||
}
|
||||
|
||||
struct kernel_param_ops param_array_ops = {
|
||||
const struct kernel_param_ops param_array_ops = {
|
||||
.set = param_array_set,
|
||||
.get = param_array_get,
|
||||
.free = param_array_free,
|
||||
@@ -507,7 +561,7 @@ int param_get_string(char *buffer, const struct kernel_param *kp)
|
||||
}
|
||||
EXPORT_SYMBOL(param_get_string);
|
||||
|
||||
struct kernel_param_ops param_ops_string = {
|
||||
const struct kernel_param_ops param_ops_string = {
|
||||
.set = param_set_copystring,
|
||||
.get = param_get_string,
|
||||
};
|
||||
@@ -542,9 +596,9 @@ static ssize_t param_attr_show(struct module_attribute *mattr,
|
||||
if (!attribute->param->ops->get)
|
||||
return -EPERM;
|
||||
|
||||
mutex_lock(¶m_lock);
|
||||
kernel_param_lock(mk->mod);
|
||||
count = attribute->param->ops->get(buf, attribute->param);
|
||||
mutex_unlock(¶m_lock);
|
||||
kernel_param_unlock(mk->mod);
|
||||
if (count > 0) {
|
||||
strcat(buf, "\n");
|
||||
++count;
|
||||
@@ -554,7 +608,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_kobject *km,
|
||||
struct module_kobject *mk,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
int err;
|
||||
@@ -563,10 +617,10 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
|
||||
if (!attribute->param->ops->set)
|
||||
return -EPERM;
|
||||
|
||||
mutex_lock(¶m_lock);
|
||||
kernel_param_lock(mk->mod);
|
||||
param_check_unsafe(attribute->param);
|
||||
err = attribute->param->ops->set(buf, attribute->param);
|
||||
mutex_unlock(¶m_lock);
|
||||
kernel_param_unlock(mk->mod);
|
||||
if (!err)
|
||||
return len;
|
||||
return err;
|
||||
@@ -580,17 +634,18 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
void __kernel_param_lock(void)
|
||||
void kernel_param_lock(struct module *mod)
|
||||
{
|
||||
mutex_lock(¶m_lock);
|
||||
mutex_lock(KPARAM_MUTEX(mod));
|
||||
}
|
||||
EXPORT_SYMBOL(__kernel_param_lock);
|
||||
|
||||
void __kernel_param_unlock(void)
|
||||
void kernel_param_unlock(struct module *mod)
|
||||
{
|
||||
mutex_unlock(¶m_lock);
|
||||
mutex_unlock(KPARAM_MUTEX(mod));
|
||||
}
|
||||
EXPORT_SYMBOL(__kernel_param_unlock);
|
||||
|
||||
EXPORT_SYMBOL(kernel_param_lock);
|
||||
EXPORT_SYMBOL(kernel_param_unlock);
|
||||
|
||||
/*
|
||||
* add_sysfs_param - add a parameter to sysfs
|
||||
@@ -856,6 +911,7 @@ static void __init version_sysfs_builtin(void)
|
||||
mk = locate_module_kobject(vattr->module_name);
|
||||
if (mk) {
|
||||
err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
|
||||
WARN_ON_ONCE(err);
|
||||
kobject_uevent(&mk->kobj, KOBJ_ADD);
|
||||
kobject_put(&mk->kobj);
|
||||
}
|
||||
|
Reference in New Issue
Block a user