Initial support for explicit write barriers
[fio.git] / engines / binject.c
CommitLineData
79a43187
JA
1/*
2 * binject engine
3 *
4 * IO engine that uses the Linux binject interface to directly inject
5 * bio's to block devices.
6 *
7 */
8#include <stdio.h>
9#include <stdlib.h>
10#include <unistd.h>
11#include <errno.h>
12#include <assert.h>
13#include <string.h>
14#include <sys/poll.h>
15
16#include "../fio.h"
17
18#ifdef FIO_HAVE_BINJECT
19
20struct binject_data {
21 struct b_user_cmd *cmds;
22 struct io_u **events;
23 struct pollfd *pfds;
24 int *fd_flags;
79a43187
JA
25};
26
0e238572
JA
27struct binject_file {
28 unsigned int bs;
29 int minor;
30 int fd;
31};
32
79a43187
JA
33static void binject_buc_init(struct binject_data *bd, struct io_u *io_u)
34{
35 struct b_user_cmd *buc = &io_u->buc;
36
37 memset(buc, 0, sizeof(*buc));
38 binject_buc_set_magic(buc);
39
40 buc->buf = (unsigned long) io_u->xfer_buf;
41 buc->len = io_u->xfer_buflen;
42 buc->offset = io_u->offset;
43 buc->usr_ptr = (unsigned long) io_u;
44
45 buc->flags = B_FLAG_NOIDLE | B_FLAG_UNPLUG;
46 assert(buc->buf);
47}
48
49static int pollin_events(struct pollfd *pfds, int fds)
50{
51 int i;
52
53 for (i = 0; i < fds; i++)
54 if (pfds[i].revents & POLLIN)
55 return 1;
56
57 return 0;
58}
59
d01c404b
JA
60static unsigned int binject_read_commands(struct thread_data *td, void *p,
61 int left, int *err)
62{
63 struct binject_file *bf;
64 struct fio_file *f;
65 int i, ret, events;
66
67one_more:
68 events = 0;
69 for_each_file(td, f, i) {
70 bf = f->file_data;
71 ret = read(bf->fd, p, left * sizeof(struct b_user_cmd));
72 if (ret < 0) {
73 if (errno == EAGAIN)
74 continue;
75 *err = -errno;
76 td_verror(td, errno, "read");
77 break;
78 } else if (ret) {
79 p += ret;
80 events += ret / sizeof(struct b_user_cmd);
81 }
82 }
83
84 if (*err || events)
85 return events;
86
87 usleep(1000);
88 goto one_more;
89}
90
79a43187
JA
91static int fio_binject_getevents(struct thread_data *td, unsigned int min,
92 unsigned int max, struct timespec fio_unused *t)
93{
94 struct binject_data *bd = td->io_ops->data;
95 int left = max, ret, r = 0, ev_index = 0;
96 void *buf = bd->cmds;
97 unsigned int i, events;
98 struct fio_file *f;
0e238572 99 struct binject_file *bf;
79a43187
JA
100
101 /*
102 * Fill in the file descriptors
103 */
104 for_each_file(td, f, i) {
d01c404b 105 bf = f->file_data;
0e238572 106
79a43187
JA
107 /*
108 * don't block for min events == 0
109 */
110 if (!min) {
0e238572
JA
111 bd->fd_flags[i] = fcntl(bf->fd, F_GETFL);
112 fcntl(bf->fd, F_SETFL, bd->fd_flags[i] | O_NONBLOCK);
79a43187 113 }
0e238572 114 bd->pfds[i].fd = bf->fd;
79a43187
JA
115 bd->pfds[i].events = POLLIN;
116 }
117
118 while (left) {
d01c404b 119 while (!min) {
79a43187
JA
120 ret = poll(bd->pfds, td->o.nr_files, -1);
121 if (ret < 0) {
122 if (!r)
123 r = -errno;
124 td_verror(td, errno, "poll");
125 break;
126 } else if (!ret)
127 continue;
128
129 if (pollin_events(bd->pfds, td->o.nr_files))
130 break;
d01c404b 131 }
79a43187
JA
132
133 if (r < 0)
134 break;
135
d01c404b 136 events = binject_read_commands(td, buf, left, &r);
79a43187
JA
137
138 if (r < 0)
139 break;
79a43187
JA
140
141 left -= events;
142 r += events;
143
144 for (i = 0; i < events; i++) {
145 struct b_user_cmd *buc = (struct b_user_cmd *) buf + i;
146
147 bd->events[ev_index] = (struct io_u *) buc->usr_ptr;
148 ev_index++;
149 }
150 }
151
152 if (!min) {
0e238572 153 for_each_file(td, f, i) {
d01c404b 154 bf = f->file_data;
0e238572
JA
155 fcntl(bf->fd, F_SETFL, bd->fd_flags[i]);
156 }
79a43187
JA
157 }
158
159 if (r > 0)
160 assert(ev_index == r);
161
162 return r;
163}
164
165static int fio_binject_doio(struct thread_data *td, struct io_u *io_u)
166{
167 struct b_user_cmd *buc = &io_u->buc;
d01c404b 168 struct binject_file *bf = io_u->file->file_data;
79a43187
JA
169 int ret;
170
0e238572 171 ret = write(bf->fd, buc, sizeof(*buc));
79a43187
JA
172 if (ret < 0)
173 return ret;
174
175 return FIO_Q_QUEUED;
176}
177
178static int fio_binject_prep(struct thread_data *td, struct io_u *io_u)
179{
180 struct binject_data *bd = td->io_ops->data;
181 struct b_user_cmd *buc = &io_u->buc;
d01c404b 182 struct binject_file *bf = io_u->file->file_data;
79a43187 183
0e238572 184 if (io_u->xfer_buflen & (bf->bs - 1)) {
79a43187
JA
185 log_err("read/write not sector aligned\n");
186 return EINVAL;
187 }
188
189 if (io_u->ddir == DDIR_READ) {
190 binject_buc_init(bd, io_u);
191 buc->type = B_TYPE_READ;
192 } else if (io_u->ddir == DDIR_WRITE) {
193 binject_buc_init(bd, io_u);
1ef2b6be
JA
194 if (io_u->flags & IO_U_F_BARRIER)
195 buc->type = B_TYPE_WRITEBARRIER;
196 else
197 buc->type = B_TYPE_WRITE;
79a43187
JA
198 } else if (io_u->ddir == DDIR_TRIM) {
199 binject_buc_init(bd, io_u);
200 buc->type = B_TYPE_DISCARD;
201 } else {
202 assert(0);
203 }
204
205 return 0;
206}
207
208static int fio_binject_queue(struct thread_data *td, struct io_u *io_u)
209{
210 int ret;
211
212 fio_ro_check(td, io_u);
213
214 ret = fio_binject_doio(td, io_u);
215
216 if (ret < 0)
217 io_u->error = errno;
218
219 if (io_u->error) {
220 td_verror(td, io_u->error, "xfer");
221 return FIO_Q_COMPLETED;
222 }
223
224 return ret;
225}
226
227static struct io_u *fio_binject_event(struct thread_data *td, int event)
228{
229 struct binject_data *bd = td->io_ops->data;
230
231 return bd->events[event];
232}
233
0e238572
JA
234static void binject_unmap_dev(struct thread_data *td, struct binject_file *bf)
235{
236 struct b_ioctl_cmd bic;
237 int fdb;
238
239 if (bf->fd >= 0) {
240 close(bf->fd);
241 bf->fd = -1;
242 }
243
244 fdb = open("/dev/binject-ctl", O_RDWR);
245 if (fdb < 0) {
246 td_verror(td, errno, "open binject-ctl");
247 return;
248 }
249
250 bic.minor = bf->minor;
251
252 if (ioctl(fdb, 1, &bic) < 0) {
253 td_verror(td, errno, "binject dev unmap");
254 close(fdb);
255 return;
256 }
257
258 close(fdb);
259}
260
261static int binject_map_dev(struct thread_data *td, struct binject_file *bf,
262 int fd)
263{
264 struct b_ioctl_cmd bic;
265 char name[80];
266 struct stat sb;
267 int fdb, dev_there, loops;
268
269 fdb = open("/dev/binject-ctl", O_RDWR);
270 if (fdb < 0) {
271 td_verror(td, errno, "binject ctl open");
272 return 1;
273 }
274
275 bic.fd = fd;
276
277 if (ioctl(fdb, 0, &bic) < 0) {
278 td_verror(td, errno, "binject dev map");
279 close(fdb);
280 return 1;
281 }
282
283 bf->minor = bic.minor;
284
285 sprintf(name, "/dev/binject%u", bf->minor);
286
287 /*
288 * Wait for udev to create the node...
289 */
290 dev_there = loops = 0;
291 do {
292 if (!stat(name, &sb)) {
293 dev_there = 1;
294 break;
295 }
296
297 usleep(10000);
298 } while (++loops < 100);
299
300 close(fdb);
301
302 if (!dev_there) {
303 log_err("fio: timed out waiting for binject dev\n");
304 goto err_unmap;
305 }
306
307 bf->fd = open(name, O_RDWR);
308 if (bf->fd < 0) {
309 td_verror(td, errno, "binject dev open");
310err_unmap:
311 binject_unmap_dev(td, bf);
312 return 1;
313 }
314
315 return 0;
316}
317
318static int fio_binject_close_file(struct thread_data *td, struct fio_file *f)
319{
d01c404b 320 struct binject_file *bf = f->file_data;
0e238572
JA
321
322 if (bf) {
323 binject_unmap_dev(td, bf);
324 free(bf);
d01c404b 325 f->file_data = NULL;
0e238572
JA
326 return generic_close_file(td, f);
327 }
328
329 return 0;
330}
331
4a435dac
JA
332static int fio_binject_open_file(struct thread_data *td, struct fio_file *f)
333{
0e238572 334 struct binject_file *bf;
4a435dac
JA
335 unsigned int bs;
336 int ret;
337
338 ret = generic_open_file(td, f);
339 if (ret)
340 return 1;
341
342 if (f->filetype != FIO_TYPE_BD) {
343 log_err("fio: binject only works with block devices\n");
0e238572 344 goto err_close;
4a435dac
JA
345 }
346 if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
347 td_verror(td, errno, "BLKSSZGET");
0e238572
JA
348 goto err_close;
349 }
350
351 bf = malloc(sizeof(*bf));
352 bf->bs = bs;
353 bf->minor = bf->fd = -1;
d01c404b 354 f->file_data = bf;
0e238572
JA
355
356 if (binject_map_dev(td, bf, f->fd)) {
357err_close:
358 ret = generic_close_file(td, f);
4a435dac
JA
359 return 1;
360 }
361
4a435dac
JA
362 return 0;
363}
364
79a43187
JA
365static void fio_binject_cleanup(struct thread_data *td)
366{
367 struct binject_data *bd = td->io_ops->data;
368
369 if (bd) {
370 free(bd->events);
371 free(bd->cmds);
372 free(bd->fd_flags);
373 free(bd->pfds);
374 free(bd);
375 }
376}
377
378static int fio_binject_init(struct thread_data *td)
379{
380 struct binject_data *bd;
381
382 bd = malloc(sizeof(*bd));
383 memset(bd, 0, sizeof(*bd));
384
385 bd->cmds = malloc(td->o.iodepth * sizeof(struct b_user_cmd));
386 memset(bd->cmds, 0, td->o.iodepth * sizeof(struct b_user_cmd));
387
388 bd->events = malloc(td->o.iodepth * sizeof(struct io_u *));
389 memset(bd->events, 0, td->o.iodepth * sizeof(struct io_u *));
390
391 bd->pfds = malloc(sizeof(struct pollfd) * td->o.nr_files);
392 memset(bd->pfds, 0, sizeof(struct pollfd) * td->o.nr_files);
393
394 bd->fd_flags = malloc(sizeof(int) * td->o.nr_files);
395 memset(bd->fd_flags, 0, sizeof(int) * td->o.nr_files);
396
397 td->io_ops->data = bd;
398 return 0;
399}
400
401static struct ioengine_ops ioengine = {
402 .name = "binject",
403 .version = FIO_IOOPS_VERSION,
404 .init = fio_binject_init,
405 .prep = fio_binject_prep,
406 .queue = fio_binject_queue,
407 .getevents = fio_binject_getevents,
408 .event = fio_binject_event,
409 .cleanup = fio_binject_cleanup,
4a435dac 410 .open_file = fio_binject_open_file,
0e238572 411 .close_file = fio_binject_close_file,
79a43187 412 .get_file_size = generic_get_file_size,
1ef2b6be 413 .flags = FIO_RAWIO | FIO_BARRIER,
79a43187
JA
414};
415
416#else /* FIO_HAVE_BINJECT */
417
418/*
419 * When we have a proper configure system in place, we simply wont build
420 * and install this io engine. For now install a crippled version that
421 * just complains and fails to load.
422 */
423static int fio_binject_init(struct thread_data fio_unused *td)
424{
a3edaf76 425 log_err("fio: ioengine binject not available\n");
79a43187
JA
426 return 1;
427}
428
429static struct ioengine_ops ioengine = {
430 .name = "binject",
431 .version = FIO_IOOPS_VERSION,
432 .init = fio_binject_init,
433};
434
435#endif
436
437static void fio_init fio_binject_register(void)
438{
439 register_ioengine(&ioengine);
440}
441
442static void fio_exit fio_binject_unregister(void)
443{
444 unregister_ioengine(&ioengine);
445}