diff options
| author | David Woodhouse <dwmw2@infradead.org> | 2007-01-17 18:34:51 -0500 |
|---|---|---|
| committer | David Woodhouse <dwmw2@infradead.org> | 2007-01-17 18:34:51 -0500 |
| commit | 9cdf083f981b8d37b3212400a359368661385099 (patch) | |
| tree | aa15a6a08ad87e650dea40fb59b3180bef0d345b /kernel/module.c | |
| parent | e499e01d234a31d59679b7b1e1cf628d917ba49a (diff) | |
| parent | a8b3485287731978899ced11f24628c927890e78 (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 103 |
1 files changed, 95 insertions, 8 deletions
diff --git a/kernel/module.c b/kernel/module.c index f0166563c602..d0f2260a0210 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -34,10 +34,10 @@ | |||
| 34 | #include <linux/err.h> | 34 | #include <linux/err.h> |
| 35 | #include <linux/vermagic.h> | 35 | #include <linux/vermagic.h> |
| 36 | #include <linux/notifier.h> | 36 | #include <linux/notifier.h> |
| 37 | #include <linux/sched.h> | ||
| 37 | #include <linux/stop_machine.h> | 38 | #include <linux/stop_machine.h> |
| 38 | #include <linux/device.h> | 39 | #include <linux/device.h> |
| 39 | #include <linux/string.h> | 40 | #include <linux/string.h> |
| 40 | #include <linux/sched.h> | ||
| 41 | #include <linux/mutex.h> | 41 | #include <linux/mutex.h> |
| 42 | #include <linux/unwind.h> | 42 | #include <linux/unwind.h> |
| 43 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
| @@ -790,6 +790,19 @@ static struct module_attribute refcnt = { | |||
| 790 | .show = show_refcnt, | 790 | .show = show_refcnt, |
| 791 | }; | 791 | }; |
| 792 | 792 | ||
| 793 | void module_put(struct module *module) | ||
| 794 | { | ||
| 795 | if (module) { | ||
| 796 | unsigned int cpu = get_cpu(); | ||
| 797 | local_dec(&module->ref[cpu].count); | ||
| 798 | /* Maybe they're waiting for us to drop reference? */ | ||
| 799 | if (unlikely(!module_is_live(module))) | ||
| 800 | wake_up_process(module->waiter); | ||
| 801 | put_cpu(); | ||
| 802 | } | ||
| 803 | } | ||
| 804 | EXPORT_SYMBOL(module_put); | ||
| 805 | |||
| 793 | #else /* !CONFIG_MODULE_UNLOAD */ | 806 | #else /* !CONFIG_MODULE_UNLOAD */ |
| 794 | static void print_unload_info(struct seq_file *m, struct module *mod) | 807 | static void print_unload_info(struct seq_file *m, struct module *mod) |
| 795 | { | 808 | { |
| @@ -811,9 +824,34 @@ static inline void module_unload_init(struct module *mod) | |||
| 811 | } | 824 | } |
| 812 | #endif /* CONFIG_MODULE_UNLOAD */ | 825 | #endif /* CONFIG_MODULE_UNLOAD */ |
| 813 | 826 | ||
| 827 | static ssize_t show_initstate(struct module_attribute *mattr, | ||
| 828 | struct module *mod, char *buffer) | ||
| 829 | { | ||
| 830 | const char *state = "unknown"; | ||
| 831 | |||
| 832 | switch (mod->state) { | ||
| 833 | case MODULE_STATE_LIVE: | ||
| 834 | state = "live"; | ||
| 835 | break; | ||
| 836 | case MODULE_STATE_COMING: | ||
| 837 | state = "coming"; | ||
| 838 | break; | ||
| 839 | case MODULE_STATE_GOING: | ||
| 840 | state = "going"; | ||
| 841 | break; | ||
| 842 | } | ||
| 843 | return sprintf(buffer, "%s\n", state); | ||
| 844 | } | ||
| 845 | |||
| 846 | static struct module_attribute initstate = { | ||
| 847 | .attr = { .name = "initstate", .mode = 0444, .owner = THIS_MODULE }, | ||
| 848 | .show = show_initstate, | ||
| 849 | }; | ||
| 850 | |||
| 814 | static struct module_attribute *modinfo_attrs[] = { | 851 | static struct module_attribute *modinfo_attrs[] = { |
| 815 | &modinfo_version, | 852 | &modinfo_version, |
| 816 | &modinfo_srcversion, | 853 | &modinfo_srcversion, |
| 854 | &initstate, | ||
| 817 | #ifdef CONFIG_MODULE_UNLOAD | 855 | #ifdef CONFIG_MODULE_UNLOAD |
| 818 | &refcnt, | 856 | &refcnt, |
| 819 | #endif | 857 | #endif |
| @@ -1086,22 +1124,37 @@ static int mod_sysfs_setup(struct module *mod, | |||
| 1086 | goto out; | 1124 | goto out; |
| 1087 | kobj_set_kset_s(&mod->mkobj, module_subsys); | 1125 | kobj_set_kset_s(&mod->mkobj, module_subsys); |
| 1088 | mod->mkobj.mod = mod; | 1126 | mod->mkobj.mod = mod; |
| 1089 | err = kobject_register(&mod->mkobj.kobj); | 1127 | |
| 1128 | /* delay uevent until full sysfs population */ | ||
| 1129 | kobject_init(&mod->mkobj.kobj); | ||
| 1130 | err = kobject_add(&mod->mkobj.kobj); | ||
| 1090 | if (err) | 1131 | if (err) |
| 1091 | goto out; | 1132 | goto out; |
| 1092 | 1133 | ||
| 1134 | mod->drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers"); | ||
| 1135 | if (!mod->drivers_dir) { | ||
| 1136 | err = -ENOMEM; | ||
| 1137 | goto out_unreg; | ||
| 1138 | } | ||
| 1139 | |||
| 1093 | err = module_param_sysfs_setup(mod, kparam, num_params); | 1140 | err = module_param_sysfs_setup(mod, kparam, num_params); |
| 1094 | if (err) | 1141 | if (err) |
| 1095 | goto out_unreg; | 1142 | goto out_unreg_drivers; |
| 1096 | 1143 | ||
| 1097 | err = module_add_modinfo_attrs(mod); | 1144 | err = module_add_modinfo_attrs(mod); |
| 1098 | if (err) | 1145 | if (err) |
| 1099 | goto out_unreg; | 1146 | goto out_unreg_param; |
| 1100 | 1147 | ||
| 1148 | kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD); | ||
| 1101 | return 0; | 1149 | return 0; |
| 1102 | 1150 | ||
| 1151 | out_unreg_param: | ||
| 1152 | module_param_sysfs_remove(mod); | ||
| 1153 | out_unreg_drivers: | ||
| 1154 | kobject_unregister(mod->drivers_dir); | ||
| 1103 | out_unreg: | 1155 | out_unreg: |
| 1104 | kobject_unregister(&mod->mkobj.kobj); | 1156 | kobject_del(&mod->mkobj.kobj); |
| 1157 | kobject_put(&mod->mkobj.kobj); | ||
| 1105 | out: | 1158 | out: |
| 1106 | return err; | 1159 | return err; |
| 1107 | } | 1160 | } |
| @@ -1110,6 +1163,7 @@ static void mod_kobject_remove(struct module *mod) | |||
| 1110 | { | 1163 | { |
| 1111 | module_remove_modinfo_attrs(mod); | 1164 | module_remove_modinfo_attrs(mod); |
| 1112 | module_param_sysfs_remove(mod); | 1165 | module_param_sysfs_remove(mod); |
| 1166 | kobject_unregister(mod->drivers_dir); | ||
| 1113 | 1167 | ||
| 1114 | kobject_unregister(&mod->mkobj.kobj); | 1168 | kobject_unregister(&mod->mkobj.kobj); |
| 1115 | } | 1169 | } |
| @@ -2182,7 +2236,7 @@ static int m_show(struct seq_file *m, void *p) | |||
| 2182 | Where refcount is a number or -, and deps is a comma-separated list | 2236 | Where refcount is a number or -, and deps is a comma-separated list |
| 2183 | of depends or -. | 2237 | of depends or -. |
| 2184 | */ | 2238 | */ |
| 2185 | struct seq_operations modules_op = { | 2239 | const struct seq_operations modules_op = { |
| 2186 | .start = m_start, | 2240 | .start = m_start, |
| 2187 | .next = m_next, | 2241 | .next = m_next, |
| 2188 | .stop = m_stop, | 2242 | .stop = m_stop, |
| @@ -2273,21 +2327,54 @@ void print_modules(void) | |||
| 2273 | printk("\n"); | 2327 | printk("\n"); |
| 2274 | } | 2328 | } |
| 2275 | 2329 | ||
| 2330 | static char *make_driver_name(struct device_driver *drv) | ||
| 2331 | { | ||
| 2332 | char *driver_name; | ||
| 2333 | |||
| 2334 | driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2, | ||
| 2335 | GFP_KERNEL); | ||
| 2336 | if (!driver_name) | ||
| 2337 | return NULL; | ||
| 2338 | |||
| 2339 | sprintf(driver_name, "%s:%s", drv->bus->name, drv->name); | ||
| 2340 | return driver_name; | ||
| 2341 | } | ||
| 2342 | |||
| 2276 | void module_add_driver(struct module *mod, struct device_driver *drv) | 2343 | void module_add_driver(struct module *mod, struct device_driver *drv) |
| 2277 | { | 2344 | { |
| 2345 | char *driver_name; | ||
| 2346 | int no_warn; | ||
| 2347 | |||
| 2278 | if (!mod || !drv) | 2348 | if (!mod || !drv) |
| 2279 | return; | 2349 | return; |
| 2280 | 2350 | ||
| 2281 | /* Don't check return code; this call is idempotent */ | 2351 | /* Don't check return codes; these calls are idempotent */ |
| 2282 | sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module"); | 2352 | no_warn = sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module"); |
| 2353 | driver_name = make_driver_name(drv); | ||
| 2354 | if (driver_name) { | ||
| 2355 | no_warn = sysfs_create_link(mod->drivers_dir, &drv->kobj, | ||
| 2356 | driver_name); | ||
| 2357 | kfree(driver_name); | ||
| 2358 | } | ||
| 2283 | } | 2359 | } |
| 2284 | EXPORT_SYMBOL(module_add_driver); | 2360 | EXPORT_SYMBOL(module_add_driver); |
| 2285 | 2361 | ||
| 2286 | void module_remove_driver(struct device_driver *drv) | 2362 | void module_remove_driver(struct device_driver *drv) |
| 2287 | { | 2363 | { |
| 2364 | char *driver_name; | ||
| 2365 | |||
| 2288 | if (!drv) | 2366 | if (!drv) |
| 2289 | return; | 2367 | return; |
| 2368 | |||
| 2290 | sysfs_remove_link(&drv->kobj, "module"); | 2369 | sysfs_remove_link(&drv->kobj, "module"); |
| 2370 | if (drv->owner && drv->owner->drivers_dir) { | ||
| 2371 | driver_name = make_driver_name(drv); | ||
| 2372 | if (driver_name) { | ||
| 2373 | sysfs_remove_link(drv->owner->drivers_dir, | ||
| 2374 | driver_name); | ||
| 2375 | kfree(driver_name); | ||
| 2376 | } | ||
| 2377 | } | ||
| 2291 | } | 2378 | } |
| 2292 | EXPORT_SYMBOL(module_remove_driver); | 2379 | EXPORT_SYMBOL(module_remove_driver); |
| 2293 | 2380 | ||
