diff options
-rw-r--r-- | include/linux/module.h | 5 | ||||
-rw-r--r-- | kernel/module.c | 95 |
2 files changed, 100 insertions, 0 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index 0e432a0f4aee..f05372b7fe77 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -51,6 +51,9 @@ struct module_attribute { | |||
51 | ssize_t (*show)(struct module_attribute *, struct module *, char *); | 51 | ssize_t (*show)(struct module_attribute *, struct module *, char *); |
52 | ssize_t (*store)(struct module_attribute *, struct module *, | 52 | ssize_t (*store)(struct module_attribute *, struct module *, |
53 | const char *, size_t count); | 53 | const char *, size_t count); |
54 | void (*setup)(struct module *, const char *); | ||
55 | int (*test)(struct module *); | ||
56 | void (*free)(struct module *); | ||
54 | }; | 57 | }; |
55 | 58 | ||
56 | struct module_kobject | 59 | struct module_kobject |
@@ -239,6 +242,8 @@ struct module | |||
239 | /* Sysfs stuff. */ | 242 | /* Sysfs stuff. */ |
240 | struct module_kobject mkobj; | 243 | struct module_kobject mkobj; |
241 | struct module_param_attrs *param_attrs; | 244 | struct module_param_attrs *param_attrs; |
245 | const char *version; | ||
246 | const char *srcversion; | ||
242 | 247 | ||
243 | /* Exported symbols */ | 248 | /* Exported symbols */ |
244 | const struct kernel_symbol *syms; | 249 | const struct kernel_symbol *syms; |
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); |