uml: simplify helper stack handling
[deliverable/linux.git] / arch / um / os-Linux / aio.c
CommitLineData
75e5584c
JD
1/*
2 * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <unistd.h>
8#include <signal.h>
9#include <errno.h>
10#include <sched.h>
11#include <sys/syscall.h>
12#include "os.h"
75e5584c
JD
13#include "aio.h"
14#include "init.h"
15#include "user.h"
16#include "mode.h"
17
91acb21f 18struct aio_thread_req {
d50084a2
JD
19 enum aio_type type;
20 int io_fd;
21 unsigned long long offset;
22 char *buf;
23 int len;
24 struct aio_context *aio;
91acb21f
JD
25};
26
75e5584c
JD
27#if defined(HAVE_AIO_ABI)
28#include <linux/aio_abi.h>
29
30/* If we have the headers, we are going to build with AIO enabled.
31 * If we don't have aio in libc, we define the necessary stubs here.
32 */
33
34#if !defined(HAVE_AIO_LIBC)
35
36static long io_setup(int n, aio_context_t *ctxp)
37{
d50084a2 38 return syscall(__NR_io_setup, n, ctxp);
75e5584c
JD
39}
40
41static long io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp)
42{
d50084a2 43 return syscall(__NR_io_submit, ctx, nr, iocbpp);
75e5584c
JD
44}
45
46static long io_getevents(aio_context_t ctx_id, long min_nr, long nr,
d50084a2 47 struct io_event *events, struct timespec *timeout)
75e5584c 48{
d50084a2 49 return syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout);
75e5584c
JD
50}
51
52#endif
53
54/* The AIO_MMAP cases force the mmapped page into memory here
55 * rather than in whatever place first touches the data. I used
56 * to do this by touching the page, but that's delicate because
57 * gcc is prone to optimizing that away. So, what's done here
58 * is we read from the descriptor from which the page was
59 * mapped. The caller is required to pass an offset which is
60 * inside the page that was mapped. Thus, when the read
61 * returns, we know that the page is in the page cache, and
62 * that it now backs the mmapped area.
63 */
64
91acb21f 65static int do_aio(aio_context_t ctx, enum aio_type type, int fd, char *buf,
d50084a2 66 int len, unsigned long long offset, struct aio_context *aio)
75e5584c 67{
d50084a2
JD
68 struct iocb iocb, *iocbp = &iocb;
69 char c;
70 int err;
71
72 iocb = ((struct iocb) { .aio_data = (unsigned long) aio,
73 .aio_reqprio = 0,
74 .aio_fildes = fd,
75 .aio_buf = (unsigned long) buf,
76 .aio_nbytes = len,
77 .aio_offset = offset,
78 .aio_reserved1 = 0,
79 .aio_reserved2 = 0,
80 .aio_reserved3 = 0 });
81
82 switch(type){
83 case AIO_READ:
84 iocb.aio_lio_opcode = IOCB_CMD_PREAD;
85 err = io_submit(ctx, 1, &iocbp);
86 break;
87 case AIO_WRITE:
88 iocb.aio_lio_opcode = IOCB_CMD_PWRITE;
89 err = io_submit(ctx, 1, &iocbp);
90 break;
91 case AIO_MMAP:
92 iocb.aio_lio_opcode = IOCB_CMD_PREAD;
93 iocb.aio_buf = (unsigned long) &c;
94 iocb.aio_nbytes = sizeof(c);
95 err = io_submit(ctx, 1, &iocbp);
96 break;
97 default:
98 printk("Bogus op in do_aio - %d\n", type);
99 err = -EINVAL;
100 break;
101 }
102
103 if(err > 0)
104 err = 0;
2867ace6
JD
105 else
106 err = -errno;
75e5584c 107
d50084a2 108 return err;
75e5584c
JD
109}
110
9683da91 111/* Initialized in an initcall and unchanged thereafter */
75e5584c
JD
112static aio_context_t ctx = 0;
113
114static int aio_thread(void *arg)
115{
d50084a2
JD
116 struct aio_thread_reply reply;
117 struct io_event event;
118 int err, n, reply_fd;
119
120 signal(SIGWINCH, SIG_IGN);
121
122 while(1){
123 n = io_getevents(ctx, 1, 1, &event, NULL);
124 if(n < 0){
125 if(errno == EINTR)
126 continue;
127 printk("aio_thread - io_getevents failed, "
128 "errno = %d\n", errno);
129 }
130 else {
131 reply = ((struct aio_thread_reply)
132 { .data = (void *) (long) event.data,
133 .err = event.res });
91acb21f 134 reply_fd = ((struct aio_context *) reply.data)->reply_fd;
a61f334f 135 err = write(reply_fd, &reply, sizeof(reply));
d50084a2 136 if(err != sizeof(reply))
91acb21f 137 printk("aio_thread - write failed, fd = %d, "
a61f334f 138 "err = %d\n", reply_fd, errno);
d50084a2
JD
139 }
140 }
141 return 0;
75e5584c
JD
142}
143
144#endif
145
91acb21f 146static int do_not_aio(struct aio_thread_req *req)
75e5584c 147{
d50084a2 148 char c;
ef0470c0 149 unsigned long long actual;
a61f334f 150 int n;
d50084a2 151
ef0470c0
JD
152 actual = lseek64(req->io_fd, req->offset, SEEK_SET);
153 if(actual != req->offset)
154 return -errno;
155
d50084a2
JD
156 switch(req->type){
157 case AIO_READ:
a61f334f 158 n = read(req->io_fd, req->buf, req->len);
d50084a2
JD
159 break;
160 case AIO_WRITE:
a61f334f 161 n = write(req->io_fd, req->buf, req->len);
d50084a2
JD
162 break;
163 case AIO_MMAP:
a61f334f 164 n = read(req->io_fd, &c, sizeof(c));
d50084a2
JD
165 break;
166 default:
167 printk("do_not_aio - bad request type : %d\n", req->type);
a61f334f 168 return -EINVAL;
d50084a2
JD
169 }
170
a61f334f
JD
171 if(n < 0)
172 return -errno;
173 return 0;
75e5584c
JD
174}
175
9683da91
JD
176/* These are initialized in initcalls and not changed */
177static int aio_req_fd_r = -1;
178static int aio_req_fd_w = -1;
179static int aio_pid = -1;
c4399016 180static unsigned long aio_stack;
9683da91 181
75e5584c
JD
182static int not_aio_thread(void *arg)
183{
d50084a2
JD
184 struct aio_thread_req req;
185 struct aio_thread_reply reply;
186 int err;
187
188 signal(SIGWINCH, SIG_IGN);
189 while(1){
a61f334f 190 err = read(aio_req_fd_r, &req, sizeof(req));
d50084a2
JD
191 if(err != sizeof(req)){
192 if(err < 0)
193 printk("not_aio_thread - read failed, "
194 "fd = %d, err = %d\n", aio_req_fd_r,
a61f334f 195 errno);
d50084a2
JD
196 else {
197 printk("not_aio_thread - short read, fd = %d, "
198 "length = %d\n", aio_req_fd_r, err);
199 }
200 continue;
201 }
202 err = do_not_aio(&req);
203 reply = ((struct aio_thread_reply) { .data = req.aio,
ef0470c0 204 .err = err });
a61f334f 205 err = write(req.aio->reply_fd, &reply, sizeof(reply));
d50084a2
JD
206 if(err != sizeof(reply))
207 printk("not_aio_thread - write failed, fd = %d, "
a61f334f 208 "err = %d\n", req.aio->reply_fd, errno);
d50084a2 209 }
1b57e9c2
JD
210
211 return 0;
75e5584c
JD
212}
213
75e5584c
JD
214static int init_aio_24(void)
215{
d50084a2
JD
216 int fds[2], err;
217
218 err = os_pipe(fds, 1, 1);
219 if(err)
220 goto out;
221
222 aio_req_fd_w = fds[0];
223 aio_req_fd_r = fds[1];
8603ec81
JD
224
225 err = os_set_fd_block(aio_req_fd_w, 0);
226 if(err)
227 goto out_close_pipe;
228
d50084a2 229 err = run_helper_thread(not_aio_thread, NULL,
c4399016 230 CLONE_FILES | CLONE_VM | SIGCHLD, &aio_stack);
d50084a2
JD
231 if(err < 0)
232 goto out_close_pipe;
233
234 aio_pid = err;
235 goto out;
236
237out_close_pipe:
238 os_close_file(fds[0]);
239 os_close_file(fds[1]);
240 aio_req_fd_w = -1;
241 aio_req_fd_r = -1;
242out:
75e5584c
JD
243#ifndef HAVE_AIO_ABI
244 printk("/usr/include/linux/aio_abi.h not present during build\n");
245#endif
246 printk("2.6 host AIO support not used - falling back to I/O "
247 "thread\n");
d50084a2 248 return 0;
75e5584c
JD
249}
250
251#ifdef HAVE_AIO_ABI
252#define DEFAULT_24_AIO 0
253static int init_aio_26(void)
254{
d50084a2 255 int err;
75e5584c 256
d50084a2 257 if(io_setup(256, &ctx)){
b4fd310e 258 err = -errno;
d50084a2
JD
259 printk("aio_thread failed to initialize context, err = %d\n",
260 errno);
261 return err;
262 }
75e5584c 263
d50084a2 264 err = run_helper_thread(aio_thread, NULL,
c4399016 265 CLONE_FILES | CLONE_VM | SIGCHLD, &aio_stack);
d50084a2
JD
266 if(err < 0)
267 return err;
75e5584c 268
d50084a2 269 aio_pid = err;
75e5584c
JD
270
271 printk("Using 2.6 host AIO\n");
d50084a2 272 return 0;
91acb21f
JD
273}
274
275static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len,
276 unsigned long long offset, struct aio_context *aio)
277{
d50084a2
JD
278 struct aio_thread_reply reply;
279 int err;
280
281 err = do_aio(ctx, type, io_fd, buf, len, offset, aio);
282 if(err){
283 reply = ((struct aio_thread_reply) { .data = aio,
284 .err = err });
a61f334f
JD
285 err = write(aio->reply_fd, &reply, sizeof(reply));
286 if(err != sizeof(reply)){
287 err = -errno;
d50084a2
JD
288 printk("submit_aio_26 - write failed, "
289 "fd = %d, err = %d\n", aio->reply_fd, -err);
a61f334f 290 }
d50084a2
JD
291 else err = 0;
292 }
293
294 return err;
75e5584c
JD
295}
296
297#else
298#define DEFAULT_24_AIO 1
91acb21f 299static int init_aio_26(void)
75e5584c 300{
d50084a2 301 return -ENOSYS;
75e5584c
JD
302}
303
91acb21f
JD
304static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len,
305 unsigned long long offset, struct aio_context *aio)
75e5584c 306{
d50084a2 307 return -ENOSYS;
75e5584c
JD
308}
309#endif
310
9683da91 311/* Initialized in an initcall and unchanged thereafter */
75e5584c
JD
312static int aio_24 = DEFAULT_24_AIO;
313
314static int __init set_aio_24(char *name, int *add)
315{
d50084a2
JD
316 aio_24 = 1;
317 return 0;
75e5584c
JD
318}
319
320__uml_setup("aio=2.4", set_aio_24,
321"aio=2.4\n"
322" This is used to force UML to use 2.4-style AIO even when 2.6 AIO is\n"
323" available. 2.4 AIO is a single thread that handles one request at a\n"
324" time, synchronously. 2.6 AIO is a thread which uses the 2.6 AIO \n"
325" interface to handle an arbitrary number of pending requests. 2.6 AIO \n"
326" is not available in tt mode, on 2.4 hosts, or when UML is built with\n"
327" /usr/include/linux/aio_abi.h not available. Many distributions don't\n"
328" include aio_abi.h, so you will need to copy it from a kernel tree to\n"
329" your /usr/include/linux in order to build an AIO-capable UML\n\n"
330);
331
332static int init_aio(void)
333{
d50084a2
JD
334 int err;
335
336 CHOOSE_MODE(({ if(!aio_24){
337 printk("Disabling 2.6 AIO in tt mode\n");
338 aio_24 = 1;
339 } }), (void) 0);
340
341 if(!aio_24){
342 err = init_aio_26();
343 if(err && (errno == ENOSYS)){
344 printk("2.6 AIO not supported on the host - "
345 "reverting to 2.4 AIO\n");
346 aio_24 = 1;
347 }
348 else return err;
349 }
350
351 if(aio_24)
352 return init_aio_24();
353
354 return 0;
75e5584c
JD
355}
356
357/* The reason for the __initcall/__uml_exitcall asymmetry is that init_aio
358 * needs to be called when the kernel is running because it calls run_helper,
359 * which needs get_free_page. exit_aio is a __uml_exitcall because the generic
360 * kernel does not run __exitcalls on shutdown, and can't because many of them
361 * break when called outside of module unloading.
362 */
363__initcall(init_aio);
364
365static void exit_aio(void)
366{
c4399016 367 if (aio_pid != -1) {
d50084a2 368 os_kill_process(aio_pid, 1);
c4399016
JD
369 free_stack(aio_stack, 0);
370 }
75e5584c
JD
371}
372
373__uml_exitcall(exit_aio);
374
91acb21f
JD
375static int submit_aio_24(enum aio_type type, int io_fd, char *buf, int len,
376 unsigned long long offset, struct aio_context *aio)
75e5584c 377{
d50084a2
JD
378 struct aio_thread_req req = { .type = type,
379 .io_fd = io_fd,
380 .offset = offset,
381 .buf = buf,
382 .len = len,
383 .aio = aio,
384 };
385 int err;
386
a61f334f 387 err = write(aio_req_fd_w, &req, sizeof(req));
d50084a2
JD
388 if(err == sizeof(req))
389 err = 0;
a61f334f 390 else err = -errno;
d50084a2
JD
391
392 return err;
91acb21f
JD
393}
394
395int submit_aio(enum aio_type type, int io_fd, char *buf, int len,
d50084a2
JD
396 unsigned long long offset, int reply_fd,
397 struct aio_context *aio)
91acb21f 398{
d50084a2
JD
399 aio->reply_fd = reply_fd;
400 if(aio_24)
401 return submit_aio_24(type, io_fd, buf, len, offset, aio);
402 else {
403 return submit_aio_26(type, io_fd, buf, len, offset, aio);
404 }
75e5584c 405}
This page took 0.216173 seconds and 5 git commands to generate.