diff options
Diffstat (limited to 'arch/um/os-Linux/aio.c')
-rw-r--r-- | arch/um/os-Linux/aio.c | 206 |
1 files changed, 111 insertions, 95 deletions
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c index f2ca2992bbd6..b04897cd995d 100644 --- a/arch/um/os-Linux/aio.c +++ b/arch/um/os-Linux/aio.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <stdlib.h> | 6 | #include <stdlib.h> |
7 | #include <unistd.h> | 7 | #include <unistd.h> |
8 | #include <signal.h> | 8 | #include <signal.h> |
9 | #include <string.h> | ||
9 | #include <errno.h> | 10 | #include <errno.h> |
10 | #include <sched.h> | 11 | #include <sched.h> |
11 | #include <sys/syscall.h> | 12 | #include <sys/syscall.h> |
@@ -16,18 +17,31 @@ | |||
16 | #include "user.h" | 17 | #include "user.h" |
17 | #include "mode.h" | 18 | #include "mode.h" |
18 | 19 | ||
19 | struct aio_thread_req { | ||
20 | enum aio_type type; | ||
21 | int io_fd; | ||
22 | unsigned long long offset; | ||
23 | char *buf; | ||
24 | int len; | ||
25 | struct aio_context *aio; | ||
26 | }; | ||
27 | |||
28 | static int aio_req_fd_r = -1; | 20 | static int aio_req_fd_r = -1; |
29 | static int aio_req_fd_w = -1; | 21 | static int aio_req_fd_w = -1; |
30 | 22 | ||
23 | static int update_aio(struct aio_context *aio, int res) | ||
24 | { | ||
25 | if(res < 0) | ||
26 | aio->len = res; | ||
27 | else if((res == 0) && (aio->type == AIO_READ)){ | ||
28 | /* This is the EOF case - we have hit the end of the file | ||
29 | * and it ends in a partial block, so we fill the end of | ||
30 | * the block with zeros and claim success. | ||
31 | */ | ||
32 | memset(aio->data, 0, aio->len); | ||
33 | aio->len = 0; | ||
34 | } | ||
35 | else if(res > 0){ | ||
36 | aio->len -= res; | ||
37 | aio->data += res; | ||
38 | aio->offset += res; | ||
39 | return aio->len; | ||
40 | } | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
31 | #if defined(HAVE_AIO_ABI) | 45 | #if defined(HAVE_AIO_ABI) |
32 | #include <linux/aio_abi.h> | 46 | #include <linux/aio_abi.h> |
33 | 47 | ||
@@ -66,8 +80,7 @@ static long io_getevents(aio_context_t ctx_id, long min_nr, long nr, | |||
66 | * that it now backs the mmapped area. | 80 | * that it now backs the mmapped area. |
67 | */ | 81 | */ |
68 | 82 | ||
69 | static int do_aio(aio_context_t ctx, enum aio_type type, int fd, char *buf, | 83 | static int do_aio(aio_context_t ctx, struct aio_context *aio) |
70 | int len, unsigned long long offset, struct aio_context *aio) | ||
71 | { | 84 | { |
72 | struct iocb iocb, *iocbp = &iocb; | 85 | struct iocb iocb, *iocbp = &iocb; |
73 | char c; | 86 | char c; |
@@ -75,37 +88,37 @@ static int do_aio(aio_context_t ctx, enum aio_type type, int fd, char *buf, | |||
75 | 88 | ||
76 | iocb = ((struct iocb) { .aio_data = (unsigned long) aio, | 89 | iocb = ((struct iocb) { .aio_data = (unsigned long) aio, |
77 | .aio_reqprio = 0, | 90 | .aio_reqprio = 0, |
78 | .aio_fildes = fd, | 91 | .aio_fildes = aio->fd, |
79 | .aio_buf = (unsigned long) buf, | 92 | .aio_buf = (unsigned long) aio->data, |
80 | .aio_nbytes = len, | 93 | .aio_nbytes = aio->len, |
81 | .aio_offset = offset, | 94 | .aio_offset = aio->offset, |
82 | .aio_reserved1 = 0, | 95 | .aio_reserved1 = 0, |
83 | .aio_reserved2 = 0, | 96 | .aio_reserved2 = 0, |
84 | .aio_reserved3 = 0 }); | 97 | .aio_reserved3 = 0 }); |
85 | 98 | ||
86 | switch(type){ | 99 | switch(aio->type){ |
87 | case AIO_READ: | 100 | case AIO_READ: |
88 | iocb.aio_lio_opcode = IOCB_CMD_PREAD; | 101 | iocb.aio_lio_opcode = IOCB_CMD_PREAD; |
89 | err = io_submit(ctx, 1, &iocbp); | ||
90 | break; | 102 | break; |
91 | case AIO_WRITE: | 103 | case AIO_WRITE: |
92 | iocb.aio_lio_opcode = IOCB_CMD_PWRITE; | 104 | iocb.aio_lio_opcode = IOCB_CMD_PWRITE; |
93 | err = io_submit(ctx, 1, &iocbp); | ||
94 | break; | 105 | break; |
95 | case AIO_MMAP: | 106 | case AIO_MMAP: |
96 | iocb.aio_lio_opcode = IOCB_CMD_PREAD; | 107 | iocb.aio_lio_opcode = IOCB_CMD_PREAD; |
97 | iocb.aio_buf = (unsigned long) &c; | 108 | iocb.aio_buf = (unsigned long) &c; |
98 | iocb.aio_nbytes = sizeof(c); | 109 | iocb.aio_nbytes = sizeof(c); |
99 | err = io_submit(ctx, 1, &iocbp); | ||
100 | break; | 110 | break; |
101 | default: | 111 | default: |
102 | printk("Bogus op in do_aio - %d\n", type); | 112 | printk("Bogus op in do_aio - %d\n", aio->type); |
103 | err = -EINVAL; | 113 | err = -EINVAL; |
104 | break; | 114 | goto out; |
105 | } | 115 | } |
116 | |||
117 | err = io_submit(ctx, 1, &iocbp); | ||
106 | if(err > 0) | 118 | if(err > 0) |
107 | err = 0; | 119 | err = 0; |
108 | 120 | ||
121 | out: | ||
109 | return err; | 122 | return err; |
110 | } | 123 | } |
111 | 124 | ||
@@ -114,8 +127,9 @@ static aio_context_t ctx = 0; | |||
114 | static int aio_thread(void *arg) | 127 | static int aio_thread(void *arg) |
115 | { | 128 | { |
116 | struct aio_thread_reply reply; | 129 | struct aio_thread_reply reply; |
130 | struct aio_context *aio; | ||
117 | struct io_event event; | 131 | struct io_event event; |
118 | int err, n, reply_fd; | 132 | int err, n; |
119 | 133 | ||
120 | signal(SIGWINCH, SIG_IGN); | 134 | signal(SIGWINCH, SIG_IGN); |
121 | 135 | ||
@@ -128,15 +142,21 @@ static int aio_thread(void *arg) | |||
128 | "errno = %d\n", errno); | 142 | "errno = %d\n", errno); |
129 | } | 143 | } |
130 | else { | 144 | else { |
145 | aio = (struct aio_context *) event.data; | ||
146 | if(update_aio(aio, event.res)){ | ||
147 | do_aio(ctx, aio); | ||
148 | continue; | ||
149 | } | ||
150 | |||
131 | reply = ((struct aio_thread_reply) | 151 | reply = ((struct aio_thread_reply) |
132 | { .data = (void *) (long) event.data, | 152 | { .data = aio, |
133 | .err = event.res }); | 153 | .err = aio->len }); |
134 | reply_fd = ((struct aio_context *) reply.data)->reply_fd; | 154 | err = os_write_file(aio->reply_fd, &reply, |
135 | err = os_write_file(reply_fd, &reply, sizeof(reply)); | 155 | sizeof(reply)); |
136 | if(err != sizeof(reply)) | 156 | if(err != sizeof(reply)) |
137 | printk("not_aio_thread - write failed, " | 157 | printk("aio_thread - write failed, " |
138 | "fd = %d, err = %d\n", | 158 | "fd = %d, err = %d\n", aio->reply_fd, |
139 | aio_req_fd_r, -err); | 159 | -err); |
140 | } | 160 | } |
141 | } | 161 | } |
142 | return 0; | 162 | return 0; |
@@ -144,35 +164,35 @@ static int aio_thread(void *arg) | |||
144 | 164 | ||
145 | #endif | 165 | #endif |
146 | 166 | ||
147 | static int do_not_aio(struct aio_thread_req *req) | 167 | static int do_not_aio(struct aio_context *aio) |
148 | { | 168 | { |
149 | char c; | 169 | char c; |
150 | int err; | 170 | int err; |
151 | 171 | ||
152 | switch(req->type){ | 172 | switch(aio->type){ |
153 | case AIO_READ: | 173 | case AIO_READ: |
154 | err = os_seek_file(req->io_fd, req->offset); | 174 | err = os_seek_file(aio->fd, aio->offset); |
155 | if(err) | 175 | if(err) |
156 | goto out; | 176 | goto out; |
157 | 177 | ||
158 | err = os_read_file(req->io_fd, req->buf, req->len); | 178 | err = os_read_file(aio->fd, aio->data, aio->len); |
159 | break; | 179 | break; |
160 | case AIO_WRITE: | 180 | case AIO_WRITE: |
161 | err = os_seek_file(req->io_fd, req->offset); | 181 | err = os_seek_file(aio->fd, aio->offset); |
162 | if(err) | 182 | if(err) |
163 | goto out; | 183 | goto out; |
164 | 184 | ||
165 | err = os_write_file(req->io_fd, req->buf, req->len); | 185 | err = os_write_file(aio->fd, aio->data, aio->len); |
166 | break; | 186 | break; |
167 | case AIO_MMAP: | 187 | case AIO_MMAP: |
168 | err = os_seek_file(req->io_fd, req->offset); | 188 | err = os_seek_file(aio->fd, aio->offset); |
169 | if(err) | 189 | if(err) |
170 | goto out; | 190 | goto out; |
171 | 191 | ||
172 | err = os_read_file(req->io_fd, &c, sizeof(c)); | 192 | err = os_read_file(aio->fd, &c, sizeof(c)); |
173 | break; | 193 | break; |
174 | default: | 194 | default: |
175 | printk("do_not_aio - bad request type : %d\n", req->type); | 195 | printk("do_not_aio - bad request type : %d\n", aio->type); |
176 | err = -EINVAL; | 196 | err = -EINVAL; |
177 | break; | 197 | break; |
178 | } | 198 | } |
@@ -183,14 +203,14 @@ static int do_not_aio(struct aio_thread_req *req) | |||
183 | 203 | ||
184 | static int not_aio_thread(void *arg) | 204 | static int not_aio_thread(void *arg) |
185 | { | 205 | { |
186 | struct aio_thread_req req; | 206 | struct aio_context *aio; |
187 | struct aio_thread_reply reply; | 207 | struct aio_thread_reply reply; |
188 | int err; | 208 | int err; |
189 | 209 | ||
190 | signal(SIGWINCH, SIG_IGN); | 210 | signal(SIGWINCH, SIG_IGN); |
191 | while(1){ | 211 | while(1){ |
192 | err = os_read_file(aio_req_fd_r, &req, sizeof(req)); | 212 | err = os_read_file(aio_req_fd_r, &aio, sizeof(aio)); |
193 | if(err != sizeof(req)){ | 213 | if(err != sizeof(aio)){ |
194 | if(err < 0) | 214 | if(err < 0) |
195 | printk("not_aio_thread - read failed, " | 215 | printk("not_aio_thread - read failed, " |
196 | "fd = %d, err = %d\n", aio_req_fd_r, | 216 | "fd = %d, err = %d\n", aio_req_fd_r, |
@@ -201,17 +221,34 @@ static int not_aio_thread(void *arg) | |||
201 | } | 221 | } |
202 | continue; | 222 | continue; |
203 | } | 223 | } |
204 | err = do_not_aio(&req); | 224 | again: |
205 | reply = ((struct aio_thread_reply) { .data = req.aio, | 225 | err = do_not_aio(aio); |
206 | .err = err }); | 226 | |
207 | err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply)); | 227 | if(update_aio(aio, err)) |
228 | goto again; | ||
229 | |||
230 | reply = ((struct aio_thread_reply) { .data = aio, | ||
231 | .err = aio->len }); | ||
232 | err = os_write_file(aio->reply_fd, &reply, sizeof(reply)); | ||
208 | if(err != sizeof(reply)) | 233 | if(err != sizeof(reply)) |
209 | printk("not_aio_thread - write failed, fd = %d, " | 234 | printk("not_aio_thread - write failed, fd = %d, " |
210 | "err = %d\n", aio_req_fd_r, -err); | 235 | "err = %d\n", aio_req_fd_r, -err); |
211 | } | 236 | } |
212 | } | 237 | } |
213 | 238 | ||
239 | static int submit_aio_24(struct aio_context *aio) | ||
240 | { | ||
241 | int err; | ||
242 | |||
243 | err = os_write_file(aio_req_fd_w, &aio, sizeof(aio)); | ||
244 | if(err == sizeof(aio)) | ||
245 | err = 0; | ||
246 | |||
247 | return err; | ||
248 | } | ||
249 | |||
214 | static int aio_pid = -1; | 250 | static int aio_pid = -1; |
251 | static int (*submit_proc)(struct aio_context *aio); | ||
215 | 252 | ||
216 | static int init_aio_24(void) | 253 | static int init_aio_24(void) |
217 | { | 254 | { |
@@ -243,11 +280,33 @@ static int init_aio_24(void) | |||
243 | #endif | 280 | #endif |
244 | printk("2.6 host AIO support not used - falling back to I/O " | 281 | printk("2.6 host AIO support not used - falling back to I/O " |
245 | "thread\n"); | 282 | "thread\n"); |
283 | |||
284 | submit_proc = submit_aio_24; | ||
285 | |||
246 | return 0; | 286 | return 0; |
247 | } | 287 | } |
248 | 288 | ||
249 | #ifdef HAVE_AIO_ABI | 289 | #ifdef HAVE_AIO_ABI |
250 | #define DEFAULT_24_AIO 0 | 290 | #define DEFAULT_24_AIO 0 |
291 | static int submit_aio_26(struct aio_context *aio) | ||
292 | { | ||
293 | struct aio_thread_reply reply; | ||
294 | int err; | ||
295 | |||
296 | err = do_aio(ctx, aio); | ||
297 | if(err){ | ||
298 | reply = ((struct aio_thread_reply) { .data = aio, | ||
299 | .err = err }); | ||
300 | err = os_write_file(aio->reply_fd, &reply, sizeof(reply)); | ||
301 | if(err != sizeof(reply)) | ||
302 | printk("submit_aio_26 - write failed, " | ||
303 | "fd = %d, err = %d\n", aio->reply_fd, -err); | ||
304 | else err = 0; | ||
305 | } | ||
306 | |||
307 | return err; | ||
308 | } | ||
309 | |||
251 | static int init_aio_26(void) | 310 | static int init_aio_26(void) |
252 | { | 311 | { |
253 | unsigned long stack; | 312 | unsigned long stack; |
@@ -267,39 +326,22 @@ static int init_aio_26(void) | |||
267 | aio_pid = err; | 326 | aio_pid = err; |
268 | 327 | ||
269 | printk("Using 2.6 host AIO\n"); | 328 | printk("Using 2.6 host AIO\n"); |
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, | ||
274 | unsigned long long offset, struct aio_context *aio) | ||
275 | { | ||
276 | struct aio_thread_reply reply; | ||
277 | int err; | ||
278 | 329 | ||
279 | err = do_aio(ctx, type, io_fd, buf, len, offset, aio); | 330 | submit_proc = submit_aio_26; |
280 | if(err){ | ||
281 | reply = ((struct aio_thread_reply) { .data = aio, | ||
282 | .err = err }); | ||
283 | err = os_write_file(aio->reply_fd, &reply, sizeof(reply)); | ||
284 | if(err != sizeof(reply)) | ||
285 | printk("submit_aio_26 - write failed, " | ||
286 | "fd = %d, err = %d\n", aio->reply_fd, -err); | ||
287 | else err = 0; | ||
288 | } | ||
289 | 331 | ||
290 | return err; | 332 | return 0; |
291 | } | 333 | } |
292 | 334 | ||
293 | #else | 335 | #else |
294 | #define DEFAULT_24_AIO 1 | 336 | #define DEFAULT_24_AIO 1 |
295 | static int init_aio_26(void) | 337 | static int submit_aio_26(struct aio_context *aio) |
296 | { | 338 | { |
297 | return -ENOSYS; | 339 | return -ENOSYS; |
298 | } | 340 | } |
299 | 341 | ||
300 | static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, | 342 | static int init_aio_26(void) |
301 | unsigned long long offset, struct aio_context *aio) | ||
302 | { | 343 | { |
344 | submit_proc = submit_aio_26; | ||
303 | return -ENOSYS; | 345 | return -ENOSYS; |
304 | } | 346 | } |
305 | #endif | 347 | #endif |
@@ -366,33 +408,7 @@ static void exit_aio(void) | |||
366 | 408 | ||
367 | __uml_exitcall(exit_aio); | 409 | __uml_exitcall(exit_aio); |
368 | 410 | ||
369 | static int submit_aio_24(enum aio_type type, int io_fd, char *buf, int len, | 411 | int submit_aio(struct aio_context *aio) |
370 | unsigned long long offset, struct aio_context *aio) | ||
371 | { | 412 | { |
372 | struct aio_thread_req req = { .type = type, | 413 | return (*submit_proc)(aio); |
373 | .io_fd = io_fd, | ||
374 | .offset = offset, | ||
375 | .buf = buf, | ||
376 | .len = len, | ||
377 | .aio = aio, | ||
378 | }; | ||
379 | int err; | ||
380 | |||
381 | err = os_write_file(aio_req_fd_w, &req, sizeof(req)); | ||
382 | if(err == sizeof(req)) | ||
383 | err = 0; | ||
384 | |||
385 | return err; | ||
386 | } | ||
387 | |||
388 | int submit_aio(enum aio_type type, int io_fd, char *buf, int len, | ||
389 | unsigned long long offset, int reply_fd, | ||
390 | struct aio_context *aio) | ||
391 | { | ||
392 | aio->reply_fd = reply_fd; | ||
393 | if(aio_24) | ||
394 | return submit_aio_24(type, io_fd, buf, len, offset, aio); | ||
395 | else { | ||
396 | return submit_aio_26(type, io_fd, buf, len, offset, aio); | ||
397 | } | ||
398 | } | 414 | } |