aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/module.c')
-rw-r--r--kernel/module.c112
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 */
250extern char __per_cpu_start[], __per_cpu_end[]; 251extern char __per_cpu_start[], __per_cpu_end[];
251 252
252static void *percpu_modalloc(unsigned long size, unsigned long align) 253static 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 */
350static inline void *percpu_modalloc(unsigned long size, unsigned long align) 356static 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) \
381static void setup_modinfo_##field(struct module *mod, const char *s) \
382{ \
383 mod->field = kstrdup(s, GFP_KERNEL); \
384} \
385static 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} \
390static int modinfo_##field##_exists(struct module *mod) \
391{ \
392 return mod->field != NULL; \
393} \
394static void free_modinfo_##field(struct module *mod) \
395{ \
396 kfree(mod->field); \
397 mod->field = NULL; \
398} \
399static 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
408MODINFO_ATTR(version);
409MODINFO_ATTR(srcversion);
410
411static 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. */
374static void module_unload_init(struct module *mod) 418static 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
695int set_obsolete(const char *val, struct kernel_param *kp) 739static 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
1079static 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
1093static 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
1035static int mod_sysfs_setup(struct module *mod, 1105static 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
1061out_unreg: 1137out_unreg:
@@ -1066,6 +1142,9 @@ out:
1066 1142
1067static void mod_kobject_remove(struct module *mod) 1143static 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
1394static 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
1315int is_exported(const char *name, const struct module *mod) 1411int 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);