diff options
author | Peter Zijlstra <peterz@infradead.org> | 2014-09-24 04:18:53 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-10-28 05:56:30 -0400 |
commit | 3c9b2c3d64a49f264422d7743599cf7f6535972d (patch) | |
tree | 72e5230f01883c626c4d9415b7c53f9cbc9f6365 /kernel/module.c | |
parent | 7d4d26966e0b6443c78123a8a8b602e8eaf67694 (diff) |
sched, modules: Fix nested sleep in add_unformed_module()
This is a genuine bug in add_unformed_module(), we cannot use blocking
primitives inside a wait loop.
So rewrite the wait_event_interruptible() usage to use the fresh
wait_woken() stuff.
Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: tglx@linutronix.de
Cc: ilya.dryomov@inktank.com
Cc: umgwanakikbuti@gmail.com
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: oleg@redhat.com
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: http://lkml.kernel.org/r/20140924082242.458562904@infradead.org
[ So this is probably complex to backport and the race wasn't reported AFAIK,
so not marked for -stable. ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/kernel/module.c b/kernel/module.c index 88cec1ddb1e3..e52a8739361a 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -3097,6 +3097,32 @@ static int may_init_module(void) | |||
3097 | } | 3097 | } |
3098 | 3098 | ||
3099 | /* | 3099 | /* |
3100 | * Can't use wait_event_interruptible() because our condition | ||
3101 | * 'finished_loading()' contains a blocking primitive itself (mutex_lock). | ||
3102 | */ | ||
3103 | static int wait_finished_loading(struct module *mod) | ||
3104 | { | ||
3105 | DEFINE_WAIT_FUNC(wait, woken_wake_function); | ||
3106 | int ret = 0; | ||
3107 | |||
3108 | add_wait_queue(&module_wq, &wait); | ||
3109 | for (;;) { | ||
3110 | if (finished_loading(mod->name)) | ||
3111 | break; | ||
3112 | |||
3113 | if (signal_pending(current)) { | ||
3114 | ret = -ERESTARTSYS; | ||
3115 | break; | ||
3116 | } | ||
3117 | |||
3118 | wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); | ||
3119 | } | ||
3120 | remove_wait_queue(&module_wq, &wait); | ||
3121 | |||
3122 | return ret; | ||
3123 | } | ||
3124 | |||
3125 | /* | ||
3100 | * We try to place it in the list now to make sure it's unique before | 3126 | * We try to place it in the list now to make sure it's unique before |
3101 | * we dedicate too many resources. In particular, temporary percpu | 3127 | * we dedicate too many resources. In particular, temporary percpu |
3102 | * memory exhaustion. | 3128 | * memory exhaustion. |
@@ -3116,8 +3142,8 @@ again: | |||
3116 | || old->state == MODULE_STATE_UNFORMED) { | 3142 | || old->state == MODULE_STATE_UNFORMED) { |
3117 | /* Wait in case it fails to load. */ | 3143 | /* Wait in case it fails to load. */ |
3118 | mutex_unlock(&module_mutex); | 3144 | mutex_unlock(&module_mutex); |
3119 | err = wait_event_interruptible(module_wq, | 3145 | |
3120 | finished_loading(mod->name)); | 3146 | err = wait_finished_loading(mod); |
3121 | if (err) | 3147 | if (err) |
3122 | goto out_unlocked; | 3148 | goto out_unlocked; |
3123 | goto again; | 3149 | goto again; |