module: Unlink module with RCU synchronizing instead of stop_machine
[linux-2.6-block.git] / kernel / module.c
index 65586ffa0c9829ce0f75b21db76477ad5685c96f..bed608b8c8a6842fa016dd7fa1afe23231667874 100644 (file)
@@ -1697,18 +1697,6 @@ static void mod_sysfs_teardown(struct module *mod)
        mod_sysfs_fini(mod);
 }
 
-/*
- * unlink the module with the whole machine is stopped with interrupts off
- * - this defends against kallsyms not taking locks
- */
-static int __unlink_module(void *_mod)
-{
-       struct module *mod = _mod;
-       list_del(&mod->list);
-       module_bug_cleanup(mod);
-       return 0;
-}
-
 #ifdef CONFIG_DEBUG_SET_MODULE_RONX
 /*
  * LKM RO/NX protection: protect module's text/ro-data
@@ -1842,7 +1830,9 @@ static void free_module(struct module *mod)
 
        /* We leave it in list to prevent duplicate loads, but make sure
         * that noone uses it while it's being deconstructed. */
+       mutex_lock(&module_mutex);
        mod->state = MODULE_STATE_UNFORMED;
+       mutex_unlock(&module_mutex);
 
        /* Remove dynamic debug info */
        ddebug_remove_module(mod->name);
@@ -1858,7 +1848,11 @@ static void free_module(struct module *mod)
 
        /* Now we can delete it from the lists */
        mutex_lock(&module_mutex);
-       stop_machine(__unlink_module, mod, NULL);
+       /* Unlink carefully: kallsyms could be walking list. */
+       list_del_rcu(&mod->list);
+       /* Wait for RCU synchronizing before releasing mod->list. */
+       synchronize_rcu();
+       module_bug_cleanup(mod);
        mutex_unlock(&module_mutex);
 
        /* This may be NULL, but that's OK */
@@ -3324,6 +3318,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
        /* Unlink carefully: kallsyms could be walking list. */
        list_del_rcu(&mod->list);
        wake_up_all(&module_wq);
+       /* Wait for RCU synchronizing before releasing mod->list. */
+       synchronize_rcu();
        mutex_unlock(&module_mutex);
  free_module:
        module_deallocate(mod, info);