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