diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/module.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/kernel/module.c b/kernel/module.c index a566745dde62..0494c89a0d26 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> |
| @@ -370,6 +371,43 @@ static inline void percpu_modcopy(void *pcpudst, const void *src, | |||
| 370 | #endif /* CONFIG_SMP */ | 371 | #endif /* CONFIG_SMP */ |
| 371 | 372 | ||
| 372 | #ifdef CONFIG_MODULE_UNLOAD | 373 | #ifdef CONFIG_MODULE_UNLOAD |
| 374 | #define MODINFO_ATTR(field) \ | ||
| 375 | static void setup_modinfo_##field(struct module *mod, const char *s) \ | ||
| 376 | { \ | ||
| 377 | mod->field = kstrdup(s, GFP_KERNEL); \ | ||
| 378 | } \ | ||
| 379 | static ssize_t show_modinfo_##field(struct module_attribute *mattr, \ | ||
| 380 | struct module *mod, char *buffer) \ | ||
| 381 | { \ | ||
| 382 | return sprintf(buffer, "%s\n", mod->field); \ | ||
| 383 | } \ | ||
| 384 | static int modinfo_##field##_exists(struct module *mod) \ | ||
| 385 | { \ | ||
| 386 | return mod->field != NULL; \ | ||
| 387 | } \ | ||
| 388 | static void free_modinfo_##field(struct module *mod) \ | ||
| 389 | { \ | ||
| 390 | kfree(mod->field); \ | ||
| 391 | mod->field = NULL; \ | ||
| 392 | } \ | ||
| 393 | static struct module_attribute modinfo_##field = { \ | ||
| 394 | .attr = { .name = __stringify(field), .mode = 0444, \ | ||
| 395 | .owner = THIS_MODULE }, \ | ||
| 396 | .show = show_modinfo_##field, \ | ||
| 397 | .setup = setup_modinfo_##field, \ | ||
| 398 | .test = modinfo_##field##_exists, \ | ||
| 399 | .free = free_modinfo_##field, \ | ||
| 400 | }; | ||
| 401 | |||
| 402 | MODINFO_ATTR(version); | ||
| 403 | MODINFO_ATTR(srcversion); | ||
| 404 | |||
| 405 | static struct module_attribute *modinfo_attrs[] = { | ||
| 406 | &modinfo_version, | ||
| 407 | &modinfo_srcversion, | ||
| 408 | NULL, | ||
| 409 | }; | ||
| 410 | |||
| 373 | /* Init the unload section of the module. */ | 411 | /* Init the unload section of the module. */ |
| 374 | static void module_unload_init(struct module *mod) | 412 | static void module_unload_init(struct module *mod) |
| 375 | { | 413 | { |
| @@ -1031,6 +1069,32 @@ static void module_remove_refcnt_attr(struct module *mod) | |||
| 1031 | } | 1069 | } |
| 1032 | #endif | 1070 | #endif |
| 1033 | 1071 | ||
| 1072 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1073 | static int module_add_modinfo_attrs(struct module *mod) | ||
| 1074 | { | ||
| 1075 | struct module_attribute *attr; | ||
| 1076 | int error = 0; | ||
| 1077 | int i; | ||
| 1078 | |||
| 1079 | for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { | ||
| 1080 | if (!attr->test || | ||
| 1081 | (attr->test && attr->test(mod))) | ||
| 1082 | error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr); | ||
| 1083 | } | ||
| 1084 | return error; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | static void module_remove_modinfo_attrs(struct module *mod) | ||
| 1088 | { | ||
| 1089 | struct module_attribute *attr; | ||
| 1090 | int i; | ||
| 1091 | |||
| 1092 | for (i = 0; (attr = modinfo_attrs[i]); i++) { | ||
| 1093 | sysfs_remove_file(&mod->mkobj.kobj,&attr->attr); | ||
| 1094 | attr->free(mod); | ||
| 1095 | } | ||
| 1096 | } | ||
| 1097 | #endif | ||
| 1034 | 1098 | ||
| 1035 | static int mod_sysfs_setup(struct module *mod, | 1099 | static int mod_sysfs_setup(struct module *mod, |
| 1036 | struct kernel_param *kparam, | 1100 | struct kernel_param *kparam, |
| @@ -1056,6 +1120,12 @@ static int mod_sysfs_setup(struct module *mod, | |||
| 1056 | if (err) | 1120 | if (err) |
| 1057 | goto out_unreg; | 1121 | goto out_unreg; |
| 1058 | 1122 | ||
| 1123 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1124 | err = module_add_modinfo_attrs(mod); | ||
| 1125 | if (err) | ||
| 1126 | goto out_unreg; | ||
| 1127 | #endif | ||
| 1128 | |||
| 1059 | return 0; | 1129 | return 0; |
| 1060 | 1130 | ||
| 1061 | out_unreg: | 1131 | out_unreg: |
| @@ -1066,6 +1136,9 @@ out: | |||
| 1066 | 1136 | ||
| 1067 | static void mod_kobject_remove(struct module *mod) | 1137 | static void mod_kobject_remove(struct module *mod) |
| 1068 | { | 1138 | { |
| 1139 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1140 | module_remove_modinfo_attrs(mod); | ||
| 1141 | #endif | ||
| 1069 | module_remove_refcnt_attr(mod); | 1142 | module_remove_refcnt_attr(mod); |
| 1070 | module_param_sysfs_remove(mod); | 1143 | module_param_sysfs_remove(mod); |
| 1071 | 1144 | ||
| @@ -1311,6 +1384,23 @@ static char *get_modinfo(Elf_Shdr *sechdrs, | |||
| 1311 | return NULL; | 1384 | return NULL; |
| 1312 | } | 1385 | } |
| 1313 | 1386 | ||
| 1387 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1388 | static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, | ||
| 1389 | unsigned int infoindex) | ||
| 1390 | { | ||
| 1391 | struct module_attribute *attr; | ||
| 1392 | int i; | ||
| 1393 | |||
| 1394 | for (i = 0; (attr = modinfo_attrs[i]); i++) { | ||
| 1395 | if (attr->setup) | ||
| 1396 | attr->setup(mod, | ||
| 1397 | get_modinfo(sechdrs, | ||
| 1398 | infoindex, | ||
| 1399 | attr->attr.name)); | ||
| 1400 | } | ||
| 1401 | } | ||
| 1402 | #endif | ||
| 1403 | |||
| 1314 | #ifdef CONFIG_KALLSYMS | 1404 | #ifdef CONFIG_KALLSYMS |
| 1315 | int is_exported(const char *name, const struct module *mod) | 1405 | int is_exported(const char *name, const struct module *mod) |
| 1316 | { | 1406 | { |
| @@ -1615,6 +1705,11 @@ static struct module *load_module(void __user *umod, | |||
| 1615 | /* Set up license info based on the info section */ | 1705 | /* Set up license info based on the info section */ |
| 1616 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); | 1706 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); |
| 1617 | 1707 | ||
| 1708 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1709 | /* Set up MODINFO_ATTR fields */ | ||
| 1710 | setup_modinfo(mod, sechdrs, infoindex); | ||
| 1711 | #endif | ||
| 1712 | |||
| 1618 | /* Fix up syms, so that st_value is a pointer to location. */ | 1713 | /* Fix up syms, so that st_value is a pointer to location. */ |
| 1619 | err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, | 1714 | err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, |
| 1620 | mod); | 1715 | mod); |
