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