Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus: stop_machine: fix error code handling on multiple cpus stop_machine: use workqueues instead of kernel threads workqueue: introduce create_rt_workqueue Call init_workqueues before pre smp initcalls. Make panic= and panic_on_oops into core_params Make initcall_debug a core_param core_param() for genuinely core kernel parameters param: Fix duplicate module prefixes module: check kernel param length at compile time, not runtime Remove stop_machine during module load v2 module: simplify load_module.
This commit is contained in:
Коммит
a534487606
|
@ -29,7 +29,7 @@
|
||||||
#define MODULE_SYMBOL_PREFIX ""
|
#define MODULE_SYMBOL_PREFIX ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MODULE_NAME_LEN (64 - sizeof(unsigned long))
|
#define MODULE_NAME_LEN MAX_PARAM_PREFIX_LEN
|
||||||
|
|
||||||
struct kernel_symbol
|
struct kernel_symbol
|
||||||
{
|
{
|
||||||
|
@ -60,6 +60,7 @@ struct module_kobject
|
||||||
struct kobject kobj;
|
struct kobject kobj;
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
struct kobject *drivers_dir;
|
struct kobject *drivers_dir;
|
||||||
|
struct module_param_attrs *mp;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* These are either module local, or the kernel's dummy ones. */
|
/* These are either module local, or the kernel's dummy ones. */
|
||||||
|
@ -242,7 +243,6 @@ struct module
|
||||||
|
|
||||||
/* Sysfs stuff. */
|
/* Sysfs stuff. */
|
||||||
struct module_kobject mkobj;
|
struct module_kobject mkobj;
|
||||||
struct module_param_attrs *param_attrs;
|
|
||||||
struct module_attribute *modinfo_attrs;
|
struct module_attribute *modinfo_attrs;
|
||||||
const char *version;
|
const char *version;
|
||||||
const char *srcversion;
|
const char *srcversion;
|
||||||
|
@ -277,7 +277,7 @@ struct module
|
||||||
|
|
||||||
/* Exception table */
|
/* Exception table */
|
||||||
unsigned int num_exentries;
|
unsigned int num_exentries;
|
||||||
const struct exception_table_entry *extable;
|
struct exception_table_entry *extable;
|
||||||
|
|
||||||
/* Startup function. */
|
/* Startup function. */
|
||||||
int (*init)(void);
|
int (*init)(void);
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
#define MODULE_PARAM_PREFIX KBUILD_MODNAME "."
|
#define MODULE_PARAM_PREFIX KBUILD_MODNAME "."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Chosen so that structs with an unsigned long line up. */
|
||||||
|
#define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
|
||||||
|
|
||||||
#ifdef MODULE
|
#ifdef MODULE
|
||||||
#define ___module_cat(a,b) __mod_ ## a ## b
|
#define ___module_cat(a,b) __mod_ ## a ## b
|
||||||
#define __module_cat(a,b) ___module_cat(a,b)
|
#define __module_cat(a,b) ___module_cat(a,b)
|
||||||
|
@ -79,7 +82,8 @@ struct kparam_array
|
||||||
#define __module_param_call(prefix, name, set, get, arg, perm) \
|
#define __module_param_call(prefix, name, set, get, arg, perm) \
|
||||||
/* Default value instead of permissions? */ \
|
/* Default value instead of permissions? */ \
|
||||||
static int __param_perm_check_##name __attribute__((unused)) = \
|
static int __param_perm_check_##name __attribute__((unused)) = \
|
||||||
BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)); \
|
BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)) \
|
||||||
|
+ BUILD_BUG_ON_ZERO(sizeof(""prefix) > MAX_PARAM_PREFIX_LEN); \
|
||||||
static const char __param_str_##name[] = prefix #name; \
|
static const char __param_str_##name[] = prefix #name; \
|
||||||
static struct kernel_param __moduleparam_const __param_##name \
|
static struct kernel_param __moduleparam_const __param_##name \
|
||||||
__used \
|
__used \
|
||||||
|
@ -100,6 +104,25 @@ struct kparam_array
|
||||||
#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)
|
||||||
|
|
||||||
|
#ifndef MODULE
|
||||||
|
/**
|
||||||
|
* core_param - define a historical core kernel parameter.
|
||||||
|
* @name: the name of the cmdline and sysfs parameter (often the same as var)
|
||||||
|
* @var: the variable
|
||||||
|
* @type: the type (for param_set_##type and param_get_##type)
|
||||||
|
* @perm: visibility in sysfs
|
||||||
|
*
|
||||||
|
* core_param is just like module_param(), but cannot be modular and
|
||||||
|
* doesn't add a prefix (such as "printk."). This is for compatibility
|
||||||
|
* with __setup(), and it makes sense as truly core parameters aren't
|
||||||
|
* tied to the particular file they're in.
|
||||||
|
*/
|
||||||
|
#define core_param(name, var, type, perm) \
|
||||||
|
param_check_##type(name, &(var)); \
|
||||||
|
__module_param_call("", name, param_set_##type, param_get_##type, \
|
||||||
|
&var, perm)
|
||||||
|
#endif /* !MODULE */
|
||||||
|
|
||||||
/* Actually copy string: maxlen param is usually sizeof(string). */
|
/* Actually copy string: maxlen param is usually sizeof(string). */
|
||||||
#define module_param_string(name, string, len, perm) \
|
#define module_param_string(name, string, len, perm) \
|
||||||
static const struct kparam_string __param_string_##name \
|
static const struct kparam_string __param_string_##name \
|
||||||
|
|
|
@ -149,11 +149,11 @@ struct execute_work {
|
||||||
|
|
||||||
extern struct workqueue_struct *
|
extern struct workqueue_struct *
|
||||||
__create_workqueue_key(const char *name, int singlethread,
|
__create_workqueue_key(const char *name, int singlethread,
|
||||||
int freezeable, struct lock_class_key *key,
|
int freezeable, int rt, struct lock_class_key *key,
|
||||||
const char *lock_name);
|
const char *lock_name);
|
||||||
|
|
||||||
#ifdef CONFIG_LOCKDEP
|
#ifdef CONFIG_LOCKDEP
|
||||||
#define __create_workqueue(name, singlethread, freezeable) \
|
#define __create_workqueue(name, singlethread, freezeable, rt) \
|
||||||
({ \
|
({ \
|
||||||
static struct lock_class_key __key; \
|
static struct lock_class_key __key; \
|
||||||
const char *__lock_name; \
|
const char *__lock_name; \
|
||||||
|
@ -164,17 +164,19 @@ __create_workqueue_key(const char *name, int singlethread,
|
||||||
__lock_name = #name; \
|
__lock_name = #name; \
|
||||||
\
|
\
|
||||||
__create_workqueue_key((name), (singlethread), \
|
__create_workqueue_key((name), (singlethread), \
|
||||||
(freezeable), &__key, \
|
(freezeable), (rt), &__key, \
|
||||||
__lock_name); \
|
__lock_name); \
|
||||||
})
|
})
|
||||||
#else
|
#else
|
||||||
#define __create_workqueue(name, singlethread, freezeable) \
|
#define __create_workqueue(name, singlethread, freezeable, rt) \
|
||||||
__create_workqueue_key((name), (singlethread), (freezeable), NULL, NULL)
|
__create_workqueue_key((name), (singlethread), (freezeable), (rt), \
|
||||||
|
NULL, NULL)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define create_workqueue(name) __create_workqueue((name), 0, 0)
|
#define create_workqueue(name) __create_workqueue((name), 0, 0, 0)
|
||||||
#define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1)
|
#define create_rt_workqueue(name) __create_workqueue((name), 0, 0, 1)
|
||||||
#define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0)
|
#define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1, 0)
|
||||||
|
#define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0, 0)
|
||||||
|
|
||||||
extern void destroy_workqueue(struct workqueue_struct *wq);
|
extern void destroy_workqueue(struct workqueue_struct *wq);
|
||||||
|
|
||||||
|
|
12
init/main.c
12
init/main.c
|
@ -699,13 +699,7 @@ asmlinkage void __init start_kernel(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int initcall_debug;
|
static int initcall_debug;
|
||||||
|
core_param(initcall_debug, initcall_debug, bool, 0644);
|
||||||
static int __init initcall_debug_setup(char *str)
|
|
||||||
{
|
|
||||||
initcall_debug = 1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
__setup("initcall_debug", initcall_debug_setup);
|
|
||||||
|
|
||||||
int do_one_initcall(initcall_t fn)
|
int do_one_initcall(initcall_t fn)
|
||||||
{
|
{
|
||||||
|
@ -775,8 +769,6 @@ static void __init do_initcalls(void)
|
||||||
static void __init do_basic_setup(void)
|
static void __init do_basic_setup(void)
|
||||||
{
|
{
|
||||||
rcu_init_sched(); /* needed by module_init stage. */
|
rcu_init_sched(); /* needed by module_init stage. */
|
||||||
/* drivers will send hotplug events */
|
|
||||||
init_workqueues();
|
|
||||||
usermodehelper_init();
|
usermodehelper_init();
|
||||||
driver_init();
|
driver_init();
|
||||||
init_irq_proc();
|
init_irq_proc();
|
||||||
|
@ -860,6 +852,8 @@ static int __init kernel_init(void * unused)
|
||||||
|
|
||||||
cad_pid = task_pid(current);
|
cad_pid = task_pid(current);
|
||||||
|
|
||||||
|
init_workqueues();
|
||||||
|
|
||||||
smp_prepare_cpus(setup_max_cpus);
|
smp_prepare_cpus(setup_max_cpus);
|
||||||
|
|
||||||
do_pre_smp_initcalls();
|
do_pre_smp_initcalls();
|
||||||
|
|
282
kernel/module.c
282
kernel/module.c
|
@ -42,6 +42,7 @@
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/unwind.h>
|
#include <linux/unwind.h>
|
||||||
|
#include <linux/rculist.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
#include <linux/license.h>
|
#include <linux/license.h>
|
||||||
|
@ -63,7 +64,7 @@
|
||||||
#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
|
#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
|
||||||
|
|
||||||
/* List of modules, protected by module_mutex or preempt_disable
|
/* List of modules, protected by module_mutex or preempt_disable
|
||||||
* (add/delete uses stop_machine). */
|
* (delete uses stop_machine/add uses RCU list operations). */
|
||||||
static DEFINE_MUTEX(module_mutex);
|
static DEFINE_MUTEX(module_mutex);
|
||||||
static LIST_HEAD(modules);
|
static LIST_HEAD(modules);
|
||||||
|
|
||||||
|
@ -132,6 +133,29 @@ static unsigned int find_sec(Elf_Ehdr *hdr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find a module section, or NULL. */
|
||||||
|
static void *section_addr(Elf_Ehdr *hdr, Elf_Shdr *shdrs,
|
||||||
|
const char *secstrings, const char *name)
|
||||||
|
{
|
||||||
|
/* Section 0 has sh_addr 0. */
|
||||||
|
return (void *)shdrs[find_sec(hdr, shdrs, secstrings, name)].sh_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find a module section, or NULL. Fill in number of "objects" in section. */
|
||||||
|
static void *section_objs(Elf_Ehdr *hdr,
|
||||||
|
Elf_Shdr *sechdrs,
|
||||||
|
const char *secstrings,
|
||||||
|
const char *name,
|
||||||
|
size_t object_size,
|
||||||
|
unsigned int *num)
|
||||||
|
{
|
||||||
|
unsigned int sec = find_sec(hdr, sechdrs, secstrings, name);
|
||||||
|
|
||||||
|
/* Section 0 has sh_addr 0 and sh_size 0. */
|
||||||
|
*num = sechdrs[sec].sh_size / object_size;
|
||||||
|
return (void *)sechdrs[sec].sh_addr;
|
||||||
|
}
|
||||||
|
|
||||||
/* Provided by the linker */
|
/* Provided by the linker */
|
||||||
extern const struct kernel_symbol __start___ksymtab[];
|
extern const struct kernel_symbol __start___ksymtab[];
|
||||||
extern const struct kernel_symbol __stop___ksymtab[];
|
extern const struct kernel_symbol __stop___ksymtab[];
|
||||||
|
@ -218,7 +242,7 @@ static bool each_symbol(bool (*fn)(const struct symsearch *arr,
|
||||||
if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data))
|
if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
list_for_each_entry(mod, &modules, list) {
|
list_for_each_entry_rcu(mod, &modules, list) {
|
||||||
struct symsearch arr[] = {
|
struct symsearch arr[] = {
|
||||||
{ mod->syms, mod->syms + mod->num_syms, mod->crcs,
|
{ mod->syms, mod->syms + mod->num_syms, mod->crcs,
|
||||||
NOT_GPL_ONLY, false },
|
NOT_GPL_ONLY, false },
|
||||||
|
@ -1393,17 +1417,6 @@ static void mod_kobject_remove(struct module *mod)
|
||||||
mod_sysfs_fini(mod);
|
mod_sysfs_fini(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* link the module with the whole machine is stopped with interrupts off
|
|
||||||
* - this defends against kallsyms not taking locks
|
|
||||||
*/
|
|
||||||
static int __link_module(void *_mod)
|
|
||||||
{
|
|
||||||
struct module *mod = _mod;
|
|
||||||
list_add(&mod->list, &modules);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* unlink the module with the whole machine is stopped with interrupts off
|
* unlink the module with the whole machine is stopped with interrupts off
|
||||||
* - this defends against kallsyms not taking locks
|
* - this defends against kallsyms not taking locks
|
||||||
|
@ -1789,32 +1802,20 @@ static inline void add_kallsyms(struct module *mod,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_KALLSYMS */
|
#endif /* CONFIG_KALLSYMS */
|
||||||
|
|
||||||
|
static void dynamic_printk_setup(struct mod_debug *debug, unsigned int num)
|
||||||
|
{
|
||||||
#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
|
#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
|
||||||
static void dynamic_printk_setup(Elf_Shdr *sechdrs, unsigned int verboseindex)
|
unsigned int i;
|
||||||
{
|
|
||||||
struct mod_debug *debug_info;
|
|
||||||
unsigned long pos, end;
|
|
||||||
unsigned int num_verbose;
|
|
||||||
|
|
||||||
pos = sechdrs[verboseindex].sh_addr;
|
for (i = 0; i < num; i++) {
|
||||||
num_verbose = sechdrs[verboseindex].sh_size /
|
register_dynamic_debug_module(debug[i].modname,
|
||||||
sizeof(struct mod_debug);
|
debug[i].type,
|
||||||
end = pos + (num_verbose * sizeof(struct mod_debug));
|
debug[i].logical_modname,
|
||||||
|
debug[i].flag_names,
|
||||||
for (; pos < end; pos += sizeof(struct mod_debug)) {
|
debug[i].hash, debug[i].hash2);
|
||||||
debug_info = (struct mod_debug *)pos;
|
|
||||||
register_dynamic_debug_module(debug_info->modname,
|
|
||||||
debug_info->type, debug_info->logical_modname,
|
|
||||||
debug_info->flag_names, debug_info->hash,
|
|
||||||
debug_info->hash2);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#else
|
|
||||||
static inline void dynamic_printk_setup(Elf_Shdr *sechdrs,
|
|
||||||
unsigned int verboseindex)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */
|
#endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */
|
||||||
|
}
|
||||||
|
|
||||||
static void *module_alloc_update_bounds(unsigned long size)
|
static void *module_alloc_update_bounds(unsigned long size)
|
||||||
{
|
{
|
||||||
|
@ -1843,37 +1844,14 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unsigned int symindex = 0;
|
unsigned int symindex = 0;
|
||||||
unsigned int strindex = 0;
|
unsigned int strindex = 0;
|
||||||
unsigned int setupindex;
|
unsigned int modindex, versindex, infoindex, pcpuindex;
|
||||||
unsigned int exindex;
|
|
||||||
unsigned int exportindex;
|
|
||||||
unsigned int modindex;
|
|
||||||
unsigned int obsparmindex;
|
|
||||||
unsigned int infoindex;
|
|
||||||
unsigned int gplindex;
|
|
||||||
unsigned int crcindex;
|
|
||||||
unsigned int gplcrcindex;
|
|
||||||
unsigned int versindex;
|
|
||||||
unsigned int pcpuindex;
|
|
||||||
unsigned int gplfutureindex;
|
|
||||||
unsigned int gplfuturecrcindex;
|
|
||||||
unsigned int unwindex = 0;
|
unsigned int unwindex = 0;
|
||||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
unsigned int num_kp, num_mcount;
|
||||||
unsigned int unusedindex;
|
struct kernel_param *kp;
|
||||||
unsigned int unusedcrcindex;
|
|
||||||
unsigned int unusedgplindex;
|
|
||||||
unsigned int unusedgplcrcindex;
|
|
||||||
#endif
|
|
||||||
unsigned int markersindex;
|
|
||||||
unsigned int markersstringsindex;
|
|
||||||
unsigned int verboseindex;
|
|
||||||
unsigned int tracepointsindex;
|
|
||||||
unsigned int tracepointsstringsindex;
|
|
||||||
unsigned int mcountindex;
|
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
long err = 0;
|
long err = 0;
|
||||||
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
|
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
|
||||||
void *mseg;
|
unsigned long *mseg;
|
||||||
struct exception_table_entry *extable;
|
|
||||||
mm_segment_t old_fs;
|
mm_segment_t old_fs;
|
||||||
|
|
||||||
DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
|
DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
|
||||||
|
@ -1937,6 +1915,7 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
err = -ENOEXEC;
|
err = -ENOEXEC;
|
||||||
goto free_hdr;
|
goto free_hdr;
|
||||||
}
|
}
|
||||||
|
/* This is temporary: point mod into copy of data. */
|
||||||
mod = (void *)sechdrs[modindex].sh_addr;
|
mod = (void *)sechdrs[modindex].sh_addr;
|
||||||
|
|
||||||
if (symindex == 0) {
|
if (symindex == 0) {
|
||||||
|
@ -1946,22 +1925,6 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
goto free_hdr;
|
goto free_hdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Optional sections */
|
|
||||||
exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
|
|
||||||
gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
|
|
||||||
gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
|
|
||||||
crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
|
|
||||||
gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
|
|
||||||
gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
|
|
||||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
|
||||||
unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused");
|
|
||||||
unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl");
|
|
||||||
unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused");
|
|
||||||
unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl");
|
|
||||||
#endif
|
|
||||||
setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
|
|
||||||
exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
|
|
||||||
obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
|
|
||||||
versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
|
versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
|
||||||
infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
|
infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
|
||||||
pcpuindex = find_pcpusec(hdr, sechdrs, secstrings);
|
pcpuindex = find_pcpusec(hdr, sechdrs, secstrings);
|
||||||
|
@ -2117,42 +2080,57 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* Set up EXPORTed & EXPORT_GPLed symbols (section 0 is 0 length) */
|
/* Now we've got everything in the final locations, we can
|
||||||
mod->num_syms = sechdrs[exportindex].sh_size / sizeof(*mod->syms);
|
* find optional sections. */
|
||||||
mod->syms = (void *)sechdrs[exportindex].sh_addr;
|
kp = section_objs(hdr, sechdrs, secstrings, "__param", sizeof(*kp),
|
||||||
if (crcindex)
|
&num_kp);
|
||||||
mod->crcs = (void *)sechdrs[crcindex].sh_addr;
|
mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab",
|
||||||
mod->num_gpl_syms = sechdrs[gplindex].sh_size / sizeof(*mod->gpl_syms);
|
sizeof(*mod->syms), &mod->num_syms);
|
||||||
mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr;
|
mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab");
|
||||||
if (gplcrcindex)
|
mod->gpl_syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab_gpl",
|
||||||
mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
|
sizeof(*mod->gpl_syms),
|
||||||
mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
|
&mod->num_gpl_syms);
|
||||||
sizeof(*mod->gpl_future_syms);
|
mod->gpl_crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab_gpl");
|
||||||
mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
|
mod->gpl_future_syms = section_objs(hdr, sechdrs, secstrings,
|
||||||
if (gplfuturecrcindex)
|
"__ksymtab_gpl_future",
|
||||||
mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
|
sizeof(*mod->gpl_future_syms),
|
||||||
|
&mod->num_gpl_future_syms);
|
||||||
|
mod->gpl_future_crcs = section_addr(hdr, sechdrs, secstrings,
|
||||||
|
"__kcrctab_gpl_future");
|
||||||
|
|
||||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||||
mod->num_unused_syms = sechdrs[unusedindex].sh_size /
|
mod->unused_syms = section_objs(hdr, sechdrs, secstrings,
|
||||||
sizeof(*mod->unused_syms);
|
"__ksymtab_unused",
|
||||||
mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size /
|
sizeof(*mod->unused_syms),
|
||||||
sizeof(*mod->unused_gpl_syms);
|
&mod->num_unused_syms);
|
||||||
mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;
|
mod->unused_crcs = section_addr(hdr, sechdrs, secstrings,
|
||||||
if (unusedcrcindex)
|
"__kcrctab_unused");
|
||||||
mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr;
|
mod->unused_gpl_syms = section_objs(hdr, sechdrs, secstrings,
|
||||||
mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr;
|
"__ksymtab_unused_gpl",
|
||||||
if (unusedgplcrcindex)
|
sizeof(*mod->unused_gpl_syms),
|
||||||
mod->unused_gpl_crcs
|
&mod->num_unused_gpl_syms);
|
||||||
= (void *)sechdrs[unusedgplcrcindex].sh_addr;
|
mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings,
|
||||||
|
"__kcrctab_unused_gpl");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_MARKERS
|
||||||
|
mod->markers = section_objs(hdr, sechdrs, secstrings, "__markers",
|
||||||
|
sizeof(*mod->markers), &mod->num_markers);
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_TRACEPOINTS
|
||||||
|
mod->tracepoints = section_objs(hdr, sechdrs, secstrings,
|
||||||
|
"__tracepoints",
|
||||||
|
sizeof(*mod->tracepoints),
|
||||||
|
&mod->num_tracepoints);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_MODVERSIONS
|
#ifdef CONFIG_MODVERSIONS
|
||||||
if ((mod->num_syms && !crcindex)
|
if ((mod->num_syms && !mod->crcs)
|
||||||
|| (mod->num_gpl_syms && !gplcrcindex)
|
|| (mod->num_gpl_syms && !mod->gpl_crcs)
|
||||||
|| (mod->num_gpl_future_syms && !gplfuturecrcindex)
|
|| (mod->num_gpl_future_syms && !mod->gpl_future_crcs)
|
||||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||||
|| (mod->num_unused_syms && !unusedcrcindex)
|
|| (mod->num_unused_syms && !mod->unused_crcs)
|
||||||
|| (mod->num_unused_gpl_syms && !unusedgplcrcindex)
|
|| (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs)
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name);
|
printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name);
|
||||||
|
@ -2161,16 +2139,6 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
markersindex = find_sec(hdr, sechdrs, secstrings, "__markers");
|
|
||||||
markersstringsindex = find_sec(hdr, sechdrs, secstrings,
|
|
||||||
"__markers_strings");
|
|
||||||
verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose");
|
|
||||||
tracepointsindex = find_sec(hdr, sechdrs, secstrings, "__tracepoints");
|
|
||||||
tracepointsstringsindex = find_sec(hdr, sechdrs, secstrings,
|
|
||||||
"__tracepoints_strings");
|
|
||||||
|
|
||||||
mcountindex = find_sec(hdr, sechdrs, secstrings,
|
|
||||||
"__mcount_loc");
|
|
||||||
|
|
||||||
/* Now do relocations. */
|
/* Now do relocations. */
|
||||||
for (i = 1; i < hdr->e_shnum; i++) {
|
for (i = 1; i < hdr->e_shnum; i++) {
|
||||||
|
@ -2193,28 +2161,16 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_MARKERS
|
|
||||||
mod->markers = (void *)sechdrs[markersindex].sh_addr;
|
|
||||||
mod->num_markers =
|
|
||||||
sechdrs[markersindex].sh_size / sizeof(*mod->markers);
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_TRACEPOINTS
|
|
||||||
mod->tracepoints = (void *)sechdrs[tracepointsindex].sh_addr;
|
|
||||||
mod->num_tracepoints =
|
|
||||||
sechdrs[tracepointsindex].sh_size / sizeof(*mod->tracepoints);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Find duplicate symbols */
|
/* Find duplicate symbols */
|
||||||
err = verify_export_symbols(mod);
|
err = verify_export_symbols(mod);
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* Set up and sort exception table */
|
/* Set up and sort exception table */
|
||||||
mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable);
|
mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table",
|
||||||
mod->extable = extable = (void *)sechdrs[exindex].sh_addr;
|
sizeof(*mod->extable), &mod->num_exentries);
|
||||||
sort_extable(extable, extable + mod->num_exentries);
|
sort_extable(mod->extable, mod->extable + mod->num_exentries);
|
||||||
|
|
||||||
/* Finally, copy percpu area over. */
|
/* Finally, copy percpu area over. */
|
||||||
percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr,
|
percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr,
|
||||||
|
@ -2223,11 +2179,17 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
|
add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
|
||||||
|
|
||||||
if (!mod->taints) {
|
if (!mod->taints) {
|
||||||
|
struct mod_debug *debug;
|
||||||
|
unsigned int num_debug;
|
||||||
|
|
||||||
#ifdef CONFIG_MARKERS
|
#ifdef CONFIG_MARKERS
|
||||||
marker_update_probe_range(mod->markers,
|
marker_update_probe_range(mod->markers,
|
||||||
mod->markers + mod->num_markers);
|
mod->markers + mod->num_markers);
|
||||||
#endif
|
#endif
|
||||||
dynamic_printk_setup(sechdrs, verboseindex);
|
debug = section_objs(hdr, sechdrs, secstrings, "__verbose",
|
||||||
|
sizeof(*debug), &num_debug);
|
||||||
|
dynamic_printk_setup(debug, num_debug);
|
||||||
|
|
||||||
#ifdef CONFIG_TRACEPOINTS
|
#ifdef CONFIG_TRACEPOINTS
|
||||||
tracepoint_update_probe_range(mod->tracepoints,
|
tracepoint_update_probe_range(mod->tracepoints,
|
||||||
mod->tracepoints + mod->num_tracepoints);
|
mod->tracepoints + mod->num_tracepoints);
|
||||||
|
@ -2235,8 +2197,9 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sechdrs[0].sh_size is always zero */
|
/* sechdrs[0].sh_size is always zero */
|
||||||
mseg = (void *)sechdrs[mcountindex].sh_addr;
|
mseg = section_objs(hdr, sechdrs, secstrings, "__mcount_loc",
|
||||||
ftrace_init_module(mseg, mseg + sechdrs[mcountindex].sh_size);
|
sizeof(*mseg), &num_mcount);
|
||||||
|
ftrace_init_module(mseg, mseg + num_mcount);
|
||||||
|
|
||||||
err = module_finalize(hdr, sechdrs, mod);
|
err = module_finalize(hdr, sechdrs, mod);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -2261,30 +2224,24 @@ static noinline struct module *load_module(void __user *umod,
|
||||||
set_fs(old_fs);
|
set_fs(old_fs);
|
||||||
|
|
||||||
mod->args = args;
|
mod->args = args;
|
||||||
if (obsparmindex)
|
if (section_addr(hdr, sechdrs, secstrings, "__obsparm"))
|
||||||
printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
|
printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
|
||||||
mod->name);
|
mod->name);
|
||||||
|
|
||||||
/* Now sew it into the lists so we can get lockdep and oops
|
/* Now sew it into the lists so we can get lockdep and oops
|
||||||
* info during argument parsing. Noone should access us, since
|
* info during argument parsing. Noone should access us, since
|
||||||
* strong_try_module_get() will fail. */
|
* strong_try_module_get() will fail.
|
||||||
stop_machine(__link_module, mod, NULL);
|
* lockdep/oops can run asynchronous, so use the RCU list insertion
|
||||||
|
* function to insert in a way safe to concurrent readers.
|
||||||
|
* The mutex protects against concurrent writers.
|
||||||
|
*/
|
||||||
|
list_add_rcu(&mod->list, &modules);
|
||||||
|
|
||||||
/* Size of section 0 is 0, so this works well if no params */
|
err = parse_args(mod->name, mod->args, kp, num_kp, NULL);
|
||||||
err = parse_args(mod->name, mod->args,
|
|
||||||
(struct kernel_param *)
|
|
||||||
sechdrs[setupindex].sh_addr,
|
|
||||||
sechdrs[setupindex].sh_size
|
|
||||||
/ sizeof(struct kernel_param),
|
|
||||||
NULL);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto unlink;
|
goto unlink;
|
||||||
|
|
||||||
err = mod_sysfs_setup(mod,
|
err = mod_sysfs_setup(mod, kp, num_kp);
|
||||||
(struct kernel_param *)
|
|
||||||
sechdrs[setupindex].sh_addr,
|
|
||||||
sechdrs[setupindex].sh_size
|
|
||||||
/ sizeof(struct kernel_param));
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto unlink;
|
goto unlink;
|
||||||
add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
|
add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
|
||||||
|
@ -2473,7 +2430,7 @@ const char *module_address_lookup(unsigned long addr,
|
||||||
const char *ret = NULL;
|
const char *ret = NULL;
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
list_for_each_entry(mod, &modules, list) {
|
list_for_each_entry_rcu(mod, &modules, list) {
|
||||||
if (within(addr, mod->module_init, mod->init_size)
|
if (within(addr, mod->module_init, mod->init_size)
|
||||||
|| within(addr, mod->module_core, mod->core_size)) {
|
|| within(addr, mod->module_core, mod->core_size)) {
|
||||||
if (modname)
|
if (modname)
|
||||||
|
@ -2496,7 +2453,7 @@ int lookup_module_symbol_name(unsigned long addr, char *symname)
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
list_for_each_entry(mod, &modules, list) {
|
list_for_each_entry_rcu(mod, &modules, list) {
|
||||||
if (within(addr, mod->module_init, mod->init_size) ||
|
if (within(addr, mod->module_init, mod->init_size) ||
|
||||||
within(addr, mod->module_core, mod->core_size)) {
|
within(addr, mod->module_core, mod->core_size)) {
|
||||||
const char *sym;
|
const char *sym;
|
||||||
|
@ -2520,7 +2477,7 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
list_for_each_entry(mod, &modules, list) {
|
list_for_each_entry_rcu(mod, &modules, list) {
|
||||||
if (within(addr, mod->module_init, mod->init_size) ||
|
if (within(addr, mod->module_init, mod->init_size) ||
|
||||||
within(addr, mod->module_core, mod->core_size)) {
|
within(addr, mod->module_core, mod->core_size)) {
|
||||||
const char *sym;
|
const char *sym;
|
||||||
|
@ -2547,7 +2504,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
list_for_each_entry(mod, &modules, list) {
|
list_for_each_entry_rcu(mod, &modules, list) {
|
||||||
if (symnum < mod->num_symtab) {
|
if (symnum < mod->num_symtab) {
|
||||||
*value = mod->symtab[symnum].st_value;
|
*value = mod->symtab[symnum].st_value;
|
||||||
*type = mod->symtab[symnum].st_info;
|
*type = mod->symtab[symnum].st_info;
|
||||||
|
@ -2590,7 +2547,7 @@ unsigned long module_kallsyms_lookup_name(const char *name)
|
||||||
ret = mod_find_symname(mod, colon+1);
|
ret = mod_find_symname(mod, colon+1);
|
||||||
*colon = ':';
|
*colon = ':';
|
||||||
} else {
|
} else {
|
||||||
list_for_each_entry(mod, &modules, list)
|
list_for_each_entry_rcu(mod, &modules, list)
|
||||||
if ((ret = mod_find_symname(mod, name)) != 0)
|
if ((ret = mod_find_symname(mod, name)) != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2693,7 +2650,7 @@ const struct exception_table_entry *search_module_extables(unsigned long addr)
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
list_for_each_entry(mod, &modules, list) {
|
list_for_each_entry_rcu(mod, &modules, list) {
|
||||||
if (mod->num_exentries == 0)
|
if (mod->num_exentries == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -2719,7 +2676,7 @@ int is_module_address(unsigned long addr)
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
|
|
||||||
list_for_each_entry(mod, &modules, list) {
|
list_for_each_entry_rcu(mod, &modules, list) {
|
||||||
if (within(addr, mod->module_core, mod->core_size)) {
|
if (within(addr, mod->module_core, mod->core_size)) {
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2740,7 +2697,7 @@ struct module *__module_text_address(unsigned long addr)
|
||||||
if (addr < module_addr_min || addr > module_addr_max)
|
if (addr < module_addr_min || addr > module_addr_max)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
list_for_each_entry(mod, &modules, list)
|
list_for_each_entry_rcu(mod, &modules, list)
|
||||||
if (within(addr, mod->module_init, mod->init_text_size)
|
if (within(addr, mod->module_init, mod->init_text_size)
|
||||||
|| within(addr, mod->module_core, mod->core_text_size))
|
|| within(addr, mod->module_core, mod->core_text_size))
|
||||||
return mod;
|
return mod;
|
||||||
|
@ -2765,8 +2722,11 @@ void print_modules(void)
|
||||||
char buf[8];
|
char buf[8];
|
||||||
|
|
||||||
printk("Modules linked in:");
|
printk("Modules linked in:");
|
||||||
list_for_each_entry(mod, &modules, list)
|
/* Most callers should already have preempt disabled, but make sure */
|
||||||
|
preempt_disable();
|
||||||
|
list_for_each_entry_rcu(mod, &modules, list)
|
||||||
printk(" %s%s", mod->name, module_flags(mod, buf));
|
printk(" %s%s", mod->name, module_flags(mod, buf));
|
||||||
|
preempt_enable();
|
||||||
if (last_unloaded_module[0])
|
if (last_unloaded_module[0])
|
||||||
printk(" [last unloaded: %s]", last_unloaded_module);
|
printk(" [last unloaded: %s]", last_unloaded_module);
|
||||||
printk("\n");
|
printk("\n");
|
||||||
|
|
|
@ -34,13 +34,6 @@ ATOMIC_NOTIFIER_HEAD(panic_notifier_list);
|
||||||
|
|
||||||
EXPORT_SYMBOL(panic_notifier_list);
|
EXPORT_SYMBOL(panic_notifier_list);
|
||||||
|
|
||||||
static int __init panic_setup(char *str)
|
|
||||||
{
|
|
||||||
panic_timeout = simple_strtoul(str, NULL, 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
__setup("panic=", panic_setup);
|
|
||||||
|
|
||||||
static long no_blink(long time)
|
static long no_blink(long time)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -218,13 +211,6 @@ void add_taint(unsigned flag)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(add_taint);
|
EXPORT_SYMBOL(add_taint);
|
||||||
|
|
||||||
static int __init pause_on_oops_setup(char *str)
|
|
||||||
{
|
|
||||||
pause_on_oops = simple_strtoul(str, NULL, 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
__setup("pause_on_oops=", pause_on_oops_setup);
|
|
||||||
|
|
||||||
static void spin_msec(int msecs)
|
static void spin_msec(int msecs)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -384,3 +370,6 @@ void __stack_chk_fail(void)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__stack_chk_fail);
|
EXPORT_SYMBOL(__stack_chk_fail);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
core_param(panic, panic_timeout, int, 0644);
|
||||||
|
core_param(pause_on_oops, pause_on_oops, int, 0644);
|
||||||
|
|
272
kernel/params.c
272
kernel/params.c
|
@ -373,6 +373,8 @@ int param_get_string(char *buffer, struct kernel_param *kp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sysfs output in /sys/modules/XYZ/parameters/ */
|
/* sysfs output in /sys/modules/XYZ/parameters/ */
|
||||||
|
#define to_module_attr(n) container_of(n, struct module_attribute, attr);
|
||||||
|
#define to_module_kobject(n) container_of(n, struct module_kobject, kobj);
|
||||||
|
|
||||||
extern struct kernel_param __start___param[], __stop___param[];
|
extern struct kernel_param __start___param[], __stop___param[];
|
||||||
|
|
||||||
|
@ -384,6 +386,7 @@ struct param_attribute
|
||||||
|
|
||||||
struct module_param_attrs
|
struct module_param_attrs
|
||||||
{
|
{
|
||||||
|
unsigned int num;
|
||||||
struct attribute_group grp;
|
struct attribute_group grp;
|
||||||
struct param_attribute attrs[0];
|
struct param_attribute attrs[0];
|
||||||
};
|
};
|
||||||
|
@ -434,69 +437,84 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
|
||||||
|
|
||||||
#ifdef CONFIG_SYSFS
|
#ifdef CONFIG_SYSFS
|
||||||
/*
|
/*
|
||||||
* param_sysfs_setup - setup sysfs support for one module or KBUILD_MODNAME
|
* add_sysfs_param - add a parameter to sysfs
|
||||||
* @mk: struct module_kobject (contains parent kobject)
|
* @mk: struct module_kobject
|
||||||
* @kparam: array of struct kernel_param, the actual parameter definitions
|
* @kparam: the actual parameter definition to add to sysfs
|
||||||
* @num_params: number of entries in array
|
* @name: name of parameter
|
||||||
* @name_skip: offset where the parameter name start in kparam[].name. Needed for built-in "modules"
|
|
||||||
*
|
*
|
||||||
* Create a kobject for a (per-module) group of parameters, and create files
|
* Create a kobject if for a (per-module) parameter if mp NULL, and
|
||||||
* in sysfs. A pointer to the param_kobject is returned on success,
|
* create file in sysfs. Returns an error on out of memory. Always cleans up
|
||||||
* NULL if there's no parameter to export, or other ERR_PTR(err).
|
* if there's an error.
|
||||||
*/
|
*/
|
||||||
static __modinit struct module_param_attrs *
|
static __modinit int add_sysfs_param(struct module_kobject *mk,
|
||||||
param_sysfs_setup(struct module_kobject *mk,
|
struct kernel_param *kp,
|
||||||
struct kernel_param *kparam,
|
const char *name)
|
||||||
unsigned int num_params,
|
|
||||||
unsigned int name_skip)
|
|
||||||
{
|
{
|
||||||
struct module_param_attrs *mp;
|
struct module_param_attrs *new;
|
||||||
unsigned int valid_attrs = 0;
|
struct attribute **attrs;
|
||||||
unsigned int i, size[2];
|
int err, num;
|
||||||
struct param_attribute *pattr;
|
|
||||||
struct attribute **gattr;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
for (i=0; i<num_params; i++) {
|
/* We don't bother calling this with invisible parameters. */
|
||||||
if (kparam[i].perm)
|
BUG_ON(!kp->perm);
|
||||||
valid_attrs++;
|
|
||||||
|
if (!mk->mp) {
|
||||||
|
num = 0;
|
||||||
|
attrs = NULL;
|
||||||
|
} else {
|
||||||
|
num = mk->mp->num;
|
||||||
|
attrs = mk->mp->grp.attrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid_attrs)
|
/* Enlarge. */
|
||||||
return NULL;
|
new = krealloc(mk->mp,
|
||||||
|
sizeof(*mk->mp) + sizeof(mk->mp->attrs[0]) * (num+1),
|
||||||
size[0] = ALIGN(sizeof(*mp) +
|
GFP_KERNEL);
|
||||||
valid_attrs * sizeof(mp->attrs[0]),
|
if (!new) {
|
||||||
sizeof(mp->grp.attrs[0]));
|
kfree(mk->mp);
|
||||||
size[1] = (valid_attrs + 1) * sizeof(mp->grp.attrs[0]);
|
err = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
mp = kzalloc(size[0] + size[1], GFP_KERNEL);
|
|
||||||
if (!mp)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
mp->grp.name = "parameters";
|
|
||||||
mp->grp.attrs = (void *)mp + size[0];
|
|
||||||
|
|
||||||
pattr = &mp->attrs[0];
|
|
||||||
gattr = &mp->grp.attrs[0];
|
|
||||||
for (i = 0; i < num_params; i++) {
|
|
||||||
struct kernel_param *kp = &kparam[i];
|
|
||||||
if (kp->perm) {
|
|
||||||
pattr->param = kp;
|
|
||||||
pattr->mattr.show = param_attr_show;
|
|
||||||
pattr->mattr.store = param_attr_store;
|
|
||||||
pattr->mattr.attr.name = (char *)&kp->name[name_skip];
|
|
||||||
pattr->mattr.attr.mode = kp->perm;
|
|
||||||
*(gattr++) = &(pattr++)->mattr.attr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*gattr = NULL;
|
attrs = krealloc(attrs, sizeof(new->grp.attrs[0])*(num+2), GFP_KERNEL);
|
||||||
|
if (!attrs) {
|
||||||
if ((err = sysfs_create_group(&mk->kobj, &mp->grp))) {
|
err = -ENOMEM;
|
||||||
kfree(mp);
|
goto fail_free_new;
|
||||||
return ERR_PTR(err);
|
|
||||||
}
|
}
|
||||||
return mp;
|
|
||||||
|
/* Sysfs wants everything zeroed. */
|
||||||
|
memset(new, 0, sizeof(*new));
|
||||||
|
memset(&new->attrs[num], 0, sizeof(new->attrs[num]));
|
||||||
|
memset(&attrs[num], 0, sizeof(attrs[num]));
|
||||||
|
new->grp.name = "parameters";
|
||||||
|
new->grp.attrs = attrs;
|
||||||
|
|
||||||
|
/* Tack new one on the end. */
|
||||||
|
new->attrs[num].param = kp;
|
||||||
|
new->attrs[num].mattr.show = param_attr_show;
|
||||||
|
new->attrs[num].mattr.store = param_attr_store;
|
||||||
|
new->attrs[num].mattr.attr.name = (char *)name;
|
||||||
|
new->attrs[num].mattr.attr.mode = kp->perm;
|
||||||
|
new->num = num+1;
|
||||||
|
|
||||||
|
/* Fix up all the pointers, since krealloc can move us */
|
||||||
|
for (num = 0; num < new->num; num++)
|
||||||
|
new->grp.attrs[num] = &new->attrs[num].mattr.attr;
|
||||||
|
new->grp.attrs[num] = NULL;
|
||||||
|
|
||||||
|
mk->mp = new;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail_free_new:
|
||||||
|
kfree(new);
|
||||||
|
fail:
|
||||||
|
mk->mp = NULL;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_module_param_attrs(struct module_kobject *mk)
|
||||||
|
{
|
||||||
|
kfree(mk->mp->grp.attrs);
|
||||||
|
kfree(mk->mp);
|
||||||
|
mk->mp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MODULES
|
#ifdef CONFIG_MODULES
|
||||||
|
@ -506,21 +524,33 @@ param_sysfs_setup(struct module_kobject *mk,
|
||||||
* @kparam: module parameters (array)
|
* @kparam: module parameters (array)
|
||||||
* @num_params: number of module parameters
|
* @num_params: number of module parameters
|
||||||
*
|
*
|
||||||
* Adds sysfs entries for module parameters, and creates a link from
|
* Adds sysfs entries for module parameters under
|
||||||
* /sys/module/[mod->name]/parameters to /sys/parameters/[mod->name]/
|
* /sys/module/[mod->name]/parameters/
|
||||||
*/
|
*/
|
||||||
int module_param_sysfs_setup(struct module *mod,
|
int module_param_sysfs_setup(struct module *mod,
|
||||||
struct kernel_param *kparam,
|
struct kernel_param *kparam,
|
||||||
unsigned int num_params)
|
unsigned int num_params)
|
||||||
{
|
{
|
||||||
struct module_param_attrs *mp;
|
int i, err;
|
||||||
|
bool params = false;
|
||||||
|
|
||||||
mp = param_sysfs_setup(&mod->mkobj, kparam, num_params, 0);
|
for (i = 0; i < num_params; i++) {
|
||||||
if (IS_ERR(mp))
|
if (kparam[i].perm == 0)
|
||||||
return PTR_ERR(mp);
|
continue;
|
||||||
|
err = add_sysfs_param(&mod->mkobj, &kparam[i], kparam[i].name);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
params = true;
|
||||||
|
}
|
||||||
|
|
||||||
mod->param_attrs = mp;
|
if (!params)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Create the param group. */
|
||||||
|
err = sysfs_create_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp);
|
||||||
|
if (err)
|
||||||
|
free_module_param_attrs(&mod->mkobj);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -532,43 +562,55 @@ int module_param_sysfs_setup(struct module *mod,
|
||||||
*/
|
*/
|
||||||
void module_param_sysfs_remove(struct module *mod)
|
void module_param_sysfs_remove(struct module *mod)
|
||||||
{
|
{
|
||||||
if (mod->param_attrs) {
|
if (mod->mkobj.mp) {
|
||||||
sysfs_remove_group(&mod->mkobj.kobj,
|
sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp);
|
||||||
&mod->param_attrs->grp);
|
|
||||||
/* We are positive that no one is using any param
|
/* We are positive that no one is using any param
|
||||||
* attrs at this point. Deallocate immediately. */
|
* attrs at this point. Deallocate immediately. */
|
||||||
kfree(mod->param_attrs);
|
free_module_param_attrs(&mod->mkobj);
|
||||||
mod->param_attrs = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
static void __init kernel_add_sysfs_param(const char *name,
|
||||||
* kernel_param_sysfs_setup - wrapper for built-in params support
|
struct kernel_param *kparam,
|
||||||
*/
|
unsigned int name_skip)
|
||||||
static void __init kernel_param_sysfs_setup(const char *name,
|
|
||||||
struct kernel_param *kparam,
|
|
||||||
unsigned int num_params,
|
|
||||||
unsigned int name_skip)
|
|
||||||
{
|
{
|
||||||
struct module_kobject *mk;
|
struct module_kobject *mk;
|
||||||
int ret;
|
struct kobject *kobj;
|
||||||
|
int err;
|
||||||
|
|
||||||
mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);
|
kobj = kset_find_obj(module_kset, name);
|
||||||
BUG_ON(!mk);
|
if (kobj) {
|
||||||
|
/* We already have one. Remove params so we can add more. */
|
||||||
|
mk = to_module_kobject(kobj);
|
||||||
|
/* We need to remove it before adding parameters. */
|
||||||
|
sysfs_remove_group(&mk->kobj, &mk->mp->grp);
|
||||||
|
} else {
|
||||||
|
mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);
|
||||||
|
BUG_ON(!mk);
|
||||||
|
|
||||||
mk->mod = THIS_MODULE;
|
mk->mod = THIS_MODULE;
|
||||||
mk->kobj.kset = module_kset;
|
mk->kobj.kset = module_kset;
|
||||||
ret = kobject_init_and_add(&mk->kobj, &module_ktype, NULL, "%s", name);
|
err = kobject_init_and_add(&mk->kobj, &module_ktype, NULL,
|
||||||
if (ret) {
|
"%s", name);
|
||||||
kobject_put(&mk->kobj);
|
if (err) {
|
||||||
printk(KERN_ERR "Module '%s' failed to be added to sysfs, "
|
kobject_put(&mk->kobj);
|
||||||
"error number %d\n", name, ret);
|
printk(KERN_ERR "Module '%s' failed add to sysfs, "
|
||||||
printk(KERN_ERR "The system will be unstable now.\n");
|
"error number %d\n", name, err);
|
||||||
return;
|
printk(KERN_ERR "The system will be unstable now.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* So that exit path is even. */
|
||||||
|
kobject_get(&mk->kobj);
|
||||||
}
|
}
|
||||||
param_sysfs_setup(mk, kparam, num_params, name_skip);
|
|
||||||
|
/* These should not fail at boot. */
|
||||||
|
err = add_sysfs_param(mk, kparam, kparam->name + name_skip);
|
||||||
|
BUG_ON(err);
|
||||||
|
err = sysfs_create_group(&mk->kobj, &mk->mp->grp);
|
||||||
|
BUG_ON(err);
|
||||||
kobject_uevent(&mk->kobj, KOBJ_ADD);
|
kobject_uevent(&mk->kobj, KOBJ_ADD);
|
||||||
|
kobject_put(&mk->kobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -579,60 +621,36 @@ static void __init kernel_param_sysfs_setup(const char *name,
|
||||||
* The "module" name (KBUILD_MODNAME) is stored before a dot, the
|
* The "module" name (KBUILD_MODNAME) is stored before a dot, the
|
||||||
* "parameter" name is stored behind a dot in kernel_param->name. So,
|
* "parameter" name is stored behind a dot in kernel_param->name. So,
|
||||||
* extract the "module" name for all built-in kernel_param-eters,
|
* extract the "module" name for all built-in kernel_param-eters,
|
||||||
* and for all who have the same, call kernel_param_sysfs_setup.
|
* and for all who have the same, call kernel_add_sysfs_param.
|
||||||
*/
|
*/
|
||||||
static void __init param_sysfs_builtin(void)
|
static void __init param_sysfs_builtin(void)
|
||||||
{
|
{
|
||||||
struct kernel_param *kp, *kp_begin = NULL;
|
struct kernel_param *kp;
|
||||||
unsigned int i, name_len, count = 0;
|
unsigned int name_len;
|
||||||
char modname[MODULE_NAME_LEN + 1] = "";
|
char modname[MODULE_NAME_LEN];
|
||||||
|
|
||||||
for (i=0; i < __stop___param - __start___param; i++) {
|
for (kp = __start___param; kp < __stop___param; kp++) {
|
||||||
char *dot;
|
char *dot;
|
||||||
size_t max_name_len;
|
|
||||||
|
|
||||||
kp = &__start___param[i];
|
if (kp->perm == 0)
|
||||||
max_name_len =
|
|
||||||
min_t(size_t, MODULE_NAME_LEN, strlen(kp->name));
|
|
||||||
|
|
||||||
dot = memchr(kp->name, '.', max_name_len);
|
|
||||||
if (!dot) {
|
|
||||||
DEBUGP("couldn't find period in first %d characters "
|
|
||||||
"of %s\n", MODULE_NAME_LEN, kp->name);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
name_len = dot - kp->name;
|
|
||||||
|
|
||||||
/* new kbuild_modname? */
|
dot = strchr(kp->name, '.');
|
||||||
if (strlen(modname) != name_len
|
if (!dot) {
|
||||||
|| strncmp(modname, kp->name, name_len) != 0) {
|
/* This happens for core_param() */
|
||||||
/* add a new kobject for previous kernel_params. */
|
strcpy(modname, "kernel");
|
||||||
if (count)
|
name_len = 0;
|
||||||
kernel_param_sysfs_setup(modname,
|
} else {
|
||||||
kp_begin,
|
name_len = dot - kp->name + 1;
|
||||||
count,
|
strlcpy(modname, kp->name, name_len);
|
||||||
strlen(modname)+1);
|
|
||||||
|
|
||||||
strncpy(modname, kp->name, name_len);
|
|
||||||
modname[name_len] = '\0';
|
|
||||||
count = 0;
|
|
||||||
kp_begin = kp;
|
|
||||||
}
|
}
|
||||||
count++;
|
kernel_add_sysfs_param(modname, kp, name_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* last kernel_params need to be registered as well */
|
|
||||||
if (count)
|
|
||||||
kernel_param_sysfs_setup(modname, kp_begin, count,
|
|
||||||
strlen(modname)+1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* module-related sysfs stuff */
|
/* module-related sysfs stuff */
|
||||||
|
|
||||||
#define to_module_attr(n) container_of(n, struct module_attribute, attr);
|
|
||||||
#define to_module_kobject(n) container_of(n, struct module_kobject, kobj);
|
|
||||||
|
|
||||||
static ssize_t module_attr_show(struct kobject *kobj,
|
static ssize_t module_attr_show(struct kobject *kobj,
|
||||||
struct attribute *attr,
|
struct attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
|
|
|
@ -37,9 +37,13 @@ struct stop_machine_data {
|
||||||
/* Like num_online_cpus(), but hotplug cpu uses us, so we need this. */
|
/* Like num_online_cpus(), but hotplug cpu uses us, so we need this. */
|
||||||
static unsigned int num_threads;
|
static unsigned int num_threads;
|
||||||
static atomic_t thread_ack;
|
static atomic_t thread_ack;
|
||||||
static struct completion finished;
|
|
||||||
static DEFINE_MUTEX(lock);
|
static DEFINE_MUTEX(lock);
|
||||||
|
|
||||||
|
static struct workqueue_struct *stop_machine_wq;
|
||||||
|
static struct stop_machine_data active, idle;
|
||||||
|
static const cpumask_t *active_cpus;
|
||||||
|
static void *stop_machine_work;
|
||||||
|
|
||||||
static void set_state(enum stopmachine_state newstate)
|
static void set_state(enum stopmachine_state newstate)
|
||||||
{
|
{
|
||||||
/* Reset ack counter. */
|
/* Reset ack counter. */
|
||||||
|
@ -51,21 +55,26 @@ static void set_state(enum stopmachine_state newstate)
|
||||||
/* Last one to ack a state moves to the next state. */
|
/* Last one to ack a state moves to the next state. */
|
||||||
static void ack_state(void)
|
static void ack_state(void)
|
||||||
{
|
{
|
||||||
if (atomic_dec_and_test(&thread_ack)) {
|
if (atomic_dec_and_test(&thread_ack))
|
||||||
/* If we're the last one to ack the EXIT, we're finished. */
|
set_state(state + 1);
|
||||||
if (state == STOPMACHINE_EXIT)
|
|
||||||
complete(&finished);
|
|
||||||
else
|
|
||||||
set_state(state + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is the actual thread which stops the CPU. It exits by itself rather
|
/* This is the actual function which stops the CPU. It runs
|
||||||
* than waiting for kthread_stop(), because it's easier for hotplug CPU. */
|
* in the context of a dedicated stopmachine workqueue. */
|
||||||
static int stop_cpu(struct stop_machine_data *smdata)
|
static void stop_cpu(struct work_struct *unused)
|
||||||
{
|
{
|
||||||
enum stopmachine_state curstate = STOPMACHINE_NONE;
|
enum stopmachine_state curstate = STOPMACHINE_NONE;
|
||||||
|
struct stop_machine_data *smdata = &idle;
|
||||||
|
int cpu = smp_processor_id();
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!active_cpus) {
|
||||||
|
if (cpu == first_cpu(cpu_online_map))
|
||||||
|
smdata = &active;
|
||||||
|
} else {
|
||||||
|
if (cpu_isset(cpu, *active_cpus))
|
||||||
|
smdata = &active;
|
||||||
|
}
|
||||||
/* Simple state machine */
|
/* Simple state machine */
|
||||||
do {
|
do {
|
||||||
/* Chill out and ensure we re-read stopmachine_state. */
|
/* Chill out and ensure we re-read stopmachine_state. */
|
||||||
|
@ -78,9 +87,11 @@ static int stop_cpu(struct stop_machine_data *smdata)
|
||||||
hard_irq_disable();
|
hard_irq_disable();
|
||||||
break;
|
break;
|
||||||
case STOPMACHINE_RUN:
|
case STOPMACHINE_RUN:
|
||||||
/* |= allows error detection if functions on
|
/* On multiple CPUs only a single error code
|
||||||
* multiple CPUs. */
|
* is needed to tell that something failed. */
|
||||||
smdata->fnret |= smdata->fn(smdata->data);
|
err = smdata->fn(smdata->data);
|
||||||
|
if (err)
|
||||||
|
smdata->fnret = err;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -90,7 +101,6 @@ static int stop_cpu(struct stop_machine_data *smdata)
|
||||||
} while (curstate != STOPMACHINE_EXIT);
|
} while (curstate != STOPMACHINE_EXIT);
|
||||||
|
|
||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
do_exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Callback for CPUs which aren't supposed to do anything. */
|
/* Callback for CPUs which aren't supposed to do anything. */
|
||||||
|
@ -101,78 +111,34 @@ static int chill(void *unused)
|
||||||
|
|
||||||
int __stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus)
|
int __stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus)
|
||||||
{
|
{
|
||||||
int i, err;
|
struct work_struct *sm_work;
|
||||||
struct stop_machine_data active, idle;
|
int i;
|
||||||
struct task_struct **threads;
|
|
||||||
|
|
||||||
|
/* Set up initial state. */
|
||||||
|
mutex_lock(&lock);
|
||||||
|
num_threads = num_online_cpus();
|
||||||
|
active_cpus = cpus;
|
||||||
active.fn = fn;
|
active.fn = fn;
|
||||||
active.data = data;
|
active.data = data;
|
||||||
active.fnret = 0;
|
active.fnret = 0;
|
||||||
idle.fn = chill;
|
idle.fn = chill;
|
||||||
idle.data = NULL;
|
idle.data = NULL;
|
||||||
|
|
||||||
/* This could be too big for stack on large machines. */
|
|
||||||
threads = kcalloc(NR_CPUS, sizeof(threads[0]), GFP_KERNEL);
|
|
||||||
if (!threads)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* Set up initial state. */
|
|
||||||
mutex_lock(&lock);
|
|
||||||
init_completion(&finished);
|
|
||||||
num_threads = num_online_cpus();
|
|
||||||
set_state(STOPMACHINE_PREPARE);
|
set_state(STOPMACHINE_PREPARE);
|
||||||
|
|
||||||
for_each_online_cpu(i) {
|
/* Schedule the stop_cpu work on all cpus: hold this CPU so one
|
||||||
struct stop_machine_data *smdata = &idle;
|
|
||||||
struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
|
|
||||||
|
|
||||||
if (!cpus) {
|
|
||||||
if (i == first_cpu(cpu_online_map))
|
|
||||||
smdata = &active;
|
|
||||||
} else {
|
|
||||||
if (cpu_isset(i, *cpus))
|
|
||||||
smdata = &active;
|
|
||||||
}
|
|
||||||
|
|
||||||
threads[i] = kthread_create((void *)stop_cpu, smdata, "kstop%u",
|
|
||||||
i);
|
|
||||||
if (IS_ERR(threads[i])) {
|
|
||||||
err = PTR_ERR(threads[i]);
|
|
||||||
threads[i] = NULL;
|
|
||||||
goto kill_threads;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Place it onto correct cpu. */
|
|
||||||
kthread_bind(threads[i], i);
|
|
||||||
|
|
||||||
/* Make it highest prio. */
|
|
||||||
if (sched_setscheduler_nocheck(threads[i], SCHED_FIFO, ¶m))
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We've created all the threads. Wake them all: hold this CPU so one
|
|
||||||
* doesn't hit this CPU until we're ready. */
|
* doesn't hit this CPU until we're ready. */
|
||||||
get_cpu();
|
get_cpu();
|
||||||
for_each_online_cpu(i)
|
for_each_online_cpu(i) {
|
||||||
wake_up_process(threads[i]);
|
sm_work = percpu_ptr(stop_machine_work, i);
|
||||||
|
INIT_WORK(sm_work, stop_cpu);
|
||||||
|
queue_work_on(i, stop_machine_wq, sm_work);
|
||||||
|
}
|
||||||
/* This will release the thread on our CPU. */
|
/* This will release the thread on our CPU. */
|
||||||
put_cpu();
|
put_cpu();
|
||||||
wait_for_completion(&finished);
|
flush_workqueue(stop_machine_wq);
|
||||||
mutex_unlock(&lock);
|
mutex_unlock(&lock);
|
||||||
|
|
||||||
kfree(threads);
|
|
||||||
|
|
||||||
return active.fnret;
|
return active.fnret;
|
||||||
|
|
||||||
kill_threads:
|
|
||||||
for_each_online_cpu(i)
|
|
||||||
if (threads[i])
|
|
||||||
kthread_stop(threads[i]);
|
|
||||||
mutex_unlock(&lock);
|
|
||||||
|
|
||||||
kfree(threads);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus)
|
int stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus)
|
||||||
|
@ -187,3 +153,11 @@ int stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(stop_machine);
|
EXPORT_SYMBOL_GPL(stop_machine);
|
||||||
|
|
||||||
|
static int __init stop_machine_init(void)
|
||||||
|
{
|
||||||
|
stop_machine_wq = create_rt_workqueue("kstop");
|
||||||
|
stop_machine_work = alloc_percpu(struct work_struct);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
early_initcall(stop_machine_init);
|
||||||
|
|
|
@ -62,6 +62,7 @@ struct workqueue_struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
int singlethread;
|
int singlethread;
|
||||||
int freezeable; /* Freeze threads during suspend */
|
int freezeable; /* Freeze threads during suspend */
|
||||||
|
int rt;
|
||||||
#ifdef CONFIG_LOCKDEP
|
#ifdef CONFIG_LOCKDEP
|
||||||
struct lockdep_map lockdep_map;
|
struct lockdep_map lockdep_map;
|
||||||
#endif
|
#endif
|
||||||
|
@ -766,6 +767,7 @@ init_cpu_workqueue(struct workqueue_struct *wq, int cpu)
|
||||||
|
|
||||||
static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
|
static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
|
||||||
{
|
{
|
||||||
|
struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
|
||||||
struct workqueue_struct *wq = cwq->wq;
|
struct workqueue_struct *wq = cwq->wq;
|
||||||
const char *fmt = is_single_threaded(wq) ? "%s" : "%s/%d";
|
const char *fmt = is_single_threaded(wq) ? "%s" : "%s/%d";
|
||||||
struct task_struct *p;
|
struct task_struct *p;
|
||||||
|
@ -781,7 +783,8 @@ static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
|
||||||
*/
|
*/
|
||||||
if (IS_ERR(p))
|
if (IS_ERR(p))
|
||||||
return PTR_ERR(p);
|
return PTR_ERR(p);
|
||||||
|
if (cwq->wq->rt)
|
||||||
|
sched_setscheduler_nocheck(p, SCHED_FIFO, ¶m);
|
||||||
cwq->thread = p;
|
cwq->thread = p;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -801,6 +804,7 @@ static void start_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
|
||||||
struct workqueue_struct *__create_workqueue_key(const char *name,
|
struct workqueue_struct *__create_workqueue_key(const char *name,
|
||||||
int singlethread,
|
int singlethread,
|
||||||
int freezeable,
|
int freezeable,
|
||||||
|
int rt,
|
||||||
struct lock_class_key *key,
|
struct lock_class_key *key,
|
||||||
const char *lock_name)
|
const char *lock_name)
|
||||||
{
|
{
|
||||||
|
@ -822,6 +826,7 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
|
||||||
lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
|
lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
|
||||||
wq->singlethread = singlethread;
|
wq->singlethread = singlethread;
|
||||||
wq->freezeable = freezeable;
|
wq->freezeable = freezeable;
|
||||||
|
wq->rt = rt;
|
||||||
INIT_LIST_HEAD(&wq->list);
|
INIT_LIST_HEAD(&wq->list);
|
||||||
|
|
||||||
if (singlethread) {
|
if (singlethread) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче