[PATCH] libaio engine: fake work-around for sync issue
[fio.git] / engines / libaio.c
1 /*
2  * native linux aio io engine
3  *
4  */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <assert.h>
10
11 #include "../fio.h"
12 #include "../os.h"
13
14 #ifdef FIO_HAVE_LIBAIO
15
16 #define ev_to_iou(ev)   (struct io_u *) ((unsigned long) (ev)->obj)
17
18 struct libaio_data {
19         io_context_t aio_ctx;
20         struct io_event *aio_events;
21         struct io_u *sync_io_u;
22 };
23
24 static int fio_libaio_prep(struct thread_data fio_unused *td, struct io_u *io_u)
25 {
26         struct fio_file *f = io_u->file;
27
28         if (io_u->ddir == DDIR_READ)
29                 io_prep_pread(&io_u->iocb, f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset);
30         else if (io_u->ddir == DDIR_WRITE)
31                 io_prep_pwrite(&io_u->iocb, f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset);
32         else if (io_u->ddir == DDIR_SYNC)
33                 io_prep_fsync(&io_u->iocb, f->fd);
34         else
35                 return 1;
36
37         return 0;
38 }
39
40 static struct io_u *fio_libaio_event(struct thread_data *td, int event)
41 {
42         struct libaio_data *ld = td->io_ops->data;
43
44         if (ld->sync_io_u) {
45                 struct io_u *ret = ld->sync_io_u;
46
47                 ld->sync_io_u = NULL;
48                 return ret;
49         }
50
51         return ev_to_iou(ld->aio_events + event);
52 }
53
54 static int fio_libaio_getevents(struct thread_data *td, int min, int max,
55                                 struct timespec *t)
56 {
57         struct libaio_data *ld = td->io_ops->data;
58         long r;
59
60         if (ld->sync_io_u)
61                 return 1;
62
63         do {
64                 r = io_getevents(ld->aio_ctx, min, max, ld->aio_events, t);
65                 if (r >= min)
66                         break;
67                 else if (r == -EAGAIN) {
68                         usleep(100);
69                         continue;
70                 } else if (r == -EINTR)
71                         continue;
72                 else if (r != 0)
73                         break;
74         } while (1);
75
76         if (r < 0)
77                 r = -r;
78
79         return (int) r;
80 }
81
82 static int fio_libaio_queue(struct thread_data *td, struct io_u *io_u)
83 {
84         struct libaio_data *ld = td->io_ops->data;
85         struct iocb *iocb = &io_u->iocb;
86         long ret;
87
88         do {
89                 ret = io_submit(ld->aio_ctx, 1, &iocb);
90                 if (ret == 1)
91                         return 0;
92                 else if (ret == -EAGAIN || !ret)
93                         usleep(100);
94                 else if (ret == -EINTR)
95                         continue;
96                 else if (ret == -EINVAL && io_u->ddir == DDIR_SYNC) {
97                         /*
98                          * the async fsync doesn't currently seem to be
99                          * supported, so just fsync if we fail with EINVAL
100                          * for a sync. since buffered io is also sync
101                          * with libaio (still), we don't have pending
102                          * requests to flush first.
103                          */
104                         ret = fsync(io_u->file->fd);
105                         ld->sync_io_u = io_u;
106                         break;
107                 } else
108                         break;
109         } while (1);
110
111         if (ret <= 0) {
112                 io_u->resid = io_u->xfer_buflen;
113                 io_u->error = -ret;
114                 return 1;
115         }
116
117         return 0;
118 }
119
120 static int fio_libaio_cancel(struct thread_data *td, struct io_u *io_u)
121 {
122         struct libaio_data *ld = td->io_ops->data;
123
124         return io_cancel(ld->aio_ctx, &io_u->iocb, ld->aio_events);
125 }
126
127 static void fio_libaio_cleanup(struct thread_data *td)
128 {
129         struct libaio_data *ld = td->io_ops->data;
130
131         if (ld) {
132                 io_destroy(ld->aio_ctx);
133                 if (ld->aio_events)
134                         free(ld->aio_events);
135
136                 free(ld);
137                 td->io_ops->data = NULL;
138         }
139 }
140
141 static int fio_libaio_init(struct thread_data *td)
142 {
143         struct libaio_data *ld = malloc(sizeof(*ld));
144
145         memset(ld, 0, sizeof(*ld));
146         if (io_queue_init(td->iodepth, &ld->aio_ctx)) {
147                 td_verror(td, errno);
148                 free(ld);
149                 return 1;
150         }
151
152         ld->aio_events = malloc(td->iodepth * sizeof(struct io_event));
153         memset(ld->aio_events, 0, td->iodepth * sizeof(struct io_event));
154         td->io_ops->data = ld;
155         return 0;
156 }
157
158 static struct ioengine_ops ioengine = {
159         .name           = "libaio",
160         .version        = FIO_IOOPS_VERSION,
161         .init           = fio_libaio_init,
162         .prep           = fio_libaio_prep,
163         .queue          = fio_libaio_queue,
164         .cancel         = fio_libaio_cancel,
165         .getevents      = fio_libaio_getevents,
166         .event          = fio_libaio_event,
167         .cleanup        = fio_libaio_cleanup,
168 };
169
170 #else /* FIO_HAVE_LIBAIO */
171
172 /*
173  * When we have a proper configure system in place, we simply wont build
174  * and install this io engine. For now install a crippled version that
175  * just complains and fails to load.
176  */
177 static int fio_libaio_init(struct thread_data fio_unused *td)
178 {
179         fprintf(stderr, "fio: libaio not available\n");
180         return 1;
181 }
182
183 static struct ioengine_ops ioengine = {
184         .name           = "libaio",
185         .version        = FIO_IOOPS_VERSION,
186         .init           = fio_libaio_init,
187 };
188
189 #endif
190
191 static void fio_init fio_libaio_register(void)
192 {
193         register_ioengine(&ioengine);
194 }
195
196 static void fio_exit fio_libaio_unregister(void)
197 {
198         unregister_ioengine(&ioengine);
199 }