aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-20 01:10:26 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-20 01:10:26 -0500
commitece8e0b2f9c980e5511fe8db2d68c6f1859b9d83 (patch)
tree70f1e3363080884965686576d079d24da8863a58
parent67cb104b4c30bd52292b6a7f526349aab2dd5cbd (diff)
parenta0327ff0eda915be623658babacef706099c11a8 (diff)
Merge branch 'for-3.9-async' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
Pull async changes from Tejun Heo: "These are followups for the earlier deadlock issue involving async ending up waiting for itself through block requesting module[1]. The following changes are made by these commits. - Instead of requesting default elevator on each request_queue init, block now requests it once early during boot. - Kmod triggers warning if invoked from an async worker. - Async synchronization implementation has been reimplemented. It's a lot simpler now." * 'for-3.9-async' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq: async: initialise list heads to fix crash async: replace list of active domains with global list of pending items async: keep pending tasks on async_domain and remove async_pending async: use ULLONG_MAX for infinity cookie value async: bring sanity to the use of words domain and running async, kmod: warn on synchronous request_module() from async workers block: don't request module during elevator init init, block: try to load default elevator module early during boot
-rw-r--r--block/elevator.c35
-rw-r--r--include/linux/async.h9
-rw-r--r--include/linux/elevator.h5
-rw-r--r--include/linux/init.h1
-rw-r--r--init/do_mounts_initrd.c3
-rw-r--r--init/initramfs.c8
-rw-r--r--init/main.c16
-rw-r--r--kernel/async.c153
-rw-r--r--kernel/kmod.c9
9 files changed, 130 insertions, 109 deletions
diff --git a/block/elevator.c b/block/elevator.c
index 9edba1b8323e..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);
@@ -136,6 +136,22 @@ static int __init elevator_setup(char *str)
136 136
137__setup("elevator=", elevator_setup); 137__setup("elevator=", elevator_setup);
138 138
139/* called during boot to load the elevator chosen by the elevator param */
140void __init load_default_elevator_module(void)
141{
142 struct elevator_type *e;
143
144 if (!chosen_elevator[0])
145 return;
146
147 spin_lock(&elv_list_lock);
148 e = elevator_find(chosen_elevator);
149 spin_unlock(&elv_list_lock);
150
151 if (!e)
152 request_module("%s-iosched", chosen_elevator);
153}
154
139static struct kobj_type elv_ktype; 155static struct kobj_type elv_ktype;
140 156
141static struct elevator_queue *elevator_alloc(struct request_queue *q, 157static struct elevator_queue *elevator_alloc(struct request_queue *q,
@@ -191,25 +207,30 @@ int elevator_init(struct request_queue *q, char *name)
191 q->boundary_rq = NULL; 207 q->boundary_rq = NULL;
192 208
193 if (name) { 209 if (name) {
194 e = elevator_get(name); 210 e = elevator_get(name, true);
195 if (!e) 211 if (!e)
196 return -EINVAL; 212 return -EINVAL;
197 } 213 }
198 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 */
199 if (!e && *chosen_elevator) { 220 if (!e && *chosen_elevator) {
200 e = elevator_get(chosen_elevator); 221 e = elevator_get(chosen_elevator, false);
201 if (!e) 222 if (!e)
202 printk(KERN_ERR "I/O scheduler %s not found\n", 223 printk(KERN_ERR "I/O scheduler %s not found\n",
203 chosen_elevator); 224 chosen_elevator);
204 } 225 }
205 226
206 if (!e) { 227 if (!e) {
207 e = elevator_get(CONFIG_DEFAULT_IOSCHED); 228 e = elevator_get(CONFIG_DEFAULT_IOSCHED, false);
208 if (!e) { 229 if (!e) {
209 printk(KERN_ERR 230 printk(KERN_ERR
210 "Default I/O scheduler not found. " \ 231 "Default I/O scheduler not found. " \
211 "Using noop.\n"); 232 "Using noop.\n");
212 e = elevator_get("noop"); 233 e = elevator_get("noop", false);
213 } 234 }
214 } 235 }
215 236
@@ -951,7 +972,7 @@ int elevator_change(struct request_queue *q, const char *name)
951 return -ENXIO; 972 return -ENXIO;
952 973
953 strlcpy(elevator_name, name, sizeof(elevator_name)); 974 strlcpy(elevator_name, name, sizeof(elevator_name));
954 e = elevator_get(strstrip(elevator_name)); 975 e = elevator_get(strstrip(elevator_name), true);
955 if (!e) { 976 if (!e) {
956 printk(KERN_ERR "elevator: type %s not found\n", elevator_name); 977 printk(KERN_ERR "elevator: type %s not found\n", elevator_name);
957 return -EINVAL; 978 return -EINVAL;
diff --git a/include/linux/async.h b/include/linux/async.h
index 345169cfa304..a2e3f18b2ad6 100644
--- a/include/linux/async.h
+++ b/include/linux/async.h
@@ -19,8 +19,7 @@ typedef u64 async_cookie_t;
19typedef void (async_func_ptr) (void *data, async_cookie_t cookie); 19typedef void (async_func_ptr) (void *data, async_cookie_t cookie);
20struct async_domain { 20struct async_domain {
21 struct list_head node; 21 struct list_head node;
22 struct list_head domain; 22 struct list_head pending;
23 int count;
24 unsigned registered:1; 23 unsigned registered:1;
25}; 24};
26 25
@@ -29,8 +28,7 @@ struct async_domain {
29 */ 28 */
30#define ASYNC_DOMAIN(_name) \ 29#define ASYNC_DOMAIN(_name) \
31 struct async_domain _name = { .node = LIST_HEAD_INIT(_name.node), \ 30 struct async_domain _name = { .node = LIST_HEAD_INIT(_name.node), \
32 .domain = LIST_HEAD_INIT(_name.domain), \ 31 .pending = LIST_HEAD_INIT(_name.pending), \
33 .count = 0, \
34 .registered = 1 } 32 .registered = 1 }
35 33
36/* 34/*
@@ -39,8 +37,7 @@ struct async_domain {
39 */ 37 */
40#define ASYNC_DOMAIN_EXCLUSIVE(_name) \ 38#define ASYNC_DOMAIN_EXCLUSIVE(_name) \
41 struct async_domain _name = { .node = LIST_HEAD_INIT(_name.node), \ 39 struct async_domain _name = { .node = LIST_HEAD_INIT(_name.node), \
42 .domain = LIST_HEAD_INIT(_name.domain), \ 40 .pending = LIST_HEAD_INIT(_name.pending), \
43 .count = 0, \
44 .registered = 0 } 41 .registered = 0 }
45 42
46extern async_cookie_t async_schedule(async_func_ptr *ptr, void *data); 43extern async_cookie_t async_schedule(async_func_ptr *ptr, void *data);
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index c03af7687bb4..186620631750 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -138,6 +138,7 @@ extern void elv_drain_elevator(struct request_queue *);
138/* 138/*
139 * io scheduler registration 139 * io scheduler registration
140 */ 140 */
141extern void __init load_default_elevator_module(void);
141extern int elv_register(struct elevator_type *); 142extern int elv_register(struct elevator_type *);
142extern void elv_unregister(struct elevator_type *); 143extern void elv_unregister(struct elevator_type *);
143 144
@@ -206,5 +207,9 @@ enum {
206 INIT_LIST_HEAD(&(rq)->csd.list); \ 207 INIT_LIST_HEAD(&(rq)->csd.list); \
207 } while (0) 208 } while (0)
208 209
210#else /* CONFIG_BLOCK */
211
212static inline void load_default_elevator_module(void) { }
213
209#endif /* CONFIG_BLOCK */ 214#endif /* CONFIG_BLOCK */
210#endif 215#endif
diff --git a/include/linux/init.h b/include/linux/init.h
index 10ed4f436458..861814710d52 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -153,6 +153,7 @@ extern unsigned int reset_devices;
153/* used by init/main.c */ 153/* used by init/main.c */
154void setup_arch(char **); 154void setup_arch(char **);
155void prepare_namespace(void); 155void prepare_namespace(void);
156void __init load_default_modules(void);
156 157
157extern void (*late_time_init)(void); 158extern void (*late_time_init)(void);
158 159
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
index f9acf71b9810..a32ec1ce882b 100644
--- a/init/do_mounts_initrd.c
+++ b/init/do_mounts_initrd.c
@@ -61,6 +61,9 @@ static void __init handle_initrd(void)
61 sys_mkdir("/old", 0700); 61 sys_mkdir("/old", 0700);
62 sys_chdir("/old"); 62 sys_chdir("/old");