diff options
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 112 |
1 files changed, 107 insertions, 5 deletions
diff --git a/kernel/module.c b/kernel/module.c index a566745dde62..c32995fbd8fd 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/notifier.h> | 35 | #include <linux/notifier.h> |
36 | #include <linux/stop_machine.h> | 36 | #include <linux/stop_machine.h> |
37 | #include <linux/device.h> | 37 | #include <linux/device.h> |
38 | #include <linux/string.h> | ||
38 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
39 | #include <asm/semaphore.h> | 40 | #include <asm/semaphore.h> |
40 | #include <asm/cacheflush.h> | 41 | #include <asm/cacheflush.h> |
@@ -249,13 +250,18 @@ static inline unsigned int block_size(int val) | |||
249 | /* Created by linker magic */ | 250 | /* Created by linker magic */ |
250 | extern char __per_cpu_start[], __per_cpu_end[]; | 251 | extern char __per_cpu_start[], __per_cpu_end[]; |
251 | 252 | ||
252 | static void *percpu_modalloc(unsigned long size, unsigned long align) | 253 | static void *percpu_modalloc(unsigned long size, unsigned long align, |
254 | const char *name) | ||
253 | { | 255 | { |
254 | unsigned long extra; | 256 | unsigned long extra; |
255 | unsigned int i; | 257 | unsigned int i; |
256 | void *ptr; | 258 | void *ptr; |
257 | 259 | ||
258 | BUG_ON(align > SMP_CACHE_BYTES); | 260 | if (align > SMP_CACHE_BYTES) { |
261 | printk(KERN_WARNING "%s: per-cpu alignment %li > %i\n", | ||
262 | name, align, SMP_CACHE_BYTES); | ||
263 | align = SMP_CACHE_BYTES; | ||
264 | } | ||
259 | 265 | ||
260 | ptr = __per_cpu_start; | 266 | ptr = __per_cpu_start; |
261 | for (i = 0; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) { | 267 | for (i = 0; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) { |
@@ -347,7 +353,8 @@ static int percpu_modinit(void) | |||
347 | } | 353 | } |
348 | __initcall(percpu_modinit); | 354 | __initcall(percpu_modinit); |
349 | #else /* ... !CONFIG_SMP */ | 355 | #else /* ... !CONFIG_SMP */ |
350 | static inline void *percpu_modalloc(unsigned long size, unsigned long align) | 356 | static inline void *percpu_modalloc(unsigned long size, unsigned long align, |
357 | const char *name) | ||
351 | { | 358 | { |
352 | return NULL; | 359 | return NULL; |
353 | } | 360 | } |
@@ -370,6 +377,43 @@ static inline void percpu_modcopy(void *pcpudst, const void *src, | |||
370 | #endif /* CONFIG_SMP */ | 377 | #endif /* CONFIG_SMP */ |
371 | 378 | ||
372 | #ifdef CONFIG_MODULE_UNLOAD | 379 | #ifdef CONFIG_MODULE_UNLOAD |
380 | #define MODINFO_ATTR(field) \ | ||
381 | static void setup_modinfo_##field(struct module *mod, const char *s) \ | ||
382 | { \ | ||
383 | mod->field = kstrdup(s, GFP_KERNEL); \ | ||
384 | } \ | ||
385 | static ssize_t show_modinfo_##field(struct module_attribute *mattr, \ | ||
386 | struct module *mod, char *buffer) \ | ||
387 | { \ | ||
388 | return sprintf(buffer, "%s\n", mod->field); \ | ||
389 | } \ | ||
390 | static int modinfo_##field##_exists(struct module *mod) \ | ||
391 | { \ | ||
392 | return mod->field != NULL; \ | ||
393 | } \ | ||
394 | static void free_modinfo_##field(struct module *mod) \ | ||
395 | { \ | ||
396 | kfree(mod->field); \ | ||
397 | mod->field = NULL; \ | ||
398 | } \ | ||
399 | static struct module_attribute modinfo_##field = { \ | ||
400 | .attr = { .name = __stringify(field), .mode = 0444, \ | ||
401 | .owner = THIS_MODULE }, \ | ||
402 | .show = show_modinfo_##field, \ | ||
403 | .setup = setup_modinfo_##field, \ | ||
404 | .test = modinfo_##field##_exists, \ | ||
405 | .free = free_modinfo_##field, \ | ||
406 | }; | ||
407 | |||
408 | MODINFO_ATTR(version); | ||
409 | MODINFO_ATTR(srcversion); | ||
410 | |||
411 | static struct module_attribute *modinfo_attrs[] = { | ||
412 | &modinfo_version, | ||
413 | &modinfo_srcversion, | ||
414 | NULL, | ||
415 | }; | ||
416 | |||
373 | /* Init the unload section of the module. */ | 417 | /* Init the unload section of the module. */ |
374 | static void module_unload_init(struct module *mod) | 418 | static void module_unload_init(struct module *mod) |
375 | { | 419 | { |
@@ -692,7 +736,7 @@ static int obsparm_copy_string(const char *val, struct kernel_param *kp) | |||
692 | return 0; | 736 | return 0; |
693 | } | 737 | } |
694 | 738 | ||
695 | int set_obsolete(const char *val, struct kernel_param *kp) | 739 | static int set_obsolete(const char *val, struct kernel_param *kp) |
696 | { | 740 | { |
697 | unsigned int min, max; | 741 | unsigned int min, max; |
698 | unsigned int size, maxsize; | 742 | unsigned int size, maxsize; |
@@ -1031,6 +1075,32 @@ static void module_remove_refcnt_attr(struct module *mod) | |||
1031 | } | 1075 | } |
1032 | #endif | 1076 | #endif |
1033 | 1077 | ||
1078 | #ifdef CONFIG_MODULE_UNLOAD | ||
1079 | static int module_add_modinfo_attrs(struct module *mod) | ||
1080 | { | ||
1081 | struct module_attribute *attr; | ||
1082 | int error = 0; | ||
1083 | int i; | ||
1084 | |||
1085 | for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { | ||
1086 | if (!attr->test || | ||
1087 | (attr->test && attr->test(mod))) | ||
1088 | error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr); | ||
1089 | } | ||
1090 | return error; | ||
1091 | } | ||
1092 | |||
1093 | static void module_remove_modinfo_attrs(struct module *mod) | ||
1094 | { | ||
1095 | struct module_attribute *attr; | ||
1096 | int i; | ||
1097 | |||
1098 | for (i = 0; (attr = modinfo_attrs[i]); i++) { | ||
1099 | sysfs_remove_file(&mod->mkobj.kobj,&attr->attr); | ||
1100 | attr->free(mod); | ||
1101 | } | ||
1102 | } | ||
1103 | #endif | ||
1034 | 1104 | ||
1035 | static int mod_sysfs_setup(struct module *mod, | 1105 | static int mod_sysfs_setup(struct module *mod, |
1036 | struct kernel_param *kparam, | 1106 | struct kernel_param *kparam, |
@@ -1056,6 +1126,12 @@ static int mod_sysfs_setup(struct module *mod, | |||
1056 | if (err) | 1126 | if (err) |
1057 | goto out_unreg; | 1127 | goto out_unreg; |
1058 | 1128 | ||
1129 | #ifdef CONFIG_MODULE_UNLOAD | ||
1130 | err = module_add_modinfo_attrs(mod); | ||
1131 | if (err) | ||
1132 | goto out_unreg; | ||
1133 | #endif | ||
1134 | |||
1059 | return 0; | 1135 | return 0; |
1060 | 1136 | ||
1061 | out_unreg: | 1137 | out_unreg: |
@@ -1066,6 +1142,9 @@ out: | |||
1066 | 1142 | ||
1067 | static void mod_kobject_remove(struct module *mod) | 1143 | static void mod_kobject_remove(struct module *mod) |
1068 | { | 1144 | { |
1145 | #ifdef CONFIG_MODULE_UNLOAD | ||
1146 | module_remove_modinfo_attrs(mod); | ||
1147 | #endif | ||
1069 | module_remove_refcnt_attr(mod); | 1148 | module_remove_refcnt_attr(mod); |
1070 | module_param_sysfs_remove(mod); | 1149 | module_param_sysfs_remove(mod); |
1071 | 1150 | ||
@@ -1311,6 +1390,23 @@ static char *get_modinfo(Elf_Shdr *sechdrs, | |||
1311 | return NULL; | 1390 | return NULL; |
1312 | } | 1391 | } |
1313 | 1392 | ||
1393 | #ifdef CONFIG_MODULE_UNLOAD | ||
1394 | static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, | ||
1395 | unsigned int infoindex) | ||
1396 | { | ||
1397 | struct module_attribute *attr; | ||
1398 | int i; | ||
1399 | |||
1400 | for (i = 0; (attr = modinfo_attrs[i]); i++) { | ||
1401 | if (attr->setup) | ||
1402 | attr->setup(mod, | ||
1403 | get_modinfo(sechdrs, | ||
1404 | infoindex, | ||
1405 | attr->attr.name)); | ||
1406 | } | ||
1407 | } | ||
1408 | #endif | ||
1409 | |||
1314 | #ifdef CONFIG_KALLSYMS | 1410 | #ifdef CONFIG_KALLSYMS |
1315 | int is_exported(const char *name, const struct module *mod) | 1411 | int is_exported(const char *name, const struct module *mod) |
1316 | { | 1412 | { |
@@ -1554,7 +1650,8 @@ static struct module *load_module(void __user *umod, | |||
1554 | if (pcpuindex) { | 1650 | if (pcpuindex) { |
1555 | /* We have a special allocation for this section. */ | 1651 | /* We have a special allocation for this section. */ |
1556 | percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size, | 1652 | percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size, |
1557 | sechdrs[pcpuindex].sh_addralign); | 1653 | sechdrs[pcpuindex].sh_addralign, |
1654 | mod->name); | ||
1558 | if (!percpu) { | 1655 | if (!percpu) { |
1559 | err = -ENOMEM; | 1656 | err = -ENOMEM; |
1560 | goto free_mod; | 1657 | goto free_mod; |
@@ -1615,6 +1712,11 @@ static struct module *load_module(void __user *umod, | |||
1615 | /* Set up license info based on the info section */ | 1712 | /* Set up license info based on the info section */ |
1616 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); | 1713 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); |
1617 | 1714 | ||
1715 | #ifdef CONFIG_MODULE_UNLOAD | ||
1716 | /* Set up MODINFO_ATTR fields */ | ||
1717 | setup_modinfo(mod, sechdrs, infoindex); | ||
1718 | #endif | ||
1719 | |||
1618 | /* Fix up syms, so that st_value is a pointer to location. */ | 1720 | /* Fix up syms, so that st_value is a pointer to location. */ |
1619 | err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, | 1721 | err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, |
1620 | mod); | 1722 | mod); |