aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-01-22 19:48:03 -0500
committerTejun Heo <tj@kernel.org>2013-01-22 19:48:03 -0500
commit21c3c5d2800733b7a276725b8e1ae49a694adc1a (patch)
tree5e9150f182dc71be6b939ac4dbd2c570d7313407 /block
parentbb813f4c933ae9f887a014483690d5f8b8ec05e1 (diff)
block: don't request module during elevator init
Block layer allows selecting an elevator which is built as a module to be selected as system default via kernel param "elevator=". This is achieved by automatically invoking request_module() whenever a new block device is initialized and the elevator is not available. This led to an interesting deadlock problem involving async and module init. Block device probing running off an async job invokes request_module(). While the module is being loaded, it performs async_synchronize_full() which ends up waiting for the async job which is already waiting for request_module() to finish, leading to deadlock. Invoking request_module() from deep in block device init path is already nasty in itself. It seems best to avoid these situations from the beginning by moving on-demand module loading out of block init path. The previous patch made sure that the default elevator module is loaded early during boot if available. This patch removes on-demand loading of the default elevator from elevator init path. As the module would have been loaded during boot, userland-visible behavior difference should be minimal. For more details, please refer to the following thread. http://thread.gmane.org/gmane.linux.kernel/1420814 v2: The bool parameter was named @request_module which conflicted with request_module(). This built okay w/ CONFIG_MODULES because request_module() was defined as a macro. W/o CONFIG_MODULES, it causes build breakage. Rename the parameter to @try_loading. Reported by Fengguang. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Jens Axboe <axboe@kernel.dk> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Alex Riesen <raa.lkml@gmail.com> Cc: Fengguang Wu <fengguang.wu@intel.com>
Diffstat (limited to 'block')
-rw-r--r--block/elevator.c19
1 files changed, 12 insertions, 7 deletions
diff --git a/block/elevator.c b/block/elevator.c
index c2d61d56e0b7..603b2c178740 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -100,14 +100,14 @@ static void elevator_put(struct elevator_type *e)
100 module_put(e->elevator_owner); 100 module_put(e->elevator_owner);
101} 101}
102 102
103static struct elevator_type *elevator_get(const char *name) 103static struct elevator_type *elevator_get(const char *name, bool try_loading)
104{ 104{
105 struct elevator_type *e; 105 struct elevator_type *e;
106 106
107 spin_lock(&elv_list_lock); 107 spin_lock(&elv_list_lock);
108 108
109 e = elevator_find(name); 109 e = elevator_find(name);
110 if (!e) { 110 if (!e && try_loading) {
111 spin_unlock(&elv_list_lock); 111 spin_unlock(&elv_list_lock);
112 request_module("%s-iosched", name); 112 request_module("%s-iosched", name);
113 spin_lock(&elv_list_lock); 113 spin_lock(&elv_list_lock);
@@ -207,25 +207,30 @@ int elevator_init(struct request_queue *q, char *name)
207 q->boundary_rq = NULL; 207 q->boundary_rq = NULL;
208 208
209 if (name) { 209 if (name) {
210 e = elevator_get(name); 210 e = elevator_get(name, true);
211 if (!e) 211 if (!e)
212 return -EINVAL; 212 return -EINVAL;
213 } 213 }
214 214
215 /*
216 * Use the default elevator specified by config boot param or
217 * config option. Don't try to load modules as we could be running
218 * off async and request_module() isn't allowed from async.
219 */
215 if (!e && *chosen_elevator) { 220 if (!e && *chosen_elevator) {
216 e = elevator_get(chosen_elevator); 221 e = elevator_get(chosen_elevator, false);
217 if (!e) 222 if (!e)
218 printk(KERN_ERR "I/O scheduler %s not found\n", 223 printk(KERN_ERR "I/O scheduler %s not found\n",
219 chosen_elevator); 224 chosen_elevator);
220 } 225 }
221 226
222 if (!e) { 227 if (!e) {
223 e = elevator_get(CONFIG_DEFAULT_IOSCHED); 228 e = elevator_get(CONFIG_DEFAULT_IOSCHED, false);
224 if (!e) { 229 if (!e) {
225 printk(KERN_ERR 230 printk(KERN_ERR
226 "Default I/O scheduler not found. " \ 231 "Default I/O scheduler not found. " \
227 "Using noop.\n"); 232 "Using noop.\n");
228 e = elevator_get("noop"); 233 e = elevator_get("noop", false);
229 } 234 }
230 } 235 }
231 236
@@ -967,7 +972,7 @@ int elevator_change(struct request_queue *q, const char *name)
967 return -ENXIO; 972 return -ENXIO;
968 973
969 strlcpy(elevator_name, name, sizeof(elevator_name)); 974 strlcpy(elevator_name, name, sizeof(elevator_name));
970 e = elevator_get(strstrip(elevator_name)); 975 e = elevator_get(strstrip(elevator_name), true);
971 if (!e) { 976 if (!e) {
972 printk(KERN_ERR "elevator: type %s not found\n", elevator_name); 977 printk(KERN_ERR "elevator: type %s not found\n", elevator_name);
973 return -EINVAL; 978 return -EINVAL;