]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - arch/um/os-Linux/aio.c
uml: convert libc layer to call read and write
[mirror_ubuntu-focal-kernel.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;
180
75e5584c
JD
181static int not_aio_thread(void *arg)
182{
d50084a2
JD
183 struct aio_thread_req req;
184 struct aio_thread_reply reply;
185 int err;
186
187 signal(SIGWINCH, SIG_IGN);
188 while(1){
a61f334f 189 err = read(aio_req_fd_r, &req, sizeof(req));
d50084a2
JD
190 if(err != sizeof(req)){
191 if(err < 0)
192 printk("not_aio_thread - read failed, "
193 "fd = %d, err = %d\n", aio_req_fd_r,
a61f334f 194 errno);
d50084a2
JD
195 else {
196 printk("not_aio_thread - short read, fd = %d, "
197 "length = %d\n", aio_req_fd_r, err);
198 }
199 continue;
200 }
201 err = do_not_aio(&req);
202 reply = ((struct aio_thread_reply) { .data = req.aio,
ef0470c0 203 .err = err });
a61f334f 204 err = write(req.aio->reply_fd, &reply, sizeof(reply));
d50084a2
JD
205 if(err != sizeof(reply))
206 printk("not_aio_thread - write failed, fd = %d, "
a61f334f 207 "err = %d\n", req.aio->reply_fd, errno);
d50084a2 208 }
1b57e9c2
JD
209
210 return 0;
75e5584c
JD
211}
212
75e5584c
JD
213static int init_aio_24(void)
214{
d50084a2
JD
215 unsigned long stack;
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];
224 err = run_helper_thread(not_aio_thread, NULL,
225 CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
226 if(err < 0)
227 goto out_close_pipe;
228
229 aio_pid = err;
230 goto out;
231
232out_close_pipe:
233 os_close_file(fds[0]);
234 os_close_file(fds[1]);
235 aio_req_fd_w = -1;
236 aio_req_fd_r = -1;
237out:
75e5584c
JD
238#ifndef HAVE_AIO_ABI
239 printk("/usr/include/linux/aio_abi.h not present during build\n");
240#endif
241 printk("2.6 host AIO support not used - falling back to I/O "
242 "thread\n");
d50084a2 243 return 0;
75e5584c
JD
244}
245
246#ifdef HAVE_AIO_ABI
247#define DEFAULT_24_AIO 0
248static int init_aio_26(void)
249{
d50084a2
JD
250 unsigned long stack;
251 int err;
75e5584c 252
d50084a2 253 if(io_setup(256, &ctx)){
b4fd310e 254 err = -errno;
d50084a2
JD
255 printk("aio_thread failed to initialize context, err = %d\n",
256 errno);
257 return err;
258 }
75e5584c 259
d50084a2
JD
260 err = run_helper_thread(aio_thread, NULL,
261 CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
262 if(err < 0)
263 return err;
75e5584c 264
d50084a2 265 aio_pid = err;
75e5584c
JD
266
267 printk("Using 2.6 host AIO\n");
d50084a2 268 return 0;
91acb21f
JD
269}
270
271static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len,
272 unsigned long long offset, struct aio_context *aio)
273{
d50084a2
JD
274 struct aio_thread_reply reply;
275 int err;
276
277 err = do_aio(ctx, type, io_fd, buf, len, offset, aio);
278 if(err){
279 reply = ((struct aio_thread_reply) { .data = aio,
280 .err = err });
a61f334f
JD
281 err = write(aio->reply_fd, &reply, sizeof(reply));
282 if(err != sizeof(reply)){
283 err = -errno;
d50084a2
JD
284 printk("submit_aio_26 - write failed, "
285 "fd = %d, err = %d\n", aio->reply_fd, -err);
a61f334f 286 }
d50084a2
JD
287 else err = 0;
288 }
289
290 return err;
75e5584c
JD
291}
292
293#else
294#define DEFAULT_24_AIO 1
91acb21f 295static int init_aio_26(void)
75e5584c 296{
d50084a2 297 return -ENOSYS;
75e5584c
JD
298}
299
91acb21f
JD
300static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len,
301 unsigned long long offset, struct aio_context *aio)
75e5584c 302{
d50084a2 303 return -ENOSYS;
75e5584c
JD
304}
305#endif
306
9683da91 307/* Initialized in an initcall and unchanged thereafter */
75e5584c
JD
308static int aio_24 = DEFAULT_24_AIO;
309
310static int __init set_aio_24(char *name, int *add)
311{
d50084a2
JD
312 aio_24 = 1;
313 return 0;
75e5584c
JD
314}
315
316__uml_setup("aio=2.4", set_aio_24,
317"aio=2.4\n"
318" This is used to force UML to use 2.4-style AIO even when 2.6 AIO is\n"
319" available. 2.4 AIO is a single thread that handles one request at a\n"
320" time, synchronously. 2.6 AIO is a thread which uses the 2.6 AIO \n"
321" interface to handle an arbitrary number of pending requests. 2.6 AIO \n"
322" is not available in tt mode, on 2.4 hosts, or when UML is built with\n"
323" /usr/include/linux/aio_abi.h not available. Many distributions don't\n"
324" include aio_abi.h, so you will need to copy it from a kernel tree to\n"
325" your /usr/include/linux in order to build an AIO-capable UML\n\n"
326);
327
328static int init_aio(void)
329{
d50084a2
JD
330 int err;
331
332 CHOOSE_MODE(({ if(!aio_24){
333 printk("Disabling 2.6 AIO in tt mode\n");
334 aio_24 = 1;
335 } }), (void) 0);
336
337 if(!aio_24){
338 err = init_aio_26();
339 if(err && (errno == ENOSYS)){
340 printk("2.6 AIO not supported on the host - "
341 "reverting to 2.4 AIO\n");
342 aio_24 = 1;
343 }
344 else return err;
345 }
346
347 if(aio_24)
348 return init_aio_24();
349
350 return 0;
75e5584c
JD
351}
352
353/* The reason for the __initcall/__uml_exitcall asymmetry is that init_aio
354 * needs to be called when the kernel is running because it calls run_helper,
355 * which needs get_free_page. exit_aio is a __uml_exitcall because the generic
356 * kernel does not run __exitcalls on shutdown, and can't because many of them
357 * break when called outside of module unloading.
358 */
359__initcall(init_aio);
360
361static void exit_aio(void)
362{
d50084a2
JD
363 if(aio_pid != -1)
364 os_kill_process(aio_pid, 1);
75e5584c
JD
365}
366
367__uml_exitcall(exit_aio);
368
91acb21f
JD
369static int submit_aio_24(enum aio_type type, int io_fd, char *buf, int len,
370 unsigned long long offset, struct aio_context *aio)
75e5584c 371{
d50084a2
JD
372 struct aio_thread_req req = { .type = type,
373 .io_fd = io_fd,
374 .offset = offset,
375 .buf = buf,
376 .len = len,
377 .aio = aio,
378 };
379 int err;
380
a61f334f 381 err = write(aio_req_fd_w, &req, sizeof(req));
d50084a2
JD
382 if(err == sizeof(req))
383 err = 0;
a61f334f 384 else err = -errno;
d50084a2
JD
385
386 return err;
91acb21f
JD
387}
388
389int submit_aio(enum aio_type type, int io_fd, char *buf, int len,
d50084a2
JD
390 unsigned long long offset, int reply_fd,
391 struct aio_context *aio)
91acb21f 392{
d50084a2
JD
393 aio->reply_fd = reply_fd;
394 if(aio_24)
395 return submit_aio_24(type, io_fd, buf, len, offset, aio);
396 else {
397 return submit_aio_26(type, io_fd, buf, len, offset, aio);
398 }
75e5584c 399}