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