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