aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-02-16 16:50:23 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-03-20 16:42:58 -0500
commit03e88ae1b13dfdc8bbaa59b8198e1ca53aad12ac (patch)
tree322127d9875129d2e9b1c3cb744b4940bd7d8a47
parentb87ba0a33a634c9a8e3609702122a04034a0688d (diff)
[PATCH] fix module sysfs files reference counting
The module files, refcnt, version, and srcversion did not properly increment the owner's module reference count, allowing the modules to be removed while the files were open, causing oopses. This patch fixes this, and also fixes the problem that the version and srcversion files were not showing up, unless CONFIG_MODULE_UNLOAD was enabled, which is not correct. Cc: Nathan Lynch <ntl@pobox.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--include/linux/module.h1
-rw-r--r--kernel/module.c77
-rw-r--r--kernel/params.c10
3 files changed, 32 insertions, 56 deletions
diff --git a/include/linux/module.h b/include/linux/module.h
index a25d5f61548c..70bd843c71cb 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -245,6 +245,7 @@ struct module
245 /* Sysfs stuff. */ 245 /* Sysfs stuff. */
246 struct module_kobject mkobj; 246 struct module_kobject mkobj;
247 struct module_param_attrs *param_attrs; 247 struct module_param_attrs *param_attrs;
248 struct module_attribute *modinfo_attrs;
248 const char *version; 249 const char *version;
249 const char *srcversion; 250 const char *srcversion;
250 251
diff --git a/kernel/module.c b/kernel/module.c
index 5ca99fbe9f44..77764f22f021 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -429,7 +429,6 @@ static inline void percpu_modcopy(void *pcpudst, const void *src,
429} 429}
430#endif /* CONFIG_SMP */ 430#endif /* CONFIG_SMP */
431 431
432#ifdef CONFIG_MODULE_UNLOAD
433#define MODINFO_ATTR(field) \ 432#define MODINFO_ATTR(field) \
434static void setup_modinfo_##field(struct module *mod, const char *s) \ 433static void setup_modinfo_##field(struct module *mod, const char *s) \
435{ \ 434{ \
@@ -461,12 +460,7 @@ static struct module_attribute modinfo_##field = { \
461MODINFO_ATTR(version); 460MODINFO_ATTR(version);
462MODINFO_ATTR(srcversion); 461MODINFO_ATTR(srcversion);
463 462
464static struct module_attribute *modinfo_attrs[] = { 463#ifdef CONFIG_MODULE_UNLOAD
465 &modinfo_version,
466 &modinfo_srcversion,
467 NULL,
468};
469
470/* Init the unload section of the module. */ 464/* Init the unload section of the module. */
471static void module_unload_init(struct module *mod) 465static void module_unload_init(struct module *mod)
472{ 466{
@@ -781,6 +775,15 @@ static inline void module_unload_init(struct module *mod)
781} 775}
782#endif /* CONFIG_MODULE_UNLOAD */ 776#endif /* CONFIG_MODULE_UNLOAD */
783 777
778static struct module_attribute *modinfo_attrs[] = {
779 &modinfo_version,
780 &modinfo_srcversion,
781#ifdef CONFIG_MODULE_UNLOAD
782 &refcnt,
783#endif
784 NULL,
785};
786
784#ifdef CONFIG_OBSOLETE_MODPARM 787#ifdef CONFIG_OBSOLETE_MODPARM
785/* Bounds checking done below */ 788/* Bounds checking done below */
786static int obsparm_copy_string(const char *val, struct kernel_param *kp) 789static int obsparm_copy_string(const char *val, struct kernel_param *kp)
@@ -1106,37 +1109,28 @@ static inline void remove_sect_attrs(struct module *mod)
1106} 1109}
1107#endif /* CONFIG_KALLSYMS */ 1110#endif /* CONFIG_KALLSYMS */
1108 1111
1109
1110#ifdef CONFIG_MODULE_UNLOAD
1111static inline int module_add_refcnt_attr(struct module *mod)
1112{
1113 return sysfs_create_file(&mod->mkobj.kobj, &refcnt.attr);
1114}
1115static void module_remove_refcnt_attr(struct module *mod)
1116{
1117 return sysfs_remove_file(&mod->mkobj.kobj, &refcnt.attr);
1118}
1119#else
1120static inline int module_add_refcnt_attr(struct module *mod)
1121{
1122 return 0;
1123}
1124static void module_remove_refcnt_attr(struct module *mod)
1125{
1126}
1127#endif
1128
1129#ifdef CONFIG_MODULE_UNLOAD
1130static int module_add_modinfo_attrs(struct module *mod) 1112static int module_add_modinfo_attrs(struct module *mod)
1131{ 1113{
1132 struct module_attribute *attr; 1114 struct module_attribute *attr;
1115 struct module_attribute *temp_attr;
1133 int error = 0; 1116 int error = 0;
1134 int i; 1117 int i;
1135 1118
1119 mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
1120 (ARRAY_SIZE(modinfo_attrs) + 1)),
1121 GFP_KERNEL);
1122 if (!mod->modinfo_attrs)
1123 return -ENOMEM;
1124
1125 temp_attr = mod->modinfo_attrs;
1136 for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { 1126 for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
1137 if (!attr->test || 1127 if (!attr->test ||
1138 (attr->test && attr->test(mod))) 1128 (attr->test && attr->test(mod))) {
1139 error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr); 1129 memcpy(temp_attr, attr, sizeof(*temp_attr));
1130 temp_attr->attr.owner = mod;
1131 error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr);
1132 ++temp_attr;
1133 }
1140 } 1134 }
1141 return error; 1135 return error;
1142} 1136}
@@ -1146,12 +1140,16 @@ static void module_remove_modinfo_attrs(struct module *mod)
1146 struct module_attribute *attr; 1140 struct module_attribute *attr;
1147 int i; 1141 int i;
1148 1142
1149 for (i = 0; (attr = modinfo_attrs[i]); i++) { 1143 for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
1144 /* pick a field to test for end of list */
1145 if (!attr->attr.name)
1146 break;
1150 sysfs_remove_file(&mod->mkobj.kobj,&attr->attr); 1147 sysfs_remove_file(&mod->mkobj.kobj,&attr->attr);
1151 attr->free(mod); 1148 if (attr->free)
1149 attr->free(mod);
1152 } 1150 }
1151 kfree(mod->modinfo_attrs);
1153} 1152}
1154#endif
1155 1153
1156static int mod_sysfs_setup(struct module *mod, 1154static int mod_sysfs_setup(struct module *mod,
1157 struct kernel_param *kparam, 1155 struct kernel_param *kparam,
@@ -1169,19 +1167,13 @@ static int mod_sysfs_setup(struct module *mod,
1169 if (err) 1167 if (err)
1170 goto out; 1168 goto out;
1171 1169
1172 err = module_add_refcnt_attr(mod);
1173 if (err)
1174 goto out_unreg;
1175
1176 err = module_param_sysfs_setup(mod, kparam, num_params); 1170 err = module_param_sysfs_setup(mod, kparam, num_params);
1177 if (err) 1171 if (err)
1178 goto out_unreg; 1172 goto out_unreg;
1179 1173
1180#ifdef CONFIG_MODULE_UNLOAD
1181 err = module_add_modinfo_attrs(mod); 1174 err = module_add_modinfo_attrs(mod);
1182 if (err) 1175 if (err)
1183 goto out_unreg; 1176 goto out_unreg;
1184#endif
1185 1177
1186 return 0; 1178 return 0;
1187 1179
@@ -1193,10 +1185,7 @@ out:
1193 1185
1194static void mod_kobject_remove(struct module *mod) 1186static void mod_kobject_remove(struct module *mod)
1195{ 1187{
1196#ifdef CONFIG_MODULE_UNLOAD
1197 module_remove_modinfo_attrs(mod); 1188 module_remove_modinfo_attrs(mod);
1198#endif
1199 module_remove_refcnt_attr(mod);
1200 module_param_sysfs_remove(mod); 1189 module_param_sysfs_remove(mod);
1201 1190
1202 kobject_unregister(&mod->mkobj.kobj); 1191 kobject_unregister(&mod->mkobj.kobj);
@@ -1474,7 +1463,6 @@ static char *get_modinfo(Elf_Shdr *sechdrs,
1474 return NULL; 1463 return NULL;
1475} 1464}
1476 1465
1477#ifdef CONFIG_MODULE_UNLOAD
1478static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, 1466static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
1479 unsigned int infoindex) 1467 unsigned int infoindex)
1480{ 1468{
@@ -1489,7 +1477,6 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
1489 attr->attr.name)); 1477 attr->attr.name));
1490 } 1478 }
1491} 1479}
1492#endif
1493 1480
1494#ifdef CONFIG_KALLSYMS 1481#ifdef CONFIG_KALLSYMS
1495int is_exported(const char *name, const struct module *mod) 1482int is_exported(const char *name, const struct module *mod)
@@ -1803,10 +1790,8 @@ static struct module *load_module(void __user *umod,
1803 if (strcmp(mod->name, "driverloader") == 0) 1790 if (strcmp(mod->name, "driverloader") == 0)
1804 add_taint(TAINT_PROPRIETARY_MODULE); 1791 add_taint(TAINT_PROPRIETARY_MODULE);
1805 1792
1806#ifdef CONFIG_MODULE_UNLOAD
1807 /* Set up MODINFO_ATTR fields */ 1793 /* Set up MODINFO_ATTR fields */
1808 setup_modinfo(mod, sechdrs, infoindex); 1794 setup_modinfo(mod, sechdrs, infoindex);
1809#endif
1810 1795
1811 /* Fix up syms, so that st_value is a pointer to location. */ 1796 /* Fix up syms, so that st_value is a pointer to location. */
1812 err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, 1797 err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
diff --git a/kernel/params.c b/kernel/params.c
index c76ad25e6a21..a29150582310 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -638,13 +638,8 @@ static ssize_t module_attr_show(struct kobject *kobj,
638 if (!attribute->show) 638 if (!attribute->show)
639 return -EIO; 639 return -EIO;
640 640
641 if (!try_module_get(mk->mod))
642 return -ENODEV;
643
644 ret = attribute->show(attribute, mk->mod, buf); 641 ret = attribute->show(attribute, mk->mod, buf);
645 642
646 module_put(mk->mod);
647
648 return ret; 643 return ret;
649} 644}
650 645
@@ -662,13 +657,8 @@ static ssize_t module_attr_store(struct kobject *kobj,
662 if (!attribute->store) 657 if (!attribute->store)
663 return -EIO; 658 return -EIO;
664 659
665 if (!try_module_get(mk->mod))
666 return -ENODEV;
667
668 ret = attribute->store(attribute, mk->mod, buf, len); 660 ret = attribute->store(attribute, mk->mod, buf, len);
669 661
670 module_put(mk->mod);
671
672 return ret; 662 return ret;
673} 663}
674 664