diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-23 13:00:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-23 13:00:14 -0400 |
commit | a5344876065e047d507800d0801a637d68d3b129 (patch) | |
tree | 240173ed2f588a1c61aff9bb513255f99b0cd6a2 | |
parent | 296e1ce0dc36bb106c139e25482d02da43c70e71 (diff) | |
parent | 8163bcac779f62c6bf847caed9bce905db0693fb (diff) |
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.
-rw-r--r-- | include/linux/module.h | 6 | ||||
-rw-r--r-- | include/linux/moduleparam.h | 25 | ||||
-rw-r--r-- | include/linux/workqueue.h | 18 | ||||
-rw-r--r-- | init/main.c | 12 | ||||
-rw-r--r-- | kernel/module.c | 284 | ||||
-rw-r--r-- | kernel/panic.c | 17 | ||||
-rw-r--r-- | kernel/params.c | 274 | ||||
-rw-r--r-- | kernel/stop_machine.c | 120 | ||||
-rw-r--r-- | kernel/workqueue.c | 7 |
9 files changed, 364 insertions, 399 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index 5d2970cdce9..3bfed013350 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -29,7 +29,7 @@ | |||
29 | #define MODULE_SYMBOL_PREFIX "" | 29 | #define MODULE_SYMBOL_PREFIX "" |
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | #define MODULE_NAME_LEN (64 - sizeof(unsigned long)) | 32 | #define MODULE_NAME_LEN MAX_PARAM_PREFIX_LEN |
33 | 33 | ||
34 | struct kernel_symbol | 34 | struct kernel_symbol |
35 | { | 35 | { |
@@ -60,6 +60,7 @@ struct module_kobject | |||
60 | struct kobject kobj; | 60 | struct kobject kobj; |
61 | struct module *mod; | 61 | struct module *mod; |
62 | struct kobject *drivers_dir; | 62 | struct kobject *drivers_dir; |
63 | struct module_param_attrs *mp; | ||
63 | }; | 64 | }; |
64 | 65 | ||
65 | /* These are either module local, or the kernel's dummy ones. */ | 66 | /* These are either module local, or the kernel's dummy ones. */ |
@@ -242,7 +243,6 @@ struct module | |||
242 | 243 | ||
243 | /* Sysfs stuff. */ | 244 | /* Sysfs stuff. */ |
244 | struct module_kobject mkobj; | 245 | struct module_kobject mkobj; |
245 | struct module_param_attrs *param_attrs; | ||
246 | struct module_attribute *modinfo_attrs; | 246 | struct module_attribute *modinfo_attrs; |
247 | const char *version; | 247 | const char *version; |
248 | const char *srcversion; | 248 | const char *srcversion; |
@@ -277,7 +277,7 @@ struct module | |||
277 | 277 | ||
278 | /* Exception table */ | 278 | /* Exception table */ |
279 | unsigned int num_exentries; | 279 | unsigned int num_exentries; |
280 | const struct exception_table_entry *extable; | 280 | struct exception_table_entry *extable; |
281 | 281 | ||
282 | /* Startup function. */ | 282 | /* Startup function. */ |
283 | int (*init)(void); | 283 | int (*init)(void); |
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index ec624381c84..e4af3399ef4 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h | |||
@@ -13,6 +13,9 @@ | |||
13 | #define MODULE_PARAM_PREFIX KBUILD_MODNAME "." | 13 | #define MODULE_PARAM_PREFIX KBUILD_MODNAME "." |
14 | #endif | 14 | #endif |
15 | 15 | ||
16 | /* Chosen so that structs with an unsigned long line up. */ | ||
17 | #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) | ||
18 | |||
16 | #ifdef MODULE | 19 | #ifdef MODULE |
17 | #define ___module_cat(a,b) __mod_ ## a ## b | 20 | #define ___module_cat(a,b) __mod_ ## a ## b |
18 | #define __module_cat(a,b) ___module_cat(a,b) | 21 | #define __module_cat(a,b) ___module_cat(a,b) |
@@ -79,7 +82,8 @@ struct kparam_array | |||
79 | #define __module_param_call(prefix, name, set, get, arg, perm) \ | 82 | #define __module_param_call(prefix, name, set, get, arg, perm) \ |
80 | /* Default value instead of permissions? */ \ | 83 | /* Default value instead of permissions? */ \ |
81 | static int __param_perm_check_##name __attribute__((unused)) = \ | 84 | static int __param_perm_check_##name __attribute__((unused)) = \ |
82 | BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)); \ | 85 | BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)) \ |
86 | + BUILD_BUG_ON_ZERO(sizeof(""prefix) > MAX_PARAM_PREFIX_LEN); \ | ||
83 | static const char __param_str_##name[] = prefix #name; \ | 87 | static const char __param_str_##name[] = prefix #name; \ |
84 | static struct kernel_param __moduleparam_const __param_##name \ | 88 | static struct kernel_param __moduleparam_const __param_##name \ |
85 | __used \ | 89 | __used \ |
@@ -100,6 +104,25 @@ struct kparam_array | |||
100 | #define module_param(name, type, perm) \ | 104 | #define module_param(name, type, perm) \ |
101 | module_param_named(name, name, type, perm) | 105 | module_param_named(name, name, type, perm) |
102 | 106 | ||
107 | #ifndef MODULE | ||
108 | /** | ||
109 | * core_param - define a historical core kernel parameter. | ||
110 | * @name: the name of the cmdline and sysfs parameter (often the same as var) | ||
111 | * @var: the variable | ||
112 | * @type: the type (for param_set_##type and param_get_##type) | ||
113 | * @perm: visibility in sysfs | ||
114 | * | ||
115 | * core_param is just like module_param(), but cannot be modular and | ||
116 | * doesn't add a prefix (such as "printk."). This is for compatibility | ||
117 | * with __setup(), and it makes sense as truly core parameters aren't | ||
118 | * tied to the particular file they're in. | ||
119 | */ | ||
120 | #define core_param(name, var, type, perm) \ | ||
121 | param_check_##type(name, &(var)); \ | ||
122 | __module_param_call("", name, param_set_##type, param_get_##type, \ | ||
123 | &var, perm) | ||
124 | #endif /* !MODULE */ | ||
125 | |||
103 | /* Actually copy string: maxlen param is usually sizeof(string). */ | 126 | /* Actually copy string: maxlen param is usually sizeof(string). */ |
104 | #define module_param_string(name, string, len, perm) \ | 127 | #define module_param_string(name, string, len, perm) \ |
105 | static const struct kparam_string __param_string_##name \ | 128 | static const struct kparam_string __param_string_##name \ |
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 5c158c477ac..89a5a1231ff 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h | |||
@@ -149,11 +149,11 @@ struct execute_work { | |||
149 | 149 | ||
150 | extern struct workqueue_struct * | 150 | extern struct workqueue_struct * |
151 | __create_workqueue_key(const char *name, int singlethread, | 151 | __create_workqueue_key(const char *name, int singlethread, |
152 | int freezeable, struct lock_class_key *key, | 152 | int freezeable, int rt, struct lock_class_key *key, |
153 | const char *lock_name); | 153 | const char *lock_name); |
154 | 154 | ||
155 | #ifdef CONFIG_LOCKDEP | 155 | #ifdef CONFIG_LOCKDEP |
156 | #define __create_workqueue(name, singlethread, freezeable) \ | 156 | #define __create_workqueue(name, singlethread, freezeable, rt) \ |
157 | ({ \ | 157 | ({ \ |
158 | static struct lock_class_key __key; \ | 158 | static struct lock_class_key __key; \ |
159 | const char *__lock_name; \ | 159 | const char *__lock_name; \ |
@@ -164,17 +164,19 @@ __create_workqueue_key(const char *name, int singlethread, | |||
164 | __lock_name = #name; \ | 164 | __lock_name = #name; \ |
165 | \ | 165 | \ |
166 | __create_workqueue_key((name), (singlethread), \ | 166 | __create_workqueue_key((name), (singlethread), \ |
167 | (freezeable), &__key, \ | 167 | (freezeable), (rt), &__key, \ |
168 | __lock_name); \ | 168 | __lock_name); \ |
169 | }) | 169 | }) |
170 | #else | 170 | #else |
171 | #define __create_workqueue(name, singlethread, freezeable) \ | 171 | #define __create_workqueue(name, singlethread, freezeable, rt) \ |
172 | __create_workqueue_key((name), (singlethread), (freezeable), NULL, NULL) | 172 | __create_workqueue_key((name), (singlethread), (freezeable), (rt), \ |
173 | NULL, NULL) | ||
173 | #endif | 174 | #endif |
174 | 175 | ||
175 | #define create_workqueue(name) __create_workqueue((name), 0, 0) | 176 | #define create_workqueue(name) __create_workqueue((name), 0, 0, 0) |
176 | #define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1) | 177 | #define create_rt_workqueue(name) __create_workqueue((name), 0, 0, 1) |
177 | #define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0) | 178 | #define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1, 0) |
179 | #define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0, 0) | ||
178 | 180 | ||
179 | extern void destroy_workqueue(struct workqueue_struct *wq); | 181 | extern void destroy_workqueue(struct workqueue_struct *wq); |
180 | 182 | ||
diff --git a/init/main.c b/init/main.c index 672ae75b205..b038fa14204 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -699,13 +699,7 @@ asmlinkage void __init start_kernel(void) | |||
699 | } | 699 | } |
700 | 700 | ||
701 | static int initcall_debug; | 701 | static int initcall_debug; |
702 | 702 | core_param(initcall_debug, initcall_debug, bool, 0644); | |
703 | static int __init initcall_debug_setup(char *str) | ||
704 | { | ||
705 | initcall_debug = 1; | ||
706 | return 1; | ||
707 | } | ||
708 | __setup("initcall_debug", initcall_debug_setup); | ||
709 | 703 | ||
710 | int do_one_initcall(initcall_t fn) | 704 | int do_one_initcall(initcall_t fn) |
711 | { | 705 | { |
@@ -775,8 +769,6 @@ static void __init do_initcalls(void) | |||
775 | static void __init do_basic_setup(void) | 769 | static void __init do_basic_setup(void) |
776 | { | 770 | { |
777 | rcu_init_sched(); /* needed by module_init stage. */ | 771 | rcu_init_sched(); /* needed by module_init stage. */ |
778 | /* drivers will send hotplug events */ | ||
779 | init_workqueues(); | ||
780 | usermodehelper_init(); | 772 | usermodehelper_init(); |
781 | driver_init(); | 773 | driver_init(); |
782 | init_irq_proc(); | 774 | init_irq_proc(); |
@@ -860,6 +852,8 @@ static int __init kernel_init(void * unused) | |||
860 | 852 | ||
861 | cad_pid = task_pid(current); | 853 | cad_pid = task_pid(current); |
862 | 854 | ||
855 | init_workqueues(); | ||
856 | |||
863 | smp_prepare_cpus(setup_max_cpus); | 857 | smp_prepare_cpus(setup_max_cpus); |
864 | 858 | ||
865 | do_pre_smp_initcalls(); | 859 | do_pre_smp_initcalls(); |
diff --git a/kernel/module.c b/kernel/module.c index 0d8d21ee792..c0f1826e2d9 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/string.h> | 42 | #include <linux/string.h> |
43 | #include <linux/mutex.h> | 43 | #include <linux/mutex.h> |
44 | #include <linux/unwind.h> | 44 | #include <linux/unwind.h> |
45 | #include <linux/rculist.h> | ||
45 | #include <asm/uaccess.h> | 46 | #include <asm/uaccess.h> |
46 | #include <asm/cacheflush.h> | 47 | #include <asm/cacheflush.h> |
47 | #include <linux/license.h> | 48 | #include <linux/license.h> |
@@ -63,7 +64,7 @@ | |||
63 | #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) | 64 | #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) |
64 | 65 | ||
65 | /* List of modules, protected by module_mutex or preempt_disable | 66 | /* List of modules, protected by module_mutex or preempt_disable |
66 | * (add/delete uses stop_machine). */ | 67 | * (delete uses stop_machine/add uses RCU list operations). */ |
67 | static DEFINE_MUTEX(module_mutex); | 68 | static DEFINE_MUTEX(module_mutex); |
68 | static LIST_HEAD(modules); | 69 | static LIST_HEAD(modules); |
69 | 70 | ||
@@ -132,6 +133,29 @@ static unsigned int find_sec(Elf_Ehdr *hdr, | |||
132 | return 0; | 133 | return 0; |
133 | } | 134 | } |
134 | 135 | ||
136 | /* Find a module section, or NULL. */ | ||
137 | static void *section_addr(Elf_Ehdr *hdr, Elf_Shdr *shdrs, | ||
138 | const char *secstrings, const char *name) | ||
139 | { | ||
140 | /* Section 0 has sh_addr 0. */ | ||
141 | return (void *)shdrs[find_sec(hdr, shdrs, secstrings, name)].sh_addr; | ||
142 | } | ||
143 | |||
144 | /* Find a module section, or NULL. Fill in number of "objects" in section. */ | ||
145 | static void *section_objs(Elf_Ehdr *hdr, | ||
146 | Elf_Shdr *sechdrs, | ||
147 | const char *secstrings, | ||
148 | const char *name, | ||
149 | size_t object_size, | ||
150 | unsigned int *num) | ||
151 | { | ||
152 | unsigned int sec = find_sec(hdr, sechdrs, secstrings, name); | ||
153 | |||
154 | /* Section 0 has sh_addr 0 and sh_size 0. */ | ||
155 | *num = sechdrs[sec].sh_size / object_size; | ||
156 | return (void *)sechdrs[sec].sh_addr; | ||
157 | } | ||
158 | |||
135 | /* Provided by the linker */ | 159 | /* Provided by the linker */ |
136 | extern const struct kernel_symbol __start___ksymtab[]; | 160 | extern const struct kernel_symbol __start___ksymtab[]; |
137 | extern const struct kernel_symbol __stop___ksymtab[]; | 161 | extern const struct kernel_symbol __stop___ksymtab[]; |
@@ -218,7 +242,7 @@ static bool each_symbol(bool (*fn)(const struct symsearch *arr, | |||
218 | if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data)) | 242 | if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data)) |
219 | return true; | 243 | return true; |
220 | 244 | ||
221 | list_for_each_entry(mod, &modules, list) { | 245 | list_for_each_entry_rcu(mod, &modules, list) { |
222 | struct symsearch arr[] = { | 246 | struct symsearch arr[] = { |
223 | { mod->syms, mod->syms + mod->num_syms, mod->crcs, | 247 | { mod->syms, mod->syms + mod->num_syms, mod->crcs, |
224 | NOT_GPL_ONLY, false }, | 248 | NOT_GPL_ONLY, false }, |
@@ -1394,17 +1418,6 @@ static void mod_kobject_remove(struct module *mod) | |||
1394 | } | 1418 | } |
1395 | 1419 | ||
1396 | /* | 1420 | /* |
1397 | * link the module with the whole machine is stopped with interrupts off | ||
1398 | * - this defends against kallsyms not taking locks | ||
1399 | */ | ||
1400 | static int __link_module(void *_mod) | ||
1401 | { | ||
1402 | struct module *mod = _mod; | ||
1403 | list_add(&mod->list, &modules); | ||
1404 | return 0; | ||
1405 | } | ||
1406 | |||
1407 | /* | ||
1408 | * unlink the module with the whole machine is stopped with interrupts off | 1421 | * unlink the module with the whole machine is stopped with interrupts off |
1409 | * - this defends against kallsyms not taking locks | 1422 | * - this defends against kallsyms not taking locks |
1410 | */ | 1423 | */ |
@@ -1789,32 +1802,20 @@ static inline void add_kallsyms(struct module *mod, | |||
1789 | } | 1802 | } |
1790 | #endif /* CONFIG_KALLSYMS */ | 1803 | #endif /* CONFIG_KALLSYMS */ |
1791 | 1804 | ||
1792 | #ifdef CONFIG_DYNAMIC_PRINTK_DEBUG | 1805 | static void dynamic_printk_setup(struct mod_debug *debug, unsigned int num) |
1793 | static void dynamic_printk_setup(Elf_Shdr *sechdrs, unsigned int verboseindex) | ||
1794 | { | 1806 | { |
1795 | struct mod_debug *debug_info; | 1807 | #ifdef CONFIG_DYNAMIC_PRINTK_DEBUG |
1796 | unsigned long pos, end; | 1808 | unsigned int i; |
1797 | unsigned int num_verbose; | ||
1798 | |||
1799 | pos = sechdrs[verboseindex].sh_addr; | ||
1800 | num_verbose = sechdrs[verboseindex].sh_size / | ||
1801 | sizeof(struct mod_debug); | ||
1802 | end = pos + (num_verbose * sizeof(struct mod_debug)); | ||
1803 | 1809 | ||
1804 | for (; pos < end; pos += sizeof(struct mod_debug)) { | 1810 | for (i = 0; i < num; i++) { |
1805 | debug_info = (struct mod_debug *)pos; | 1811 | register_dynamic_debug_module(debug[i].modname, |
1806 | register_dynamic_debug_module(debug_info->modname, | 1812 | debug[i].type, |
1807 | debug_info->type, debug_info->logical_modname, | 1813 | debug[i].logical_modname, |
1808 | debug_info->flag_names, debug_info->hash, | 1814 | debug[i].flag_names, |
1809 | debug_info->hash2); | 1815 | debug[i].hash, debug[i].hash2); |
1810 | } | 1816 | } |
1811 | } | ||
1812 | #else | ||
1813 | static inline void dynamic_printk_setup(Elf_Shdr *sechdrs, | ||
1814 | unsigned int verboseindex) | ||
1815 | { | ||
1816 | } | ||
1817 | #endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */ | 1817 | #endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */ |
1818 | } | ||
1818 | 1819 | ||
1819 | static void *module_alloc_update_bounds(unsigned long size) | 1820 | static void *module_alloc_update_bounds(unsigned long size) |
1820 | { | 1821 | { |
@@ -1843,37 +1844,14 @@ static noinline struct module *load_module(void __user *umod, | |||
1843 | unsigned int i; | 1844 | unsigned int i; |
1844 | unsigned int symindex = 0; | 1845 | unsigned int symindex = 0; |
1845 | unsigned int strindex = 0; | 1846 | unsigned int strindex = 0; |
1846 | unsigned int setupindex; | 1847 | unsigned int modindex, versindex, infoindex, pcpuindex; |
1847 | unsigned int exindex; | ||
1848 | unsigned int exportindex; | ||
1849 | unsigned int modindex; | ||
1850 | unsigned int obsparmindex; | ||
1851 | unsigned int infoindex; | ||
1852 | unsigned int gplindex; | ||
1853 | unsigned int crcindex; | ||
1854 | unsigned int gplcrcindex; | ||
1855 | unsigned int versindex; | ||
1856 | unsigned int pcpuindex; | ||
1857 | unsigned int gplfutureindex; | ||
1858 | unsigned int gplfuturecrcindex; | ||
1859 | unsigned int unwindex = 0; | 1848 | unsigned int unwindex = 0; |
1860 | #ifdef CONFIG_UNUSED_SYMBOLS | 1849 | unsigned int num_kp, num_mcount; |
1861 | unsigned int unusedindex; | 1850 | struct kernel_param *kp; |
1862 | unsigned int unusedcrcindex; | ||
1863 | unsigned int unusedgplindex; | ||
1864 | unsigned int unusedgplcrcindex; | ||
1865 | #endif | ||
1866 | unsigned int markersindex; | ||
1867 | unsigned int markersstringsindex; | ||
1868 | unsigned int verboseindex; | ||
1869 | unsigned int tracepointsindex; | ||
1870 | unsigned int tracepointsstringsindex; | ||
1871 | unsigned int mcountindex; | ||
1872 | struct module *mod; | 1851 | struct module *mod; |
1873 | long err = 0; | 1852 | long err = 0; |
1874 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ | 1853 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ |
1875 | void *mseg; | 1854 | unsigned long *mseg; |
1876 | struct exception_table_entry *extable; | ||
1877 | mm_segment_t old_fs; | 1855 | mm_segment_t old_fs; |
1878 | 1856 | ||
1879 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", | 1857 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", |
@@ -1937,6 +1915,7 @@ static noinline struct module *load_module(void __user *umod, | |||
1937 | err = -ENOEXEC; | 1915 | err = -ENOEXEC; |
1938 | goto free_hdr; | 1916 | goto free_hdr; |
1939 | } | 1917 | } |
1918 | /* This is temporary: point mod into copy of data. */ | ||
1940 | mod = (void *)sechdrs[modindex].sh_addr; | 1919 | mod = (void *)sechdrs[modindex].sh_addr; |
1941 | 1920 | ||
1942 | if (symindex == 0) { | 1921 | if (symindex == 0) { |
@@ -1946,22 +1925,6 @@ static noinline struct module *load_module(void __user *umod, | |||
1946 | goto free_hdr; | 1925 | goto free_hdr; |
1947 | } | 1926 | } |
1948 | 1927 | ||
1949 | /* Optional sections */ | ||
1950 | exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); | ||
1951 | gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); | ||
1952 | gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future"); | ||
1953 | crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); | ||
1954 | gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); | ||
1955 | gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future"); | ||
1956 | #ifdef CONFIG_UNUSED_SYMBOLS | ||
1957 | unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused"); | ||
1958 | unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl"); | ||
1959 | unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused"); | ||
1960 | unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl"); | ||
1961 | #endif | ||
1962 | setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); | ||
1963 | exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); | ||
1964 | obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); | ||
1965 | versindex = find_sec(hdr, sechdrs, secstrings, "__versions"); | 1928 | versindex = find_sec(hdr, sechdrs, secstrings, "__versions"); |
1966 | infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo"); | 1929 | infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo"); |
1967 | pcpuindex = find_pcpusec(hdr, sechdrs, secstrings); | 1930 | pcpuindex = find_pcpusec(hdr, sechdrs, secstrings); |
@@ -2117,42 +2080,57 @@ static noinline struct module *load_module(void __user *umod, | |||
2117 | if (err < 0) | 2080 | if (err < 0) |
2118 | goto cleanup; | 2081 | goto cleanup; |
2119 | 2082 | ||
2120 | /* Set up EXPORTed & EXPORT_GPLed symbols (section 0 is 0 length) */ | 2083 | /* Now we've got everything in the final locations, we can |
2121 | mod->num_syms = sechdrs[exportindex].sh_size / sizeof(*mod->syms); | 2084 | * find optional sections. */ |
2122 | mod->syms = (void *)sechdrs[exportindex].sh_addr; | 2085 | kp = section_objs(hdr, sechdrs, secstrings, "__param", sizeof(*kp), |
2123 | if (crcindex) | 2086 | &num_kp); |
2124 | mod->crcs = (void *)sechdrs[crcindex].sh_addr; | 2087 | mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab", |
2125 | mod->num_gpl_syms = sechdrs[gplindex].sh_size / sizeof(*mod->gpl_syms); | 2088 | sizeof(*mod->syms), &mod->num_syms); |
2126 | mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr; | 2089 | mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab"); |
2127 | if (gplcrcindex) | 2090 | mod->gpl_syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab_gpl", |
2128 | mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; | 2091 | sizeof(*mod->gpl_syms), |
2129 | mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size / | 2092 | &mod->num_gpl_syms); |
2130 | sizeof(*mod->gpl_future_syms); | 2093 | mod->gpl_crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab_gpl"); |
2131 | mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; | 2094 | mod->gpl_future_syms = section_objs(hdr, sechdrs, secstrings, |
2132 | if (gplfuturecrcindex) | 2095 | "__ksymtab_gpl_future", |
2133 | mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; | 2096 | sizeof(*mod->gpl_future_syms), |
2097 | &mod->num_gpl_future_syms); | ||
2098 | mod->gpl_future_crcs = section_addr(hdr, sechdrs, secstrings, | ||
2099 | "__kcrctab_gpl_future"); | ||
2134 | 2100 | ||
2135 | #ifdef CONFIG_UNUSED_SYMBOLS | 2101 | #ifdef CONFIG_UNUSED_SYMBOLS |
2136 | mod->num_unused_syms = sechdrs[unusedindex].sh_size / | 2102 | mod->unused_syms = section_objs(hdr, sechdrs, secstrings, |
2137 | sizeof(*mod->unused_syms); | 2103 | "__ksymtab_unused", |
2138 | mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size / | 2104 | sizeof(*mod->unused_syms), |
2139 | sizeof(*mod->unused_gpl_syms); | 2105 | &mod->num_unused_syms); |
2140 | mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr; | 2106 | mod->unused_crcs = section_addr(hdr, sechdrs, secstrings, |
2141 | if (unusedcrcindex) | 2107 | "__kcrctab_unused"); |
2142 | mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; | 2108 | mod->unused_gpl_syms = section_objs(hdr, sechdrs, secstrings, |
2143 | mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr; | 2109 | "__ksymtab_unused_gpl", |
2144 | if (unusedgplcrcindex) | 2110 | sizeof(*mod->unused_gpl_syms), |
2145 | mod->unused_gpl_crcs | 2111 | &mod->num_unused_gpl_syms); |
2146 | = (void *)sechdrs[unusedgplcrcindex].sh_addr; | 2112 | mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings, |
2113 | "__kcrctab_unused_gpl"); | ||
2114 | #endif | ||
2115 | |||
2116 | #ifdef CONFIG_MARKERS | ||
2117 | mod->markers = section_objs(hdr, sechdrs, secstrings, "__markers", | ||
2118 | sizeof(*mod->markers), &mod->num_markers); | ||
2119 | #endif | ||
2120 | #ifdef CONFIG_TRACEPOINTS | ||
2121 | mod->tracepoints = section_objs(hdr, sechdrs, secstrings, | ||
2122 | "__tracepoints", | ||
2123 | sizeof(*mod->tracepoints), | ||
2124 | &mod->num_tracepoints); | ||
2147 | #endif | 2125 | #endif |
2148 | 2126 | ||
2149 | #ifdef CONFIG_MODVERSIONS | 2127 | #ifdef CONFIG_MODVERSIONS |
2150 | if ((mod->num_syms && !crcindex) | 2128 | if ((mod->num_syms && !mod->crcs) |
2151 | || (mod->num_gpl_syms && !gplcrcindex) | 2129 | || (mod->num_gpl_syms && !mod->gpl_crcs) |
2152 | || (mod->num_gpl_future_syms && !gplfuturecrcindex) | 2130 | || (mod->num_gpl_future_syms && !mod->gpl_future_crcs) |
2153 | #ifdef CONFIG_UNUSED_SYMBOLS | 2131 | #ifdef CONFIG_UNUSED_SYMBOLS |
2154 | || (mod->num_unused_syms && !unusedcrcindex) | 2132 | || (mod->num_unused_syms && !mod->unused_crcs) |
2155 | || (mod->num_unused_gpl_syms && !unusedgplcrcindex) | 2133 | || (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs) |
2156 | #endif | 2134 | #endif |
2157 | ) { | 2135 | ) { |
2158 | printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name); | 2136 | 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, | |||
2161 | goto cleanup; | 2139 | goto cleanup; |
2162 | } | 2140 | } |
2163 | #endif | 2141 | #endif |
2164 | markersindex = find_sec(hdr, sechdrs, secstrings, "__markers"); | ||
2165 | markersstringsindex = find_sec(hdr, sechdrs, secstrings, | ||
2166 | "__markers_strings"); | ||
2167 | verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose"); | ||
2168 | tracepointsindex = find_sec(hdr, sechdrs, secstrings, "__tracepoints"); | ||
2169 | tracepointsstringsindex = find_sec(hdr, sechdrs, secstrings, | ||
2170 | "__tracepoints_strings"); | ||
2171 | |||
2172 | mcountindex = find_sec(hdr, sechdrs, secstrings, | ||
2173 | "__mcount_loc"); | ||
2174 | 2142 | ||
2175 | /* Now do relocations. */ | 2143 | /* Now do relocations. */ |
2176 | for (i = 1; i < hdr->e_shnum; i++) { | 2144 | for (i = 1; i < hdr->e_shnum; i++) { |
@@ -2193,28 +2161,16 @@ static noinline struct module *load_module(void __user *umod, | |||
2193 | if (err < 0) | 2161 | if (err < 0) |
2194 | goto cleanup; | 2162 | goto cleanup; |
2195 | } | 2163 | } |
2196 | #ifdef CONFIG_MARKERS | ||
2197 | mod->markers = (void *)sechdrs[markersindex].sh_addr; | ||
2198 | mod->num_markers = | ||
2199 | sechdrs[markersindex].sh_size / sizeof(*mod->markers); | ||
2200 | #endif | ||
2201 | #ifdef CONFIG_TRACEPOINTS | ||
2202 | mod->tracepoints = (void *)sechdrs[tracepointsindex].sh_addr; | ||
2203 | mod->num_tracepoints = | ||
2204 | sechdrs[tracepointsindex].sh_size / sizeof(*mod->tracepoints); | ||
2205 | #endif | ||
2206 | |||
2207 | 2164 | ||
2208 | /* Find duplicate symbols */ | 2165 | /* Find duplicate symbols */ |
2209 | err = verify_export_symbols(mod); | 2166 | err = verify_export_symbols(mod); |
2210 | |||
2211 | if (err < 0) | 2167 | if (err < 0) |
2212 | goto cleanup; | 2168 | goto cleanup; |
2213 | 2169 | ||
2214 | /* Set up and sort exception table */ | 2170 | /* Set up and sort exception table */ |
2215 | mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable); | 2171 | mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table", |
2216 | mod->extable = extable = (void *)sechdrs[exindex].sh_addr; | 2172 | sizeof(*mod->extable), &mod->num_exentries); |
2217 | sort_extable(extable, extable + mod->num_exentries); | 2173 | sort_extable(mod->extable, mod->extable + mod->num_exentries); |
2218 | 2174 | ||
2219 | /* Finally, copy percpu area over. */ | 2175 | /* Finally, copy percpu area over. */ |
2220 | percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr, | 2176 | percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr, |
@@ -2223,11 +2179,17 @@ static noinline struct module *load_module(void __user *umod, | |||
2223 | add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); | 2179 | add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); |
2224 | 2180 | ||
2225 | if (!mod->taints) { | 2181 | if (!mod->taints) { |
2182 | struct mod_debug *debug; | ||
2183 | unsigned int num_debug; | ||
2184 | |||
2226 | #ifdef CONFIG_MARKERS | 2185 | #ifdef CONFIG_MARKERS |
2227 | marker_update_probe_range(mod->markers, | 2186 | marker_update_probe_range(mod->markers, |
2228 | mod->markers + mod->num_markers); | 2187 | mod->markers + mod->num_markers); |
2229 | #endif | 2188 | #endif |
2230 | dynamic_printk_setup(sechdrs, verboseindex); | 2189 | debug = section_objs(hdr, sechdrs, secstrings, "__verbose", |
2190 | sizeof(*debug), &num_debug); | ||
2191 | dynamic_printk_setup(debug, num_debug); | ||
2192 | |||
2231 | #ifdef CONFIG_TRACEPOINTS | 2193 | #ifdef CONFIG_TRACEPOINTS |
2232 | tracepoint_update_probe_range(mod->tracepoints, | 2194 | tracepoint_update_probe_range(mod->tracepoints, |
2233 | mod->tracepoints + mod->num_tracepoints); | 2195 | mod->tracepoints + mod->num_tracepoints); |
@@ -2235,8 +2197,9 @@ static noinline struct module *load_module(void __user *umod, | |||
2235 | } | 2197 | } |
2236 | 2198 | ||
2237 | /* sechdrs[0].sh_size is always zero */ | 2199 | /* sechdrs[0].sh_size is always zero */ |
2238 | mseg = (void *)sechdrs[mcountindex].sh_addr; | 2200 | mseg = section_objs(hdr, sechdrs, secstrings, "__mcount_loc", |
2239 | ftrace_init_module(mseg, mseg + sechdrs[mcountindex].sh_size); | 2201 | sizeof(*mseg), &num_mcount); |
2202 | ftrace_init_module(mseg, mseg + num_mcount); | ||
2240 | 2203 | ||
2241 | err = module_finalize(hdr, sechdrs, mod); | 2204 | err = module_finalize(hdr, sechdrs, mod); |
2242 | if (err < 0) | 2205 | if (err < 0) |
@@ -2261,30 +2224,24 @@ static noinline struct module *load_module(void __user *umod, | |||
2261 | set_fs(old_fs); | 2224 | set_fs(old_fs); |
2262 | 2225 | ||
2263 | mod->args = args; | 2226 | mod->args = args; |
2264 | if (obsparmindex) | 2227 | if (section_addr(hdr, sechdrs, secstrings, "__obsparm")) |
2265 | printk(KERN_WARNING "%s: Ignoring obsolete parameters\n", | 2228 | printk(KERN_WARNING "%s: Ignoring obsolete parameters\n", |
2266 | mod->name); | 2229 | mod->name); |
2267 | 2230 | ||
2268 | /* Now sew it into the lists so we can get lockdep and oops | 2231 | /* Now sew it into the lists so we can get lockdep and oops |
2269 | * info during argument parsing. Noone should access us, since | 2232 | * info during argument parsing. Noone should access us, since |
2270 | * strong_try_module_get() will fail. */ | 2233 | * strong_try_module_get() will fail. |
2271 | stop_machine(__link_module, mod, NULL); | 2234 | * lockdep/oops can run asynchronous, so use the RCU list insertion |
2272 | 2235 | * function to insert in a way safe to concurrent readers. | |
2273 | /* Size of section 0 is 0, so this works well if no params */ | 2236 | * The mutex protects against concurrent writers. |
2274 | err = parse_args(mod->name, mod->args, | 2237 | */ |
2275 | (struct kernel_param *) | 2238 | list_add_rcu(&mod->list, &modules); |
2276 | sechdrs[setupindex].sh_addr, | 2239 | |
2277 | sechdrs[setupindex].sh_size | 2240 | err = parse_args(mod->name, mod->args, kp, num_kp, NULL); |
2278 | / sizeof(struct kernel_param), | ||
2279 | NULL); | ||
2280 | if (err < 0) | 2241 | if (err < 0) |
2281 | goto unlink; | 2242 | goto unlink; |
2282 | 2243 | ||
2283 | err = mod_sysfs_setup(mod, | 2244 | err = mod_sysfs_setup(mod, kp, num_kp); |
2284 | (struct kernel_param *) | ||
2285 | sechdrs[setupindex].sh_addr, | ||
2286 | sechdrs[setupindex].sh_size | ||
2287 | / sizeof(struct kernel_param)); | ||
2288 | if (err < 0) | 2245 | if (err < 0) |
2289 | goto unlink; | 2246 | goto unlink; |
2290 | add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); | 2247 | add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); |
@@ -2473,7 +2430,7 @@ const char *module_address_lookup(unsigned long addr, | |||
2473 | const char *ret = NULL; | 2430 | const char *ret = NULL; |
2474 | 2431 | ||
2475 | preempt_disable(); | 2432 | preempt_disable(); |
2476 | list_for_each_entry(mod, &modules, list) { | 2433 | list_for_each_entry_rcu(mod, &modules, list) { |
2477 | if (within(addr, mod->module_init, mod->init_size) | 2434 | if (within(addr, mod->module_init, mod->init_size) |
2478 | || within(addr, mod->module_core, mod->core_size)) { | 2435 | || within(addr, mod->module_core, mod->core_size)) { |
2479 | if (modname) | 2436 | if (modname) |
@@ -2496,7 +2453,7 @@ int lookup_module_symbol_name(unsigned long addr, char *symname) | |||
2496 | struct module *mod; | 2453 | struct module *mod; |
2497 | 2454 | ||
2498 | preempt_disable(); | 2455 | preempt_disable(); |
2499 | list_for_each_entry(mod, &modules, list) { | 2456 | list_for_each_entry_rcu(mod, &modules, list) { |
2500 | if (within(addr, mod->module_init, mod->init_size) || | 2457 | if (within(addr, mod->module_init, mod->init_size) || |
2501 | within(addr, mod->module_core, mod->core_size)) { | 2458 | within(addr, mod->module_core, mod->core_size)) { |
2502 | const char *sym; | 2459 | const char *sym; |
@@ -2520,7 +2477,7 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, | |||
2520 | struct module *mod; | 2477 | struct module *mod; |
2521 | 2478 | ||
2522 | preempt_disable(); | 2479 | preempt_disable(); |
2523 | list_for_each_entry(mod, &modules, list) { | 2480 | list_for_each_entry_rcu(mod, &modules, list) { |
2524 | if (within(addr, mod->module_init, mod->init_size) || | 2481 | if (within(addr, mod->module_init, mod->init_size) || |
2525 | within(addr, mod->module_core, mod->core_size)) { | 2482 | within(addr, mod->module_core, mod->core_size)) { |
2526 | const char *sym; | 2483 | const char *sym; |
@@ -2547,7 +2504,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, | |||
2547 | struct module *mod; | 2504 | struct module *mod; |
2548 | 2505 | ||
2549 | preempt_disable(); | 2506 | preempt_disable(); |
2550 | list_for_each_entry(mod, &modules, list) { | 2507 | list_for_each_entry_rcu(mod, &modules, list) { |
2551 | if (symnum < mod->num_symtab) { | 2508 | if (symnum < mod->num_symtab) { |
2552 | *value = mod->symtab[symnum].st_value; | 2509 | *value = mod->symtab[symnum].st_value; |
2553 | *type = mod->symtab[symnum].st_info; | 2510 | *type = mod->symtab[symnum].st_info; |
@@ -2590,7 +2547,7 @@ unsigned long module_kallsyms_lookup_name(const char *name) | |||
2590 | ret = mod_find_symname(mod, colon+1); | 2547 | ret = mod_find_symname(mod, colon+1); |
2591 | *colon = ':'; | 2548 | *colon = ':'; |
2592 | } else { | 2549 | } else { |
2593 | list_for_each_entry(mod, &modules, list) | 2550 | list_for_each_entry_rcu(mod, &modules, list) |
2594 | if ((ret = mod_find_symname(mod, name)) != 0) | 2551 | if ((ret = mod_find_symname(mod, name)) != 0) |
2595 | break; | 2552 | break; |
2596 | } | 2553 | } |
@@ -2693,7 +2650,7 @@ const struct exception_table_entry *search_module_extables(unsigned long addr) | |||
2693 | struct module *mod; | 2650 | struct module *mod; |
2694 | 2651 | ||
2695 | preempt_disable(); | 2652 | preempt_disable(); |
2696 | list_for_each_entry(mod, &modules, list) { | 2653 | list_for_each_entry_rcu(mod, &modules, list) { |
2697 | if (mod->num_exentries == 0) | 2654 | if (mod->num_exentries == 0) |
2698 | continue; | 2655 | continue; |
2699 | 2656 | ||
@@ -2719,7 +2676,7 @@ int is_module_address(unsigned long addr) | |||
2719 | 2676 | ||
2720 | preempt_disable(); | 2677 | preempt_disable(); |
2721 | 2678 | ||
2722 | list_for_each_entry(mod, &modules, list) { | 2679 | list_for_each_entry_rcu(mod, &modules, list) { |
2723 | if (within(addr, mod->module_core, mod->core_size)) { | 2680 | if (within(addr, mod->module_core, mod->core_size)) { |
2724 | preempt_enable(); | 2681 | preempt_enable(); |
2725 | return 1; | 2682 | return 1; |
@@ -2740,7 +2697,7 @@ struct module *__module_text_address(unsigned long addr) | |||
2740 | if (addr < module_addr_min || addr > module_addr_max) | 2697 | if (addr < module_addr_min || addr > module_addr_max) |
2741 | return NULL; | 2698 | return NULL; |
2742 | 2699 | ||
2743 | list_for_each_entry(mod, &modules, list) | 2700 | list_for_each_entry_rcu(mod, &modules, list) |
2744 | if (within(addr, mod->module_init, mod->init_text_size) | 2701 | if (within(addr, mod->module_init, mod->init_text_size) |
2745 | || within(addr, mod->module_core, mod->core_text_size)) | 2702 | || within(addr, mod->module_core, mod->core_text_size)) |
2746 | return mod; | 2703 | return mod; |
@@ -2765,8 +2722,11 @@ void print_modules(void) | |||
2765 | char buf[8]; | 2722 | char buf[8]; |
2766 | 2723 | ||
2767 | printk("Modules linked in:"); | 2724 | printk("Modules linked in:"); |
2768 | list_for_each_entry(mod, &modules, list) | 2725 | /* Most callers should already have preempt disabled, but make sure */ |
2726 | preempt_disable(); | ||
2727 | list_for_each_entry_rcu(mod, &modules, list) | ||
2769 | printk(" %s%s", mod->name, module_flags(mod, buf)); | 2728 | printk(" %s%s", mod->name, module_flags(mod, buf)); |
2729 | preempt_enable(); | ||
2770 | if (last_unloaded_module[0]) | 2730 | if (last_unloaded_module[0]) |
2771 | printk(" [last unloaded: %s]", last_unloaded_module); | 2731 | printk(" [last unloaded: %s]", last_unloaded_module); |
2772 | printk("\n"); | 2732 | printk("\n"); |
diff --git a/kernel/panic.c b/kernel/panic.c index bda561ef3cd..6513aac8e99 100644 --- a/kernel/panic.c +++ b/kernel/panic.c | |||
@@ -34,13 +34,6 @@ ATOMIC_NOTIFIER_HEAD(panic_notifier_list); | |||
34 | 34 | ||
35 | EXPORT_SYMBOL(panic_notifier_list); | 35 | EXPORT_SYMBOL(panic_notifier_list); |
36 | 36 | ||
37 | static int __init panic_setup(char *str) | ||
38 | { | ||
39 | panic_timeout = simple_strtoul(str, NULL, 0); | ||
40 | return 1; | ||
41 | } | ||
42 | __setup("panic=", panic_setup); | ||
43 | |||
44 | static long no_blink(long time) | 37 | static long no_blink(long time) |
45 | { | 38 | { |
46 | return 0; | 39 | return 0; |
@@ -218,13 +211,6 @@ void add_taint(unsigned flag) | |||
218 | } | 211 | } |
219 | EXPORT_SYMBOL(add_taint); | 212 | EXPORT_SYMBOL(add_taint); |
220 | 213 | ||
221 | static int __init pause_on_oops_setup(char *str) | ||
222 | { | ||
223 | pause_on_oops = simple_strtoul(str, NULL, 0); | ||
224 | return 1; | ||
225 | } | ||
226 | __setup("pause_on_oops=", pause_on_oops_setup); | ||
227 | |||
228 | static void spin_msec(int msecs) | 214 | static void spin_msec(int msecs) |
229 | { | 215 | { |
230 | int i; | 216 | int i; |
@@ -384,3 +370,6 @@ void __stack_chk_fail(void) | |||
384 | } | 370 | } |
385 | EXPORT_SYMBOL(__stack_chk_fail); | 371 | EXPORT_SYMBOL(__stack_chk_fail); |
386 | #endif | 372 | #endif |
373 | |||
374 | core_param(panic, panic_timeout, int, 0644); | ||
375 | core_param(pause_on_oops, pause_on_oops, int, 0644); | ||
diff --git a/kernel/params.c b/kernel/params.c index afc46a23eb6..b077f1b045d 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
@@ -373,6 +373,8 @@ int param_get_string(char *buffer, struct kernel_param *kp) | |||
373 | } | 373 | } |
374 | 374 | ||
375 | /* sysfs output in /sys/modules/XYZ/parameters/ */ | 375 | /* sysfs output in /sys/modules/XYZ/parameters/ */ |
376 | #define to_module_attr(n) container_of(n, struct module_attribute, attr); | ||
377 | #define to_module_kobject(n) container_of(n, struct module_kobject, kobj); | ||
376 | 378 | ||
377 | extern struct kernel_param __start___param[], __stop___param[]; | 379 | extern struct kernel_param __start___param[], __stop___param[]; |
378 | 380 | ||
@@ -384,6 +386,7 @@ struct param_attribute | |||
384 | 386 | ||
385 | struct module_param_attrs | 387 | struct module_param_attrs |
386 | { | 388 | { |
389 | unsigned int num; | ||
387 | struct attribute_group grp; | 390 | struct attribute_group grp; |
388 | struct param_attribute attrs[0]; | 391 | struct param_attribute attrs[0]; |
389 | }; | 392 | }; |
@@ -434,69 +437,84 @@ static ssize_t param_attr_store(struct module_attribute *mattr, | |||
434 | 437 | ||
435 | #ifdef CONFIG_SYSFS | 438 | #ifdef CONFIG_SYSFS |
436 | /* | 439 | /* |
437 | * param_sysfs_setup - setup sysfs support for one module or KBUILD_MODNAME | 440 | * add_sysfs_param - add a parameter to sysfs |
438 | * @mk: struct module_kobject (contains parent kobject) | 441 | * @mk: struct module_kobject |
439 | * @kparam: array of struct kernel_param, the actual parameter definitions | 442 | * @kparam: the actual parameter definition to add to sysfs |
440 | * @num_params: number of entries in array | 443 | * @name: name of parameter |
441 | * @name_skip: offset where the parameter name start in kparam[].name. Needed for built-in "modules" | ||
442 | * | 444 | * |
443 | * Create a kobject for a (per-module) group of parameters, and create files | 445 | * Create a kobject if for a (per-module) parameter if mp NULL, and |
444 | * in sysfs. A pointer to the param_kobject is returned on success, | 446 | * create file in sysfs. Returns an error on out of memory. Always cleans up |
445 | * NULL if there's no parameter to export, or other ERR_PTR(err). | 447 | * if there's an error. |
446 | */ | 448 | */ |
447 | static __modinit struct module_param_attrs * | 449 | static __modinit int add_sysfs_param(struct module_kobject *mk, |
448 | param_sysfs_setup(struct module_kobject *mk, | 450 | struct kernel_param *kp, |
449 | struct kernel_param *kparam, | 451 | const char *name) |
450 | unsigned int num_params, | ||
451 | unsigned int name_skip) | ||
452 | { | 452 | { |
453 | struct module_param_attrs *mp; | 453 | struct module_param_attrs *new; |
454 | unsigned int valid_attrs = 0; | 454 | struct attribute **attrs; |
455 | unsigned int i, size[2]; | 455 | int err, num; |
456 | struct param_attribute *pattr; | 456 | |
457 | struct attribute **gattr; | 457 | /* We don't bother calling this with invisible parameters. */ |
458 | int err; | 458 | BUG_ON(!kp->perm); |
459 | 459 | ||
460 | for (i=0; i<num_params; i++) { | 460 | if (!mk->mp) { |
461 | if (kparam[i].perm) | 461 | num = 0; |
462 | valid_attrs++; | 462 | attrs = NULL; |
463 | } else { | ||
464 | num = mk->mp->num; | ||
465 | attrs = mk->mp->grp.attrs; | ||
463 | } | 466 | } |
464 | 467 | ||
465 | if (!valid_attrs) | 468 | /* Enlarge. */ |
466 | return NULL; | 469 | new = krealloc(mk->mp, |
467 | 470 | sizeof(*mk->mp) + sizeof(mk->mp->attrs[0]) * (num+1), | |
468 | size[0] = ALIGN(sizeof(*mp) + | 471 | GFP_KERNEL); |
469 | valid_attrs * sizeof(mp->attrs[0]), | 472 | if (!new) { |
470 | sizeof(mp->grp.attrs[0])); | 473 | kfree(mk->mp); |
471 | size[1] = (valid_attrs + 1) * sizeof(mp->grp.attrs[0]); | 474 | err = -ENOMEM; |
472 | 475 | goto fail; | |
473 | mp = kzalloc(size[0] + size[1], GFP_KERNEL); | 476 | } |
474 | if (!mp) | 477 | attrs = krealloc(attrs, sizeof(new->grp.attrs[0])*(num+2), GFP_KERNEL); |
475 | return ERR_PTR(-ENOMEM); | 478 | if (!attrs) { |
479 | err = -ENOMEM; | ||
480 | goto fail_free_new; | ||
481 | } | ||
476 | 482 | ||
477 | mp->grp.name = "parameters"; | 483 | /* Sysfs wants everything zeroed. */ |
478 | mp->grp.attrs = (void *)mp + size[0]; | 484 | memset(new, 0, sizeof(*new)); |
485 | memset(&new->attrs[num], 0, sizeof(new->attrs[num])); | ||
486 | memset(&attrs[num], 0, sizeof(attrs[num])); | ||
487 | new->grp.name = "parameters"; | ||
488 | new->grp.attrs = attrs; | ||
489 | |||
490 | /* Tack new one on the end. */ | ||
491 | new->attrs[num].param = kp; | ||
492 | new->attrs[num].mattr.show = param_attr_show; | ||
493 | new->attrs[num].mattr.store = param_attr_store; | ||
494 | new->attrs[num].mattr.attr.name = (char *)name; | ||
495 | new->attrs[num].mattr.attr.mode = kp->perm; | ||
496 | new->num = num+1; | ||
497 | |||
498 | /* Fix up all the pointers, since krealloc can move us */ | ||
499 | for (num = 0; num < new->num; num++) | ||
500 | new->grp.attrs[num] = &new->attrs[num].mattr.attr; | ||
501 | new->grp.attrs[num] = NULL; | ||
502 | |||
503 | mk->mp = new; | ||
504 | return 0; | ||
479 | 505 | ||
480 | pattr = &mp->attrs[0]; | 506 | fail_free_new: |
481 | gattr = &mp->grp.attrs[0]; | 507 | kfree(new); |
482 | for (i = 0; i < num_params; i++) { | 508 | fail: |
483 | struct kernel_param *kp = &kparam[i]; | 509 | mk->mp = NULL; |
484 | if (kp->perm) { | 510 | return err; |
485 | pattr->param = kp; | 511 | } |
486 | pattr->mattr.show = param_attr_show; | ||
487 | pattr->mattr.store = param_attr_store; | ||
488 | pattr->mattr.attr.name = (char *)&kp->name[name_skip]; | ||
489 | pattr->mattr.attr.mode = kp->perm; | ||
490 | *(gattr++) = &(pattr++)->mattr.attr; | ||
491 | } | ||
492 | } | ||
493 | *gattr = NULL; | ||
494 | 512 | ||
495 | if ((err = sysfs_create_group(&mk->kobj, &mp->grp))) { | 513 | static void free_module_param_attrs(struct module_kobject *mk) |
496 | kfree(mp); | 514 | { |
497 | return ERR_PTR(err); | 515 | kfree(mk->mp->grp.attrs); |
498 | } | 516 | kfree(mk->mp); |
499 | return mp; | 517 | mk->mp = NULL; |
500 | } | 518 | } |
501 | 519 | ||
502 | #ifdef CONFIG_MODULES | 520 | #ifdef CONFIG_MODULES |
@@ -506,21 +524,33 @@ param_sysfs_setup(struct module_kobject *mk, | |||
506 | * @kparam: module parameters (array) | 524 | * @kparam: module parameters (array) |
507 | * @num_params: number of module parameters | 525 | * @num_params: number of module parameters |
508 | * | 526 | * |
509 | * Adds sysfs entries for module parameters, and creates a link from | 527 | * Adds sysfs entries for module parameters under |
510 | * /sys/module/[mod->name]/parameters to /sys/parameters/[mod->name]/ | 528 | * /sys/module/[mod->name]/parameters/ |
511 | */ | 529 | */ |
512 | int module_param_sysfs_setup(struct module *mod, | 530 | int module_param_sysfs_setup(struct module *mod, |
513 | struct kernel_param *kparam, | 531 | struct kernel_param *kparam, |
514 | unsigned int num_params) | 532 | unsigned int num_params) |
515 | { | 533 | { |
516 | struct module_param_attrs *mp; | 534 | int i, err; |
535 | bool params = false; | ||
536 | |||
537 | for (i = 0; i < num_params; i++) { | ||
538 | if (kparam[i].perm == 0) | ||
539 | continue; | ||
540 | err = add_sysfs_param(&mod->mkobj, &kparam[i], kparam[i].name); | ||
541 | if (err) | ||
542 | return err; | ||
543 | params = true; | ||
544 | } | ||
517 | 545 | ||
518 | mp = param_sysfs_setup(&mod->mkobj, kparam, num_params, 0); | 546 | if (!params) |
519 | if (IS_ERR(mp)) | 547 | return 0; |
520 | return PTR_ERR(mp); | ||
521 | 548 | ||
522 | mod->param_attrs = mp; | 549 | /* Create the param group. */ |
523 | return 0; | 550 | err = sysfs_create_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp); |
551 | if (err) | ||
552 | free_module_param_attrs(&mod->mkobj); | ||
553 | return err; | ||
524 | } | 554 | } |
525 | 555 | ||
526 | /* | 556 | /* |
@@ -532,43 +562,55 @@ int module_param_sysfs_setup(struct module *mod, | |||
532 | */ | 562 | */ |
533 | void module_param_sysfs_remove(struct module *mod) | 563 | void module_param_sysfs_remove(struct module *mod) |
534 | { | 564 | { |
535 | if (mod->param_attrs) { | 565 | if (mod->mkobj.mp) { |
536 | sysfs_remove_group(&mod->mkobj.kobj, | 566 | sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp); |
537 | &mod->param_attrs->grp); | ||
538 | /* We are positive that no one is using any param | 567 | /* We are positive that no one is using any param |
539 | * attrs at this point. Deallocate immediately. */ | 568 | * attrs at this point. Deallocate immediately. */ |
540 | kfree(mod->param_attrs); | 569 | free_module_param_attrs(&mod->mkobj); |
541 | mod->param_attrs = NULL; | ||
542 | } | 570 | } |
543 | } | 571 | } |
544 | #endif | 572 | #endif |
545 | 573 | ||
546 | /* | 574 | static void __init kernel_add_sysfs_param(const char *name, |
547 | * kernel_param_sysfs_setup - wrapper for built-in params support | 575 | struct kernel_param *kparam, |
548 | */ | 576 | unsigned int name_skip) |
549 | static void __init kernel_param_sysfs_setup(const char *name, | ||
550 | struct kernel_param *kparam, | ||
551 | unsigned int num_params, | ||
552 | unsigned int name_skip) | ||
553 | { | 577 | { |
554 | struct module_kobject *mk; | 578 | struct module_kobject *mk; |
555 | int ret; | 579 | struct kobject *kobj; |
580 | int err; | ||
556 | 581 | ||
557 | mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL); | 582 | kobj = kset_find_obj(module_kset, name); |
558 | BUG_ON(!mk); | 583 | if (kobj) { |
559 | 584 | /* We already have one. Remove params so we can add more. */ | |
560 | mk->mod = THIS_MODULE; | 585 | mk = to_module_kobject(kobj); |
561 | mk->kobj.kset = module_kset; | 586 | /* We need to remove it before adding parameters. */ |
562 | ret = kobject_init_and_add(&mk->kobj, &module_ktype, NULL, "%s", name); | 587 | sysfs_remove_group(&mk->kobj, &mk->mp->grp); |
563 | if (ret) { | 588 | } else { |
564 | kobject_put(&mk->kobj); | 589 | mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL); |
565 | printk(KERN_ERR "Module '%s' failed to be added to sysfs, " | 590 | BUG_ON(!mk); |
566 | "error number %d\n", name, ret); | 591 | |
567 | printk(KERN_ERR "The system will be unstable now.\n"); | 592 | mk->mod = THIS_MODULE; |
568 | return; | 593 | mk->kobj.kset = module_kset; |
594 | err = kobject_init_and_add(&mk->kobj, &module_ktype, NULL, | ||
595 | "%s", name); | ||
596 | if (err) { | ||
597 | kobject_put(&mk->kobj); | ||
598 | printk(KERN_ERR "Module '%s' failed add to sysfs, " | ||
599 | "error number %d\n", name, err); | ||
600 | printk(KERN_ERR "The system will be unstable now.\n"); | ||
601 | return; | ||
602 | } | ||
603 | /* So that exit path is even. */ | ||
604 | kobject_get(&mk->kobj); | ||
569 | } | 605 | } |
570 | param_sysfs_setup(mk, kparam, num_params, name_skip); | 606 | |
607 | /* These should not fail at boot. */ | ||
608 | err = add_sysfs_param(mk, kparam, kparam->name + name_skip); | ||
609 | BUG_ON(err); | ||
610 | err = sysfs_create_group(&mk->kobj, &mk->mp->grp); | ||
611 | BUG_ON(err); | ||
571 | kobject_uevent(&mk->kobj, KOBJ_ADD); | 612 | kobject_uevent(&mk->kobj, KOBJ_ADD); |
613 | kobject_put(&mk->kobj); | ||
572 | } | 614 | } |
573 | 615 | ||
574 | /* | 616 | /* |
@@ -579,60 +621,36 @@ static void __init kernel_param_sysfs_setup(const char *name, | |||
579 | * The "module" name (KBUILD_MODNAME) is stored before a dot, the | 621 | * The "module" name (KBUILD_MODNAME) is stored before a dot, the |
580 | * "parameter" name is stored behind a dot in kernel_param->name. So, | 622 | * "parameter" name is stored behind a dot in kernel_param->name. So, |
581 | * extract the "module" name for all built-in kernel_param-eters, | 623 | * extract the "module" name for all built-in kernel_param-eters, |
582 | * and for all who have the same, call kernel_param_sysfs_setup. | 624 | * and for all who have the same, call kernel_add_sysfs_param. |
583 | */ | 625 | */ |
584 | static void __init param_sysfs_builtin(void) | 626 | static void __init param_sysfs_builtin(void) |
585 | { | 627 | { |
586 | struct kernel_param *kp, *kp_begin = NULL; | 628 | struct kernel_param *kp; |
587 | unsigned int i, name_len, count = 0; | 629 | unsigned int name_len; |
588 | char modname[MODULE_NAME_LEN + 1] = ""; | 630 | char modname[MODULE_NAME_LEN]; |
589 | 631 | ||
590 | for (i=0; i < __stop___param - __start___param; i++) { | 632 | for (kp = __start___param; kp < __stop___param; kp++) { |
591 | char *dot; | 633 | char *dot; |
592 | size_t max_name_len; | ||
593 | 634 | ||
594 | kp = &__start___param[i]; | 635 | if (kp->perm == 0) |
595 | max_name_len = | 636 | continue; |
596 | min_t(size_t, MODULE_NAME_LEN, strlen(kp->name)); | ||
597 | 637 | ||
598 | dot = memchr(kp->name, '.', max_name_len); | 638 | dot = strchr(kp->name, '.'); |
599 | if (!dot) { | 639 | if (!dot) { |
600 | DEBUGP("couldn't find period in first %d characters " | 640 | /* This happens for core_param() */ |
601 | "of %s\n", MODULE_NAME_LEN, kp->name); | 641 | strcpy(modname, "kernel"); |
602 | continue; | 642 | name_len = 0; |
603 | } | 643 | } else { |
604 | name_len = dot - kp->name; | 644 | name_len = dot - kp->name + 1; |
605 | 645 | strlcpy(modname, kp->name, name_len); | |
606 | /* new kbuild_modname? */ | ||
607 | if (strlen(modname) != name_len | ||
608 | || strncmp(modname, kp->name, name_len) != 0) { | ||
609 | /* add a new kobject for previous kernel_params. */ | ||
610 | if (count) | ||
611 | kernel_param_sysfs_setup(modname, | ||
612 | kp_begin, | ||
613 | count, | ||
614 | strlen(modname)+1); | ||
615 | |||
616 | strncpy(modname, kp->name, name_len); | ||
617 | modname[name_len] = '\0'; | ||
618 | count = 0; | ||
619 | kp_begin = kp; | ||
620 | } | 646 | } |
621 | count++; | 647 | kernel_add_sysfs_param(modname, kp, name_len); |
622 | } | 648 | } |
623 | |||
624 | /* last kernel_params need to be registered as well */ | ||
625 | if (count) | ||
626 | kernel_param_sysfs_setup(modname, kp_begin, count, | ||
627 | strlen(modname)+1); | ||
628 | } | 649 | } |
629 | 650 | ||
630 | 651 | ||
631 | /* module-related sysfs stuff */ | 652 | /* module-related sysfs stuff */ |
632 | 653 | ||
633 | #define to_module_attr(n) container_of(n, struct module_attribute, attr); | ||
634 | #define to_module_kobject(n) container_of(n, struct module_kobject, kobj); | ||
635 | |||
636 | static ssize_t module_attr_show(struct kobject *kobj, | 654 | static ssize_t module_attr_show(struct kobject *kobj, |
637 | struct attribute *attr, | 655 | struct attribute *attr, |
638 | char *buf) | 656 | char *buf) |
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index af3c7cea258..8aff79d90dd 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c | |||
@@ -37,9 +37,13 @@ struct stop_machine_data { | |||
37 | /* Like num_online_cpus(), but hotplug cpu uses us, so we need this. */ | 37 | /* Like num_online_cpus(), but hotplug cpu uses us, so we need this. */ |
38 | static unsigned int num_threads; | 38 | static unsigned int num_threads; |
39 | static atomic_t thread_ack; | 39 | static atomic_t thread_ack; |
40 | static struct completion finished; | ||
41 | static DEFINE_MUTEX(lock); | 40 | static DEFINE_MUTEX(lock); |
42 | 41 | ||
42 | static struct workqueue_struct *stop_machine_wq; | ||
43 | static struct stop_machine_data active, idle; | ||
44 | static const cpumask_t *active_cpus; | ||
45 | static void *stop_machine_work; | ||
46 | |||
43 | static void set_state(enum stopmachine_state newstate) | 47 | static void set_state(enum stopmachine_state newstate) |
44 | { | 48 | { |
45 | /* Reset ack counter. */ | 49 | /* Reset ack counter. */ |
@@ -51,21 +55,26 @@ static void set_state(enum stopmachine_state newstate) | |||
51 | /* Last one to ack a state moves to the next state. */ | 55 | /* Last one to ack a state moves to the next state. */ |
52 | static void ack_state(void) | 56 | static void ack_state(void) |
53 | { | 57 | { |
54 | if (atomic_dec_and_test(&thread_ack)) { | 58 | if (atomic_dec_and_test(&thread_ack)) |
55 | /* If we're the last one to ack the EXIT, we're finished. */ | 59 | set_state(state + 1); |
56 | if (state == STOPMACHINE_EXIT) | ||
57 | complete(&finished); | ||
58 | else | ||
59 | set_state(state + 1); | ||
60 | } | ||
61 | } | 60 | } |
62 | 61 | ||
63 | /* This is the actual thread which stops the CPU. It exits by itself rather | 62 | /* This is the actual function which stops the CPU. It runs |
64 | * than waiting for kthread_stop(), because it's easier for hotplug CPU. */ | 63 | * in the context of a dedicated stopmachine workqueue. */ |
65 | static int stop_cpu(struct stop_machine_data *smdata) | 64 | static void stop_cpu(struct work_struct *unused) |
66 | { | 65 | { |
67 | enum stopmachine_state curstate = STOPMACHINE_NONE; | 66 | enum stopmachine_state curstate = STOPMACHINE_NONE; |
68 | 67 | struct stop_machine_data *smdata = &idle; | |
68 | int cpu = smp_processor_id(); | ||
69 | int err; | ||
70 | |||
71 | if (!active_cpus) { | ||
72 | if (cpu == first_cpu(cpu_online_map)) | ||
73 | smdata = &active; | ||
74 | } else { | ||
75 | if (cpu_isset(cpu, *active_cpus)) | ||
76 | smdata = &active; | ||
77 | } | ||
69 | /* Simple state machine */ | 78 | /* Simple state machine */ |
70 | do { | 79 | do { |
71 | /* Chill out and ensure we re-read stopmachine_state. */ | 80 | /* Chill out and ensure we re-read stopmachine_state. */ |
@@ -78,9 +87,11 @@ static int stop_cpu(struct stop_machine_data *smdata) | |||
78 | hard_irq_disable(); | 87 | hard_irq_disable(); |
79 | break; | 88 | break; |
80 | case STOPMACHINE_RUN: | 89 | case STOPMACHINE_RUN: |
81 | /* |= allows error detection if functions on | 90 | /* On multiple CPUs only a single error code |
82 | * multiple CPUs. */ | 91 | * is needed to tell that something failed. */ |
83 | smdata->fnret |= smdata->fn(smdata->data); | 92 | err = smdata->fn(smdata->data); |
93 | if (err) | ||
94 | smdata->fnret = err; | ||
84 | break; | 95 | break; |
85 | default: | 96 | default: |
86 | break; | 97 | break; |
@@ -90,7 +101,6 @@ static int stop_cpu(struct stop_machine_data *smdata) | |||
90 | } while (curstate != STOPMACHINE_EXIT); | 101 | } while (curstate != STOPMACHINE_EXIT); |
91 | 102 | ||
92 | local_irq_enable(); | 103 | local_irq_enable(); |
93 | do_exit(0); | ||
94 | } | 104 | } |
95 | 105 | ||
96 | /* Callback for CPUs which aren't supposed to do anything. */ | 106 | /* Callback for CPUs which aren't supposed to do anything. */ |
@@ -101,78 +111,34 @@ static int chill(void *unused) | |||
101 | 111 | ||
102 | int __stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus) | 112 | int __stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus) |
103 | { | 113 | { |
104 | int i, err; | 114 | struct work_struct *sm_work; |
105 | struct stop_machine_data active, idle; | 115 | int i; |
106 | struct task_struct **threads; | ||
107 | 116 | ||
117 | /* Set up initial state. */ | ||
118 | mutex_lock(&lock); | ||
119 | num_threads = num_online_cpus(); | ||
120 | active_cpus = cpus; | ||
108 | active.fn = fn; | 121 | active.fn = fn; |
109 | active.data = data; | 122 | active.data = data; |
110 | active.fnret = 0; | 123 | active.fnret = 0; |
111 | idle.fn = chill; | 124 | idle.fn = chill; |
112 | idle.data = NULL; | 125 | idle.data = NULL; |
113 | 126 | ||
114 | /* This could be too big for stack on large machines. */ | ||
115 | threads = kcalloc(NR_CPUS, sizeof(threads[0]), GFP_KERNEL); | ||
116 | if (!threads) | ||
117 | return -ENOMEM; | ||
118 | |||
119 | /* Set up initial state. */ | ||
120 | mutex_lock(&lock); | ||
121 | init_completion(&finished); | ||
122 | num_threads = num_online_cpus(); | ||
123 | set_state(STOPMACHINE_PREPARE); | 127 | set_state(STOPMACHINE_PREPARE); |
124 | 128 | ||
125 | for_each_online_cpu(i) { | 129 | /* Schedule the stop_cpu work on all cpus: hold this CPU so one |
126 | struct stop_machine_data *smdata = &idle; | ||
127 | struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; | ||
128 | |||
129 | if (!cpus) { | ||
130 | if (i == first_cpu(cpu_online_map)) | ||
131 | smdata = &active; | ||
132 | } else { | ||
133 | if (cpu_isset(i, *cpus)) | ||
134 | smdata = &active; | ||
135 | } | ||
136 | |||
137 | threads[i] = kthread_create((void *)stop_cpu, smdata, "kstop%u", | ||
138 | i); | ||
139 | if (IS_ERR(threads[i])) { | ||
140 | err = PTR_ERR(threads[i]); | ||
141 | threads[i] = NULL; | ||
142 | goto kill_threads; | ||
143 | } | ||
144 | |||
145 | /* Place it onto correct cpu. */ | ||
146 | kthread_bind(threads[i], i); | ||
147 | |||
148 | /* Make it highest prio. */ | ||
149 | if (sched_setscheduler_nocheck(threads[i], SCHED_FIFO, ¶m)) | ||
150 | BUG(); | ||
151 | } | ||
152 | |||
153 | /* We've created all the threads. Wake them all: hold this CPU so one | ||
154 | * doesn't hit this CPU until we're ready. */ | 130 | * doesn't hit this CPU until we're ready. */ |
155 | get_cpu(); | 131 | get_cpu(); |
156 | for_each_online_cpu(i) | 132 | for_each_online_cpu(i) { |
157 | wake_up_process(threads[i]); | 133 | sm_work = percpu_ptr(stop_machine_work, i); |
158 | 134 | INIT_WORK(sm_work, stop_cpu); | |
135 | queue_work_on(i, stop_machine_wq, sm_work); | ||
136 | } | ||
159 | /* This will release the thread on our CPU. */ | 137 | /* This will release the thread on our CPU. */ |
160 | put_cpu(); | 138 | put_cpu(); |
161 | wait_for_completion(&finished); | 139 | flush_workqueue(stop_machine_wq); |
162 | mutex_unlock(&lock); | 140 | mutex_unlock(&lock); |
163 | |||
164 | kfree(threads); | ||
165 | |||
166 | return active.fnret; | 141 | return active.fnret; |
167 | |||
168 | kill_threads: | ||
169 | for_each_online_cpu(i) | ||
170 | if (threads[i]) | ||
171 | kthread_stop(threads[i]); | ||
172 | mutex_unlock(&lock); | ||
173 | |||
174 | kfree(threads); | ||
175 | return err; | ||
176 | } | 142 | } |
177 | 143 | ||
178 | int stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus) | 144 | 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) | |||
187 | return ret; | 153 | return ret; |
188 | } | 154 | } |
189 | EXPORT_SYMBOL_GPL(stop_machine); | 155 | EXPORT_SYMBOL_GPL(stop_machine); |
156 | |||
157 | static int __init stop_machine_init(void) | ||
158 | { | ||
159 | stop_machine_wq = create_rt_workqueue("kstop"); | ||
160 | stop_machine_work = alloc_percpu(struct work_struct); | ||
161 | return 0; | ||
162 | } | ||
163 | early_initcall(stop_machine_init); | ||
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 714afad4653..f928f2a87b9 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -62,6 +62,7 @@ struct workqueue_struct { | |||
62 | const char *name; | 62 | const char *name; |
63 | int singlethread; | 63 | int singlethread; |
64 | int freezeable; /* Freeze threads during suspend */ | 64 | int freezeable; /* Freeze threads during suspend */ |
65 | int rt; | ||
65 | #ifdef CONFIG_LOCKDEP | 66 | #ifdef CONFIG_LOCKDEP |
66 | struct lockdep_map lockdep_map; | 67 | struct lockdep_map lockdep_map; |
67 | #endif | 68 | #endif |
@@ -766,6 +767,7 @@ init_cpu_workqueue(struct workqueue_struct *wq, int cpu) | |||
766 | 767 | ||
767 | static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) | 768 | static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) |
768 | { | 769 | { |
770 | struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; | ||
769 | struct workqueue_struct *wq = cwq->wq; | 771 | struct workqueue_struct *wq = cwq->wq; |
770 | const char *fmt = is_single_threaded(wq) ? "%s" : "%s/%d"; | 772 | const char *fmt = is_single_threaded(wq) ? "%s" : "%s/%d"; |
771 | struct task_struct *p; | 773 | struct task_struct *p; |
@@ -781,7 +783,8 @@ static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) | |||
781 | */ | 783 | */ |
782 | if (IS_ERR(p)) | 784 | if (IS_ERR(p)) |
783 | return PTR_ERR(p); | 785 | return PTR_ERR(p); |
784 | 786 | if (cwq->wq->rt) | |
787 | sched_setscheduler_nocheck(p, SCHED_FIFO, ¶m); | ||
785 | cwq->thread = p; | 788 | cwq->thread = p; |
786 | 789 | ||
787 | return 0; | 790 | return 0; |
@@ -801,6 +804,7 @@ static void start_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) | |||
801 | struct workqueue_struct *__create_workqueue_key(const char *name, | 804 | struct workqueue_struct *__create_workqueue_key(const char *name, |
802 | int singlethread, | 805 | int singlethread, |
803 | int freezeable, | 806 | int freezeable, |
807 | int rt, | ||
804 | struct lock_class_key *key, | 808 | struct lock_class_key *key, |
805 | const char *lock_name) | 809 | const char *lock_name) |
806 | { | 810 | { |
@@ -822,6 +826,7 @@ struct workqueue_struct *__create_workqueue_key(const char *name, | |||
822 | lockdep_init_map(&wq->lockdep_map, lock_name, key, 0); | 826 | lockdep_init_map(&wq->lockdep_map, lock_name, key, 0); |
823 | wq->singlethread = singlethread; | 827 | wq->singlethread = singlethread; |
824 | wq->freezeable = freezeable; | 828 | wq->freezeable = freezeable; |
829 | wq->rt = rt; | ||
825 | INIT_LIST_HEAD(&wq->list); | 830 | INIT_LIST_HEAD(&wq->list); |
826 | 831 | ||
827 | if (singlethread) { | 832 | if (singlethread) { |