diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/kmod.c | 120 | ||||
-rw-r--r-- | kernel/module.c | 47 | ||||
-rw-r--r-- | kernel/params.c | 29 | ||||
-rw-r--r-- | kernel/printk.c | 2 |
4 files changed, 165 insertions, 33 deletions
diff --git a/kernel/kmod.c b/kernel/kmod.c index 796276141e51..9f923f8ce6a0 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include <linux/resource.h> | 36 | #include <linux/resource.h> |
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | 38 | ||
39 | extern int delete_module(const char *name, unsigned int flags); | ||
40 | |||
39 | extern int max_threads; | 41 | extern int max_threads; |
40 | 42 | ||
41 | static struct workqueue_struct *khelper_wq; | 43 | static struct workqueue_struct *khelper_wq; |
@@ -46,6 +48,7 @@ static struct workqueue_struct *khelper_wq; | |||
46 | modprobe_path is set via /proc/sys. | 48 | modprobe_path is set via /proc/sys. |
47 | */ | 49 | */ |
48 | char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; | 50 | char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; |
51 | struct module_kobject kmod_mk; | ||
49 | 52 | ||
50 | /** | 53 | /** |
51 | * request_module - try to load a kernel module | 54 | * request_module - try to load a kernel module |
@@ -75,6 +78,11 @@ int request_module(const char *fmt, ...) | |||
75 | static atomic_t kmod_concurrent = ATOMIC_INIT(0); | 78 | static atomic_t kmod_concurrent = ATOMIC_INIT(0); |
76 | #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ | 79 | #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ |
77 | static int kmod_loop_msg; | 80 | static int kmod_loop_msg; |
81 | char modalias[16 + MODULE_NAME_LEN] = "MODALIAS="; | ||
82 | char *uevent_envp[2] = { | ||
83 | modalias, | ||
84 | NULL | ||
85 | }; | ||
78 | 86 | ||
79 | va_start(args, fmt); | 87 | va_start(args, fmt); |
80 | ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); | 88 | ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); |
@@ -82,6 +90,12 @@ int request_module(const char *fmt, ...) | |||
82 | if (ret >= MODULE_NAME_LEN) | 90 | if (ret >= MODULE_NAME_LEN) |
83 | return -ENAMETOOLONG; | 91 | return -ENAMETOOLONG; |
84 | 92 | ||
93 | strcpy(&modalias[strlen("MODALIAS=")], module_name); | ||
94 | kobject_uevent_env(&kmod_mk.kobj, KOBJ_CHANGE, uevent_envp); | ||
95 | |||
96 | if (modprobe_path[0] == '\0') | ||
97 | goto out; | ||
98 | |||
85 | /* If modprobe needs a service that is in a module, we get a recursive | 99 | /* If modprobe needs a service that is in a module, we get a recursive |
86 | * loop. Limit the number of running kmod threads to max_threads/2 or | 100 | * loop. Limit the number of running kmod threads to max_threads/2 or |
87 | * MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method | 101 | * MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method |
@@ -108,9 +122,115 @@ int request_module(const char *fmt, ...) | |||
108 | 122 | ||
109 | ret = call_usermodehelper(modprobe_path, argv, envp, 1); | 123 | ret = call_usermodehelper(modprobe_path, argv, envp, 1); |
110 | atomic_dec(&kmod_concurrent); | 124 | atomic_dec(&kmod_concurrent); |
125 | out: | ||
111 | return ret; | 126 | return ret; |
112 | } | 127 | } |
113 | EXPORT_SYMBOL(request_module); | 128 | EXPORT_SYMBOL(request_module); |
129 | |||
130 | static ssize_t store_mod_request(struct module_attribute *mattr, | ||
131 | struct module *mod, | ||
132 | const char *buffer, size_t count) | ||
133 | { | ||
134 | char name[MODULE_NAME_LEN]; | ||
135 | int ret; | ||
136 | |||
137 | if (count < 1 || count+1 > MODULE_NAME_LEN) | ||
138 | return -EINVAL; | ||
139 | memcpy(name, buffer, count); | ||
140 | name[count] = '\0'; | ||
141 | if (name[count-1] == '\n') | ||
142 | name[count-1] = '\0'; | ||
143 | |||
144 | ret = request_module(name); | ||
145 | if (ret < 0) | ||
146 | return ret; | ||
147 | return count; | ||
148 | } | ||
149 | |||
150 | static struct module_attribute mod_request = { | ||
151 | .attr = { .name = "mod_request", .mode = S_IWUSR, .owner = THIS_MODULE }, | ||
152 | .store = store_mod_request, | ||
153 | }; | ||
154 | |||
155 | #ifdef CONFIG_MODULE_UNLOAD | ||
156 | static ssize_t store_mod_unload(struct module_attribute *mattr, | ||
157 | struct module *mod, | ||
158 | const char *buffer, size_t count) | ||
159 | { | ||
160 | char name[MODULE_NAME_LEN]; | ||
161 | int ret; | ||
162 | |||
163 | if (count < 1 || count+1 > MODULE_NAME_LEN) | ||
164 | return -EINVAL; | ||
165 | memcpy(name, buffer, count); | ||
166 | name[count] = '\0'; | ||
167 | if (name[count-1] == '\n') | ||
168 | name[count-1] = '\0'; | ||
169 | |||
170 | ret = delete_module(name, O_NONBLOCK); | ||
171 | if (ret < 0) | ||
172 | return ret; | ||
173 | return count; | ||
174 | } | ||
175 | |||
176 | static struct module_attribute mod_unload = { | ||
177 | .attr = { .name = "mod_unload", .mode = S_IWUSR, .owner = THIS_MODULE }, | ||
178 | .store = store_mod_unload, | ||
179 | }; | ||
180 | #endif | ||
181 | |||
182 | static ssize_t show_mod_request_helper(struct module_attribute *mattr, | ||
183 | struct module *mod, | ||
184 | char *buffer) | ||
185 | { | ||
186 | return sprintf(buffer, "%s\n", modprobe_path); | ||
187 | } | ||
188 | |||
189 | static ssize_t store_mod_request_helper(struct module_attribute *mattr, | ||
190 | struct module *mod, | ||
191 | const char *buffer, size_t count) | ||
192 | { | ||
193 | if (count < 1 || count+1 > KMOD_PATH_LEN) | ||
194 | return -EINVAL; | ||
195 | memcpy(modprobe_path, buffer, count); | ||
196 | modprobe_path[count] = '\0'; | ||
197 | if (modprobe_path[count-1] == '\n') | ||
198 | modprobe_path[count-1] = '\0'; | ||
199 | return count; | ||
200 | } | ||
201 | |||
202 | static struct module_attribute mod_request_helper = { | ||
203 | .attr = { | ||
204 | .name = "mod_request_helper", | ||
205 | .mode = S_IWUSR | S_IRUGO, | ||
206 | .owner = THIS_MODULE | ||
207 | }, | ||
208 | .show = show_mod_request_helper, | ||
209 | .store = store_mod_request_helper, | ||
210 | }; | ||
211 | |||
212 | void __init kmod_sysfs_init(void) | ||
213 | { | ||
214 | int ret; | ||
215 | |||
216 | kmod_mk.mod = THIS_MODULE; | ||
217 | kobj_set_kset_s(&kmod_mk, module_subsys); | ||
218 | kobject_set_name(&kmod_mk.kobj, "kmod"); | ||
219 | kobject_init(&kmod_mk.kobj); | ||
220 | ret = kobject_add(&kmod_mk.kobj); | ||
221 | if (ret < 0) | ||
222 | goto out; | ||
223 | |||
224 | ret = sysfs_create_file(&kmod_mk.kobj, &mod_request_helper.attr); | ||
225 | ret = sysfs_create_file(&kmod_mk.kobj, &mod_request.attr); | ||
226 | #ifdef CONFIG_MODULE_UNLOAD | ||
227 | ret = sysfs_create_file(&kmod_mk.kobj, &mod_unload.attr); | ||
228 | #endif | ||
229 | |||
230 | kobject_uevent(&kmod_mk.kobj, KOBJ_ADD); | ||
231 | out: | ||
232 | return; | ||
233 | } | ||
114 | #endif /* CONFIG_KMOD */ | 234 | #endif /* CONFIG_KMOD */ |
115 | 235 | ||
116 | struct subprocess_info { | 236 | struct subprocess_info { |
diff --git a/kernel/module.c b/kernel/module.c index 8a94e054230c..8c25b1a04fa6 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -653,20 +653,11 @@ static void wait_for_zero_refcount(struct module *mod) | |||
653 | mutex_lock(&module_mutex); | 653 | mutex_lock(&module_mutex); |
654 | } | 654 | } |
655 | 655 | ||
656 | asmlinkage long | 656 | int delete_module(const char *name, unsigned int flags) |
657 | sys_delete_module(const char __user *name_user, unsigned int flags) | ||
658 | { | 657 | { |
659 | struct module *mod; | 658 | struct module *mod; |
660 | char name[MODULE_NAME_LEN]; | ||
661 | int ret, forced = 0; | 659 | int ret, forced = 0; |
662 | 660 | ||
663 | if (!capable(CAP_SYS_MODULE)) | ||
664 | return -EPERM; | ||
665 | |||
666 | if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) | ||
667 | return -EFAULT; | ||
668 | name[MODULE_NAME_LEN-1] = '\0'; | ||
669 | |||
670 | if (mutex_lock_interruptible(&module_mutex) != 0) | 661 | if (mutex_lock_interruptible(&module_mutex) != 0) |
671 | return -EINTR; | 662 | return -EINTR; |
672 | 663 | ||
@@ -727,6 +718,21 @@ sys_delete_module(const char __user *name_user, unsigned int flags) | |||
727 | return ret; | 718 | return ret; |
728 | } | 719 | } |
729 | 720 | ||
721 | asmlinkage long | ||
722 | sys_delete_module(const char __user *name_user, unsigned int flags) | ||
723 | { | ||
724 | char name[MODULE_NAME_LEN]; | ||
725 | |||
726 | if (!capable(CAP_SYS_MODULE)) | ||
727 | return -EPERM; | ||
728 | |||
729 | if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) | ||
730 | return -EFAULT; | ||
731 | name[MODULE_NAME_LEN-1] = '\0'; | ||
732 | |||
733 | return delete_module(name, flags); | ||
734 | } | ||
735 | |||
730 | static void print_unload_info(struct seq_file *m, struct module *mod) | 736 | static void print_unload_info(struct seq_file *m, struct module *mod) |
731 | { | 737 | { |
732 | struct module_use *use; | 738 | struct module_use *use; |
@@ -1068,7 +1074,8 @@ static inline void remove_sect_attrs(struct module *mod) | |||
1068 | } | 1074 | } |
1069 | #endif /* CONFIG_KALLSYMS */ | 1075 | #endif /* CONFIG_KALLSYMS */ |
1070 | 1076 | ||
1071 | static int module_add_modinfo_attrs(struct module *mod) | 1077 | #ifdef CONFIG_SYSFS |
1078 | int module_add_modinfo_attrs(struct module *mod) | ||
1072 | { | 1079 | { |
1073 | struct module_attribute *attr; | 1080 | struct module_attribute *attr; |
1074 | struct module_attribute *temp_attr; | 1081 | struct module_attribute *temp_attr; |
@@ -1094,7 +1101,7 @@ static int module_add_modinfo_attrs(struct module *mod) | |||
1094 | return error; | 1101 | return error; |
1095 | } | 1102 | } |
1096 | 1103 | ||
1097 | static void module_remove_modinfo_attrs(struct module *mod) | 1104 | void module_remove_modinfo_attrs(struct module *mod) |
1098 | { | 1105 | { |
1099 | struct module_attribute *attr; | 1106 | struct module_attribute *attr; |
1100 | int i; | 1107 | int i; |
@@ -1109,8 +1116,10 @@ static void module_remove_modinfo_attrs(struct module *mod) | |||
1109 | } | 1116 | } |
1110 | kfree(mod->modinfo_attrs); | 1117 | kfree(mod->modinfo_attrs); |
1111 | } | 1118 | } |
1119 | #endif | ||
1112 | 1120 | ||
1113 | static int mod_sysfs_init(struct module *mod) | 1121 | #ifdef CONFIG_SYSFS |
1122 | int mod_sysfs_init(struct module *mod) | ||
1114 | { | 1123 | { |
1115 | int err; | 1124 | int err; |
1116 | 1125 | ||
@@ -1133,7 +1142,7 @@ out: | |||
1133 | return err; | 1142 | return err; |
1134 | } | 1143 | } |
1135 | 1144 | ||
1136 | static int mod_sysfs_setup(struct module *mod, | 1145 | int mod_sysfs_setup(struct module *mod, |
1137 | struct kernel_param *kparam, | 1146 | struct kernel_param *kparam, |
1138 | unsigned int num_params) | 1147 | unsigned int num_params) |
1139 | { | 1148 | { |
@@ -1169,16 +1178,14 @@ out_unreg: | |||
1169 | out: | 1178 | out: |
1170 | return err; | 1179 | return err; |
1171 | } | 1180 | } |
1181 | #endif | ||
1172 | 1182 | ||
1173 | static void mod_kobject_remove(struct module *mod) | 1183 | static void mod_kobject_remove(struct module *mod) |
1174 | { | 1184 | { |
1175 | module_remove_modinfo_attrs(mod); | 1185 | module_remove_modinfo_attrs(mod); |
1176 | module_param_sysfs_remove(mod); | 1186 | module_param_sysfs_remove(mod); |
1177 | if (mod->mkobj.drivers_dir) | 1187 | kobject_unregister(mod->mkobj.drivers_dir); |
1178 | kobject_unregister(mod->mkobj.drivers_dir); | 1188 | kobject_unregister(mod->holders_dir); |
1179 | if (mod->holders_dir) | ||
1180 | kobject_unregister(mod->holders_dir); | ||
1181 | |||
1182 | kobject_unregister(&mod->mkobj.kobj); | 1189 | kobject_unregister(&mod->mkobj.kobj); |
1183 | } | 1190 | } |
1184 | 1191 | ||
@@ -2345,6 +2352,7 @@ void print_modules(void) | |||
2345 | printk("\n"); | 2352 | printk("\n"); |
2346 | } | 2353 | } |
2347 | 2354 | ||
2355 | #ifdef CONFIG_SYSFS | ||
2348 | static char *make_driver_name(struct device_driver *drv) | 2356 | static char *make_driver_name(struct device_driver *drv) |
2349 | { | 2357 | { |
2350 | char *driver_name; | 2358 | char *driver_name; |
@@ -2419,6 +2427,7 @@ void module_remove_driver(struct device_driver *drv) | |||
2419 | } | 2427 | } |
2420 | } | 2428 | } |
2421 | EXPORT_SYMBOL(module_remove_driver); | 2429 | EXPORT_SYMBOL(module_remove_driver); |
2430 | #endif | ||
2422 | 2431 | ||
2423 | #ifdef CONFIG_MODVERSIONS | 2432 | #ifdef CONFIG_MODVERSIONS |
2424 | /* Generate the signature for struct module here, too, for modversions. */ | 2433 | /* Generate the signature for struct module here, too, for modversions. */ |
diff --git a/kernel/params.c b/kernel/params.c index 553cf7d6a4be..7a751570b56d 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
@@ -30,8 +30,6 @@ | |||
30 | #define DEBUGP(fmt, a...) | 30 | #define DEBUGP(fmt, a...) |
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | static struct kobj_type module_ktype; | ||
34 | |||
35 | static inline char dash2underscore(char c) | 33 | static inline char dash2underscore(char c) |
36 | { | 34 | { |
37 | if (c == '-') | 35 | if (c == '-') |
@@ -391,6 +389,7 @@ struct module_param_attrs | |||
391 | struct param_attribute attrs[0]; | 389 | struct param_attribute attrs[0]; |
392 | }; | 390 | }; |
393 | 391 | ||
392 | #ifdef CONFIG_SYSFS | ||
394 | #define to_param_attr(n) container_of(n, struct param_attribute, mattr); | 393 | #define to_param_attr(n) container_of(n, struct param_attribute, mattr); |
395 | 394 | ||
396 | static ssize_t param_attr_show(struct module_attribute *mattr, | 395 | static ssize_t param_attr_show(struct module_attribute *mattr, |
@@ -426,6 +425,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr, | |||
426 | return len; | 425 | return len; |
427 | return err; | 426 | return err; |
428 | } | 427 | } |
428 | #endif | ||
429 | 429 | ||
430 | #ifdef CONFIG_MODULES | 430 | #ifdef CONFIG_MODULES |
431 | #define __modinit | 431 | #define __modinit |
@@ -433,6 +433,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr, | |||
433 | #define __modinit __init | 433 | #define __modinit __init |
434 | #endif | 434 | #endif |
435 | 435 | ||
436 | #ifdef CONFIG_SYSFS | ||
436 | /* | 437 | /* |
437 | * param_sysfs_setup - setup sysfs support for one module or KBUILD_MODNAME | 438 | * param_sysfs_setup - setup sysfs support for one module or KBUILD_MODNAME |
438 | * @mk: struct module_kobject (contains parent kobject) | 439 | * @mk: struct module_kobject (contains parent kobject) |
@@ -500,9 +501,7 @@ param_sysfs_setup(struct module_kobject *mk, | |||
500 | return mp; | 501 | return mp; |
501 | } | 502 | } |
502 | 503 | ||
503 | |||
504 | #ifdef CONFIG_MODULES | 504 | #ifdef CONFIG_MODULES |
505 | |||
506 | /* | 505 | /* |
507 | * module_param_sysfs_setup - setup sysfs support for one module | 506 | * module_param_sysfs_setup - setup sysfs support for one module |
508 | * @mod: module | 507 | * @mod: module |
@@ -625,7 +624,6 @@ static void __init param_sysfs_builtin(void) | |||
625 | 624 | ||
626 | 625 | ||
627 | /* module-related sysfs stuff */ | 626 | /* module-related sysfs stuff */ |
628 | #ifdef CONFIG_SYSFS | ||
629 | 627 | ||
630 | #define to_module_attr(n) container_of(n, struct module_attribute, attr); | 628 | #define to_module_attr(n) container_of(n, struct module_attribute, attr); |
631 | #define to_module_kobject(n) container_of(n, struct module_kobject, kobj); | 629 | #define to_module_kobject(n) container_of(n, struct module_kobject, kobj); |
@@ -673,6 +671,8 @@ static struct sysfs_ops module_sysfs_ops = { | |||
673 | .store = module_attr_store, | 671 | .store = module_attr_store, |
674 | }; | 672 | }; |
675 | 673 | ||
674 | static struct kobj_type module_ktype; | ||
675 | |||
676 | static int uevent_filter(struct kset *kset, struct kobject *kobj) | 676 | static int uevent_filter(struct kset *kset, struct kobject *kobj) |
677 | { | 677 | { |
678 | struct kobj_type *ktype = get_ktype(kobj); | 678 | struct kobj_type *ktype = get_ktype(kobj); |
@@ -686,19 +686,12 @@ static struct kset_uevent_ops module_uevent_ops = { | |||
686 | .filter = uevent_filter, | 686 | .filter = uevent_filter, |
687 | }; | 687 | }; |
688 | 688 | ||
689 | #else | 689 | decl_subsys(module, &module_ktype, &module_uevent_ops); |
690 | static struct sysfs_ops module_sysfs_ops = { | ||
691 | .show = NULL, | ||
692 | .store = NULL, | ||
693 | }; | ||
694 | #endif | ||
695 | 690 | ||
696 | static struct kobj_type module_ktype = { | 691 | static struct kobj_type module_ktype = { |
697 | .sysfs_ops = &module_sysfs_ops, | 692 | .sysfs_ops = &module_sysfs_ops, |
698 | }; | 693 | }; |
699 | 694 | ||
700 | decl_subsys(module, &module_ktype, &module_uevent_ops); | ||
701 | |||
702 | /* | 695 | /* |
703 | * param_sysfs_init - wrapper for built-in params support | 696 | * param_sysfs_init - wrapper for built-in params support |
704 | */ | 697 | */ |
@@ -714,11 +707,21 @@ static int __init param_sysfs_init(void) | |||
714 | } | 707 | } |
715 | 708 | ||
716 | param_sysfs_builtin(); | 709 | param_sysfs_builtin(); |
710 | kmod_sysfs_init(); | ||
717 | 711 | ||
718 | return 0; | 712 | return 0; |
719 | } | 713 | } |
720 | subsys_initcall(param_sysfs_init); | 714 | subsys_initcall(param_sysfs_init); |
721 | 715 | ||
716 | #else | ||
717 | #if 0 | ||
718 | static struct sysfs_ops module_sysfs_ops = { | ||
719 | .show = NULL, | ||
720 | .store = NULL, | ||
721 | }; | ||
722 | #endif | ||
723 | #endif | ||
724 | |||
722 | EXPORT_SYMBOL(param_set_byte); | 725 | EXPORT_SYMBOL(param_set_byte); |
723 | EXPORT_SYMBOL(param_get_byte); | 726 | EXPORT_SYMBOL(param_get_byte); |
724 | EXPORT_SYMBOL(param_set_short); | 727 | EXPORT_SYMBOL(param_set_short); |
diff --git a/kernel/printk.c b/kernel/printk.c index 0c151877ff71..4b47e59248df 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -54,7 +54,7 @@ int console_printk[4] = { | |||
54 | }; | 54 | }; |
55 | 55 | ||
56 | /* | 56 | /* |
57 | * Low lever drivers may need that to know if they can schedule in | 57 | * Low level drivers may need that to know if they can schedule in |
58 | * their unblank() callback or not. So let's export it. | 58 | * their unblank() callback or not. So let's export it. |
59 | */ | 59 | */ |
60 | int oops_in_progress; | 60 | int oops_in_progress; |