Commit | Line | Data |
---|---|---|
f5087211 JA |
1 | #include <stdio.h> |
2 | #include <stdlib.h> | |
3 | #include <unistd.h> | |
4 | #include <errno.h> | |
5 | #include "fio.h" | |
6 | #include "os.h" | |
7 | ||
8 | #ifdef FIO_HAVE_LIBAIO | |
9 | ||
10 | #define ev_to_iou(ev) (struct io_u *) ((unsigned long) (ev)->obj) | |
11 | ||
12 | struct libaio_data { | |
13 | io_context_t aio_ctx; | |
14 | struct io_event *aio_events; | |
15 | }; | |
16 | ||
17 | static void fio_libaio_io_prep(struct thread_data *td, struct io_u *io_u, | |
18 | int read) | |
19 | { | |
20 | if (read) | |
21 | io_prep_pread(&io_u->iocb, td->fd, io_u->buf, io_u->buflen, io_u->offset); | |
22 | else | |
23 | io_prep_pwrite(&io_u->iocb, td->fd, io_u->buf, io_u->buflen, io_u->offset); | |
24 | } | |
25 | ||
26 | static struct io_u *fio_libaio_event(struct thread_data *td, int event) | |
27 | { | |
28 | struct libaio_data *ld = td->aio_data; | |
29 | ||
30 | return ev_to_iou(ld->aio_events + event); | |
31 | } | |
32 | ||
33 | static int fio_libaio_getevents(struct thread_data *td, int min, int max, | |
34 | struct timespec *t) | |
35 | { | |
36 | struct libaio_data *ld = td->aio_data; | |
37 | ||
38 | int r; | |
39 | ||
40 | do { | |
41 | r = io_getevents(ld->aio_ctx, min, max, ld->aio_events, t); | |
42 | if (r != -EAGAIN && r != -EINTR) | |
43 | break; | |
44 | } while (1); | |
45 | ||
46 | return r; | |
47 | } | |
48 | ||
49 | static int fio_libaio_queue(struct thread_data *td, struct io_u *io_u) | |
50 | { | |
51 | struct libaio_data *ld = td->aio_data; | |
52 | struct iocb *iocb = &io_u->iocb; | |
53 | int ret; | |
54 | ||
55 | do { | |
56 | ret = io_submit(ld->aio_ctx, 1, &iocb); | |
57 | if (ret == 1) | |
58 | return 0; | |
59 | else if (ret == -EAGAIN) | |
60 | usleep(100); | |
61 | else if (ret == -EINTR) | |
62 | continue; | |
63 | else | |
64 | break; | |
65 | } while (1); | |
66 | ||
67 | return ret; | |
68 | ||
69 | } | |
70 | ||
71 | static int fio_libaio_cancel(struct thread_data *td, struct io_u *io_u) | |
72 | { | |
73 | struct libaio_data *ld = td->aio_data; | |
74 | ||
75 | return io_cancel(ld->aio_ctx, &io_u->iocb, ld->aio_events); | |
76 | } | |
77 | ||
78 | int fio_libaio_init(struct thread_data *td) | |
79 | { | |
80 | struct libaio_data *ld = malloc(sizeof(*ld)); | |
81 | ||
82 | memset(ld, 0, sizeof(*ld)); | |
83 | if (io_queue_init(td->aio_depth, &ld->aio_ctx)) { | |
84 | td_verror(td, errno); | |
85 | return 1; | |
86 | } | |
87 | ||
88 | td->io_prep = fio_libaio_io_prep; | |
89 | td->io_queue = fio_libaio_queue; | |
90 | td->io_getevents = fio_libaio_getevents; | |
91 | td->io_event = fio_libaio_event; | |
92 | td->io_cancel = fio_libaio_cancel; | |
93 | ||
94 | ld->aio_events = malloc(td->aio_depth * sizeof(struct io_event)); | |
95 | td->aio_data = ld; | |
96 | return 0; | |
97 | } | |
98 | ||
99 | void fio_libaio_cleanup(struct thread_data *td) | |
100 | { | |
101 | struct libaio_data *ld = td->aio_data; | |
102 | ||
103 | if (ld) { | |
104 | io_destroy(ld->aio_ctx); | |
105 | if (ld->aio_events) | |
106 | free(ld->aio_events); | |
107 | ||
108 | free(ld); | |
109 | td->aio_data = NULL; | |
110 | } | |
111 | } | |
112 | ||
113 | #else /* FIO_HAVE_LIBAIO */ | |
114 | ||
115 | int fio_libaio_init(struct thread_data *td) | |
116 | { | |
117 | return EINVAL; | |
118 | } | |
119 | ||
120 | void fio_libaio_cleanup(struct thread_data *td) | |
121 | { | |
122 | } | |
123 | ||
124 | #endif /* FIO_HAVE_LIBAIO */ | |
125 | ||
126 | #ifdef FIO_HAVE_POSIXAIO | |
127 | ||
128 | struct posixaio_data { | |
129 | struct io_u **aio_events; | |
130 | }; | |
131 | ||
132 | static int fio_posixaio_cancel(struct thread_data *td, struct io_u *io_u) | |
133 | { | |
134 | int r = aio_cancel(td->fd, &io_u->aiocb); | |
135 | ||
136 | if (r == 1 || r == AIO_CANCELED) | |
137 | return 0; | |
138 | ||
139 | return 1; | |
140 | } | |
141 | ||
142 | static void fio_posixaio_prep(struct thread_data *td, struct io_u *io_u, | |
143 | int read) | |
144 | { | |
145 | struct aiocb *aiocb = &io_u->aiocb; | |
146 | ||
147 | aiocb->aio_fildes = td->fd; | |
148 | aiocb->aio_buf = io_u->buf; | |
149 | aiocb->aio_nbytes = io_u->buflen; | |
150 | aiocb->aio_offset = io_u->offset; | |
151 | ||
152 | if (read) | |
153 | aiocb->aio_lio_opcode = LIO_READ; | |
154 | else | |
155 | aiocb->aio_lio_opcode = LIO_WRITE; | |
156 | ||
157 | io_u->seen = 0; | |
158 | } | |
159 | ||
160 | static int fio_posixaio_getevents(struct thread_data *td, int min, int max, | |
161 | struct timespec *t) | |
162 | { | |
163 | struct posixaio_data *pd = td->aio_data; | |
164 | struct list_head *entry; | |
165 | int r; | |
166 | ||
167 | r = 0; | |
168 | restart: | |
169 | list_for_each(entry, &td->io_u_busylist) { | |
170 | struct io_u *io_u = list_entry(entry, struct io_u, list); | |
171 | ||
172 | if (io_u->seen) | |
173 | continue; | |
174 | ||
175 | if (aio_error(&io_u->aiocb) != EINPROGRESS) { | |
176 | pd->aio_events[r++] = io_u; | |
177 | io_u->seen = 1; | |
178 | } | |
179 | ||
180 | if (r >= max) | |
181 | break; | |
182 | } | |
183 | ||
184 | if (r >= min) | |
185 | return r; | |
186 | ||
187 | /* | |
188 | * hrmpf, we need to wait for more. we should use aio_suspend, for | |
189 | * now just sleep a little and recheck status of busy-and-not-seen | |
190 | */ | |
191 | usleep(1000); | |
192 | goto restart; | |
193 | } | |
194 | ||
195 | static struct io_u *fio_posixaio_event(struct thread_data *td, int event) | |
196 | { | |
197 | struct posixaio_data *pd = td->aio_data; | |
198 | ||
199 | return pd->aio_events[event]; | |
200 | } | |
201 | ||
202 | static int fio_posixaio_queue(struct thread_data *td, struct io_u *io_u) | |
203 | { | |
204 | struct aiocb *aiocb = &io_u->aiocb; | |
205 | ||
206 | if (aiocb->aio_lio_opcode == LIO_READ) | |
207 | return aio_read(aiocb); | |
208 | else | |
209 | return aio_write(aiocb); | |
210 | } | |
211 | ||
212 | int fio_posixaio_init(struct thread_data *td) | |
213 | { | |
214 | struct posixaio_data *pd = malloc(sizeof(*pd)); | |
215 | ||
216 | pd->aio_events = malloc(td->aio_depth * sizeof(struct io_u *)); | |
217 | ||
218 | td->io_prep = fio_posixaio_prep; | |
219 | td->io_queue = fio_posixaio_queue; | |
220 | td->io_getevents = fio_posixaio_getevents; | |
221 | td->io_event = fio_posixaio_event; | |
222 | td->io_cancel = fio_posixaio_cancel; | |
223 | ||
224 | td->aio_data = pd; | |
225 | return 0; | |
226 | } | |
227 | ||
228 | void fio_posixaio_cleanup(struct thread_data *td) | |
229 | { | |
230 | struct posixaio_data *pd = td->aio_data; | |
231 | ||
232 | if (pd) { | |
233 | free(pd->aio_events); | |
234 | free(pd); | |
235 | td->aio_data = NULL; | |
236 | } | |
237 | } | |
238 | ||
239 | #else /* FIO_HAVE_POSIXAIO */ | |
240 | ||
241 | int fio_posixaio_init(struct thread_data *td) | |
242 | { | |
243 | return EINVAL; | |
244 | } | |
245 | ||
246 | void fio_posixaio_cleanup(struct thread_data *td) | |
247 | { | |
248 | } | |
249 | ||
250 | #endif /* FIO_HAVE_POSIXAIO */ |