[PATCH] Missing memset and free-on-error in io engines
[fio.git] / engines / fio-engine-posixaio.c
CommitLineData
2866c82d
JA
1/*
2 * posix 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#include "fio.h"
11#include "os.h"
12
34cfcdaf
JA
13#ifdef FIO_HAVE_POSIXAIO
14
2866c82d
JA
15struct posixaio_data {
16 struct io_u **aio_events;
17};
18
19static int fill_timespec(struct timespec *ts)
20{
21#ifdef _POSIX_TIMERS
22 if (!clock_gettime(CLOCK_MONOTONIC, ts))
23 return 0;
24
25 perror("clock_gettime");
26#endif
27 return 1;
28}
29
30static unsigned long long ts_utime_since_now(struct timespec *t)
31{
32 long long sec, nsec;
33 struct timespec now;
34
35 if (fill_timespec(&now))
36 return 0;
37
38 sec = now.tv_sec - t->tv_sec;
39 nsec = now.tv_nsec - t->tv_nsec;
40 if (sec > 0 && nsec < 0) {
41 sec--;
42 nsec += 1000000000;
43 }
44
45 sec *= 1000000;
46 nsec /= 1000;
47 return sec + nsec;
48}
49
7a16dd02
JA
50static int fio_posixaio_cancel(struct thread_data fio_unused *td,
51 struct io_u *io_u)
2866c82d 52{
53cdc686
JA
53 struct fio_file *f = io_u->file;
54 int r = aio_cancel(f->fd, &io_u->aiocb);
2866c82d
JA
55
56 if (r == 1 || r == AIO_CANCELED)
57 return 0;
58
59 return 1;
60}
61
7a16dd02
JA
62static int fio_posixaio_prep(struct thread_data fio_unused *td,
63 struct io_u *io_u)
2866c82d
JA
64{
65 struct aiocb *aiocb = &io_u->aiocb;
53cdc686 66 struct fio_file *f = io_u->file;
2866c82d 67
53cdc686 68 aiocb->aio_fildes = f->fd;
2866c82d
JA
69 aiocb->aio_buf = io_u->buf;
70 aiocb->aio_nbytes = io_u->buflen;
71 aiocb->aio_offset = io_u->offset;
72
73 io_u->seen = 0;
74 return 0;
75}
76
77static int fio_posixaio_getevents(struct thread_data *td, int min, int max,
78 struct timespec *t)
79{
80 struct posixaio_data *pd = td->io_ops->data;
81 struct list_head *entry;
82 struct timespec start;
83 int r, have_timeout = 0;
84
85 if (t && !fill_timespec(&start))
86 have_timeout = 1;
87
88 r = 0;
89restart:
90 list_for_each(entry, &td->io_u_busylist) {
91 struct io_u *io_u = list_entry(entry, struct io_u, list);
92 int err;
93
94 if (io_u->seen)
95 continue;
96
97 err = aio_error(&io_u->aiocb);
98 switch (err) {
99 default:
100 io_u->error = err;
101 case ECANCELED:
102 case 0:
103 pd->aio_events[r++] = io_u;
104 io_u->seen = 1;
105 break;
106 case EINPROGRESS:
107 break;
108 }
109
110 if (r >= max)
111 break;
112 }
113
114 if (r >= min)
115 return r;
116
117 if (have_timeout) {
118 unsigned long long usec;
119
120 usec = (t->tv_sec * 1000000) + (t->tv_nsec / 1000);
121 if (ts_utime_since_now(&start) > usec)
122 return r;
123 }
124
125 /*
126 * hrmpf, we need to wait for more. we should use aio_suspend, for
127 * now just sleep a little and recheck status of busy-and-not-seen
128 */
129 usleep(1000);
130 goto restart;
131}
132
133static struct io_u *fio_posixaio_event(struct thread_data *td, int event)
134{
135 struct posixaio_data *pd = td->io_ops->data;
136
137 return pd->aio_events[event];
138}
139
140static int fio_posixaio_queue(struct thread_data fio_unused *td,
141 struct io_u *io_u)
142{
143 struct aiocb *aiocb = &io_u->aiocb;
144 int ret;
145
146 if (io_u->ddir == DDIR_READ)
147 ret = aio_read(aiocb);
87dc1ab1 148 else if (io_u->ddir == DDIR_WRITE)
2866c82d 149 ret = aio_write(aiocb);
87dc1ab1
JA
150 else
151 ret = aio_fsync(O_SYNC, aiocb);
2866c82d
JA
152
153 if (ret)
154 io_u->error = errno;
155
156 return io_u->error;
157}
158
159static void fio_posixaio_cleanup(struct thread_data *td)
160{
161 struct posixaio_data *pd = td->io_ops->data;
162
163 if (pd) {
164 free(pd->aio_events);
165 free(pd);
166 td->io_ops->data = NULL;
167 }
168}
169
170static int fio_posixaio_init(struct thread_data *td)
171{
172 struct posixaio_data *pd = malloc(sizeof(*pd));
173
cb781c75 174 memset(pd, 0, sizeof(*pd));
2866c82d 175 pd->aio_events = malloc(td->iodepth * sizeof(struct io_u *));
cb781c75 176 memset(pd->aio_events, 0, td->iodepth * sizeof(struct io_u *));
2866c82d
JA
177
178 td->io_ops->data = pd;
179 return 0;
180}
181
182struct ioengine_ops ioengine = {
183 .name = "posixaio",
184 .version = FIO_IOOPS_VERSION,
185 .init = fio_posixaio_init,
186 .prep = fio_posixaio_prep,
187 .queue = fio_posixaio_queue,
188 .cancel = fio_posixaio_cancel,
189 .getevents = fio_posixaio_getevents,
190 .event = fio_posixaio_event,
191 .cleanup = fio_posixaio_cleanup,
2866c82d 192};
34cfcdaf
JA
193
194#else /* FIO_HAVE_POSIXAIO */
195
196/*
197 * When we have a proper configure system in place, we simply wont build
198 * and install this io engine. For now install a crippled version that
199 * just complains and fails to load.
200 */
201static int fio_posixaio_init(struct thread_data fio_unused *td)
202{
203 fprintf(stderr, "fio: posixaio not available\n");
204 return 1;
205}
206
207struct ioengine_ops ioengine = {
208 .name = "posixaio",
209 .version = FIO_IOOPS_VERSION,
210 .init = fio_posixaio_init,
211};
212
213#endif