[PATCH] Move td_verror() into io_ops->queue() hook
[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                         break;
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                         if (fsync(io_u->file->fd) < 0)
105                                 ret = errno;
106                         else {
107                                 ret = 1;
108                                 ld->sync_io_u = io_u;
109                         }
110                         break;
111                 } else
112                         break;
113         } while (1);
114
115         if (ret <= 0) {
116                 io_u->resid = io_u->xfer_buflen;
117                 io_u->error = -ret;
118                 td_verror(td, io_u->error);
119                 return 1;
120         }
121
122         return 0;
123 }
124
125 static int fio_libaio_cancel(struct thread_data *td, struct io_u *io_u)
126 {
127         struct libaio_data *ld = td->io_ops->data;
128
129         return io_cancel(ld->aio_ctx, &io_u->iocb, ld->aio_events);
130 }
131
132 static void fio_libaio_cleanup(struct thread_data *td)
133 {
134         struct libaio_data *ld = td->io_ops->data;
135
136         if (ld) {
137                 io_destroy(ld->aio_ctx);
138                 if (ld->aio_events)
139                         free(ld->aio_events);
140
141                 free(ld);
142                 td->io_ops->data = NULL;
143         }
144 }
145
146 static int fio_libaio_init(struct thread_data *td)
147 {
148         struct libaio_data *ld = malloc(sizeof(*ld));
149
150         memset(ld, 0, sizeof(*ld));
151         if (io_queue_init(td->iodepth, &ld->aio_ctx)) {
152                 td_verror(td, errno);
153                 free(ld);
154                 return 1;
155         }
156
157         ld->aio_events = malloc(td->iodepth * sizeof(struct io_event));
158         memset(ld->aio_events, 0, td->iodepth * sizeof(struct io_event));
159         td->io_ops->data = ld;
160         return 0;
161 }
162
163 static struct ioengine_ops ioengine = {
164         .name           = "libaio",
165         .version        = FIO_IOOPS_VERSION,
166         .init           = fio_libaio_init,
167         .prep           = fio_libaio_prep,
168         .queue          = fio_libaio_queue,
169         .cancel         = fio_libaio_cancel,
170         .getevents      = fio_libaio_getevents,
171         .event          = fio_libaio_event,
172         .cleanup        = fio_libaio_cleanup,
173 };
174
175 #else /* FIO_HAVE_LIBAIO */
176
177 /*
178  * When we have a proper configure system in place, we simply wont build
179  * and install this io engine. For now install a crippled version that
180  * just complains and fails to load.
181  */
182 static int fio_libaio_init(struct thread_data fio_unused *td)
183 {
184         fprintf(stderr, "fio: libaio not available\n");
185         return 1;
186 }
187
188 static struct ioengine_ops ioengine = {
189         .name           = "libaio",
190         .version        = FIO_IOOPS_VERSION,
191         .init           = fio_libaio_init,
192 };
193
194 #endif
195
196 static void fio_init fio_libaio_register(void)
197 {
198         register_ioengine(&ioengine);
199 }
200
201 static void fio_exit fio_libaio_unregister(void)
202 {
203         unregister_ioengine(&ioengine);
204 }