67 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			67 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From: Rusty Russell <rusty@rustcorp.com.au>
 | 
						|
Date: Fri, 28 Sep 2012 05:01:03 +0000 (+0930)
 | 
						|
Subject: module: fix symbol waiting when module fails before init
 | 
						|
X-Git-Tag: v3.7-rc1~2^2~33
 | 
						|
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=6f13909f4fe9652f1
 | 
						|
 | 
						|
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>
 | 
						|
---
 | 
						|
 | 
						|
diff --git a/kernel/module.c b/kernel/module.c
 | 
						|
index 7f2ee45f..63cf6e7 100644
 | 
						|
--- a/kernel/module.c
 | 
						|
+++ b/kernel/module.c
 | 
						|
@@ -2959,7 +2959,7 @@ static struct module *load_module(void __user *umod,
 | 
						|
 	/* Unlink carefully: kallsyms could be walking list. */
 | 
						|
 	list_del_rcu(&mod->list);
 | 
						|
 	module_bug_cleanup(mod);
 | 
						|
-
 | 
						|
+	wake_up_all(&module_wq);
 | 
						|
  ddebug:
 | 
						|
 	dynamic_debug_remove(info.debug);
 | 
						|
  unlock:
 | 
						|
@@ -3034,7 +3034,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
 | 
						|
 		blocking_notifier_call_chain(&module_notify_list,
 | 
						|
 					     MODULE_STATE_GOING, mod);
 | 
						|
 		free_module(mod);
 | 
						|
-		wake_up(&module_wq);
 | 
						|
+		wake_up_all(&module_wq);
 | 
						|
 		return ret;
 | 
						|
 	}
 | 
						|
 	if (ret > 0) {
 | 
						|
@@ -3046,9 +3046,8 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
 | 
						|
 		dump_stack();
 | 
						|
 	}
 | 
						|
 
 | 
						|
-	/* Now it's a first class citizen!  Wake up anyone waiting for it. */
 | 
						|
+	/* Now it's a first class citizen! */
 | 
						|
 	mod->state = MODULE_STATE_LIVE;
 | 
						|
-	wake_up(&module_wq);
 | 
						|
 	blocking_notifier_call_chain(&module_notify_list,
 | 
						|
 				     MODULE_STATE_LIVE, mod);
 | 
						|
 
 | 
						|
@@ -3071,6 +3070,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
 | 
						|
 	mod->init_ro_size = 0;
 | 
						|
 	mod->init_text_size = 0;
 | 
						|
 	mutex_unlock(&module_mutex);
 | 
						|
+	wake_up_all(&module_wq);
 | 
						|
 
 | 
						|
 	return 0;
 | 
						|
 }
 |