]> err.no Git - linux-2.6/blobdiff - kernel/module.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[linux-2.6] / kernel / module.c
index dc4d3f5ce820882d26c7c1e4c8042610e5038239..1bb4c5e0d56e330b1de92b5e20fddbd446e9d314 100644 (file)
@@ -496,6 +496,8 @@ static struct module_attribute modinfo_##field = {                    \
 MODINFO_ATTR(version);
 MODINFO_ATTR(srcversion);
 
+static char last_unloaded_module[MODULE_NAME_LEN+1];
+
 #ifdef CONFIG_MODULE_UNLOAD
 /* Init the unload section of the module. */
 static void module_unload_init(struct module *mod)
@@ -719,6 +721,8 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
                mod->exit();
                mutex_lock(&module_mutex);
        }
+       /* Store the name of the last unloaded module for diagnostic purposes */
+       sprintf(last_unloaded_module, mod->name);
        free_module(mod);
 
  out:
@@ -1217,16 +1221,16 @@ int mod_sysfs_init(struct module *mod)
                err = -EINVAL;
                goto out;
        }
-       memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
-       err = kobject_set_name(&mod->mkobj.kobj, "%s", mod->name);
-       if (err)
-               goto out;
-       mod->mkobj.kobj.kset = module_kset;
-       mod->mkobj.kobj.ktype = &module_ktype;
        mod->mkobj.mod = mod;
 
-       kobject_init(&mod->mkobj.kobj);
+       memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
+       mod->mkobj.kobj.kset = module_kset;
+       err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
+                                  "%s", mod->name);
+       if (err)
+               kobject_put(&mod->mkobj.kobj);
 
+       /* delay uevent until full sysfs population */
 out:
        return err;
 }
@@ -1237,11 +1241,6 @@ int mod_sysfs_setup(struct module *mod,
 {
        int err;
 
-       /* delay uevent until full sysfs population */
-       err = kobject_add(&mod->mkobj.kobj);
-       if (err)
-               goto out;
-
        mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
        if (!mod->holders_dir) {
                err = -ENOMEM;
@@ -1262,11 +1261,9 @@ int mod_sysfs_setup(struct module *mod,
 out_unreg_param:
        module_param_sysfs_remove(mod);
 out_unreg_holders:
-       kobject_unregister(mod->holders_dir);
+       kobject_put(mod->holders_dir);
 out_unreg:
-       kobject_del(&mod->mkobj.kobj);
        kobject_put(&mod->mkobj.kobj);
-out:
        return err;
 }
 #endif
@@ -1275,9 +1272,9 @@ static void mod_kobject_remove(struct module *mod)
 {
        module_remove_modinfo_attrs(mod);
        module_param_sysfs_remove(mod);
-       kobject_unregister(mod->mkobj.drivers_dir);
-       kobject_unregister(mod->holders_dir);
-       kobject_unregister(&mod->mkobj.kobj);
+       kobject_put(mod->mkobj.drivers_dir);
+       kobject_put(mod->holders_dir);
+       kobject_put(&mod->mkobj.kobj);
 }
 
 /*
@@ -1883,10 +1880,10 @@ static struct module *load_module(void __user *umod,
        /* Now we've moved module, initialize linked lists, etc. */
        module_unload_init(mod);
 
-       /* Initialize kobject, so we can reference it. */
+       /* add kobject, so we can reference it. */
        err = mod_sysfs_init(mod);
        if (err)
-               goto cleanup;
+               goto free_unload;
 
        /* Set up license info based on the info section */
        set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
@@ -2056,6 +2053,9 @@ static struct module *load_module(void __user *umod,
  arch_cleanup:
        module_arch_cleanup(mod);
  cleanup:
+       kobject_del(&mod->mkobj.kobj);
+       kobject_put(&mod->mkobj.kobj);
+ free_unload:
        module_unload_free(mod);
        module_free(mod, mod->module_init);
  free_core:
@@ -2361,21 +2361,30 @@ static void m_stop(struct seq_file *m, void *p)
        mutex_unlock(&module_mutex);
 }
 
-static char *taint_flags(unsigned int taints, char *buf)
+static char *module_flags(struct module *mod, char *buf)
 {
        int bx = 0;
 
-       if (taints) {
+       if (mod->taints ||
+           mod->state == MODULE_STATE_GOING ||
+           mod->state == MODULE_STATE_COMING) {
                buf[bx++] = '(';
-               if (taints & TAINT_PROPRIETARY_MODULE)
+               if (mod->taints & TAINT_PROPRIETARY_MODULE)
                        buf[bx++] = 'P';
-               if (taints & TAINT_FORCED_MODULE)
+               if (mod->taints & TAINT_FORCED_MODULE)
                        buf[bx++] = 'F';
                /*
                 * TAINT_FORCED_RMMOD: could be added.
                 * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
                 * apply to modules.
                 */
+
+               /* Show a - for module-is-being-unloaded */
+               if (mod->state == MODULE_STATE_GOING)
+                       buf[bx++] = '-';
+               /* Show a + for module-is-being-loaded */
+               if (mod->state == MODULE_STATE_COMING)
+                       buf[bx++] = '+';
                buf[bx++] = ')';
        }
        buf[bx] = '\0';
@@ -2402,7 +2411,7 @@ static int m_show(struct seq_file *m, void *p)
 
        /* Taints info */
        if (mod->taints)
-               seq_printf(m, " %s", taint_flags(mod->taints, buf));
+               seq_printf(m, " %s", module_flags(mod, buf));
 
        seq_printf(m, "\n");
        return 0;
@@ -2497,7 +2506,9 @@ void print_modules(void)
 
        printk("Modules linked in:");
        list_for_each_entry(mod, &modules, list)
-               printk(" %s%s", mod->name, taint_flags(mod->taints, buf));
+               printk(" %s%s", mod->name, module_flags(mod, buf));
+       if (last_unloaded_module[0])
+               printk(" [last unloaded: %s]", last_unloaded_module);
        printk("\n");
 }