aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/module.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2012-09-28 01:01:03 -0400
committerRusty Russell <rusty@rustcorp.com.au>2012-09-28 01:01:03 -0400
commit6f13909f4fe9652f189b462c6c98767309000321 (patch)
tree0b56b6817caea8d81c46bbbfe575cd4729ca4a23 /kernel/module.c
parent786d35d45cc40b2a51a18f73e14e135d47fdced7 (diff)
module: fix symbol waiting when module fails before init
We use resolve_symbol_wait(), which blocks if the module containing the symbol is still loading. However: 1) The module_wq we use is only woken after calling the modules' init function, but there are other failure paths after the module is placed in the linked list where we need to do the same thing. 2) wake_up() only wakes one waiter, and our waitqueue is shared by all modules, so we need to wake them all. 3) wake_up_all() doesn't imply a memory barrier: I feel happier calling it after we've grabbed and dropped the module_mutex, not just after the state assignment. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'kernel/module.c')
-rw-r--r--kernel/module.c8
1 files changed, 4 insertions, 4 deletions
diff --git a/kernel/module.c b/kernel/module.c
index 7f2ee45f362c..63cf6e7f1394 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2959,7 +2959,7 @@ static struct module *load_module(void __user *umod,
2959 /* Unlink carefully: kallsyms could be walking list. */ 2959 /* Unlink carefully: kallsyms could be walking list. */
2960 list_del_rcu(&mod->list); 2960 list_del_rcu(&mod->list);
2961 module_bug_cleanup(mod); 2961 module_bug_cleanup(mod);
2962 2962 wake_up_all(&module_wq);
2963 ddebug: 2963 ddebug:
2964 dynamic_debug_remove(info.debug); 2964 dynamic_debug_remove(info.debug);
2965 unlock: 2965 unlock:
@@ -3034,7 +3034,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
3034 blocking_notifier_call_chain(&module_notify_list, 3034 blocking_notifier_call_chain(&module_notify_list,
3035 MODULE_STATE_GOING, mod); 3035 MODULE_STATE_GOING, mod);
3036 free_module(mod); 3036 free_module(mod);
3037 wake_up(&module_wq); 3037 wake_up_all(&module_wq);
3038 return ret; 3038 return ret;
3039 } 3039 }
3040 if (ret > 0) { 3040 if (ret > 0) {
@@ -3046,9 +3046,8 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
3046 dump_stack(); 3046 dump_stack();
3047 } 3047 }
3048 3048
3049 /* Now it's a first class citizen! Wake up anyone waiting for it. */ 3049 /* Now it's a first class citizen! */
3050 mod->state = MODULE_STATE_LIVE; 3050 mod->state = MODULE_STATE_LIVE;
3051 wake_up(&module_wq);
3052 blocking_notifier_call_chain(&module_notify_list, 3051 blocking_notifier_call_chain(&module_notify_list,
3053 MODULE_STATE_LIVE, mod); 3052 MODULE_STATE_LIVE, mod);
3054 3053
@@ -3071,6 +3070,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
3071 mod->init_ro_size = 0; 3070 mod->init_ro_size = 0;
3072 mod->init_text_size = 0; 3071 mod->init_text_size = 0;
3073 mutex_unlock(&module_mutex); 3072 mutex_unlock(&module_mutex);
3073 wake_up_all(&module_wq);
3074 3074
3075 return 0; 3075 return 0;
3076} 3076}