binject updates
[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);
3410599a 194 buc->type = B_TYPE_WRITE;
79a43187
JA
195 } else if (io_u->ddir == DDIR_TRIM) {
196 binject_buc_init(bd, io_u);
197 buc->type = B_TYPE_DISCARD;
198 } else {
199 assert(0);
200 }
201
202 return 0;
203}
204
205static int fio_binject_queue(struct thread_data *td, struct io_u *io_u)
206{
207 int ret;
208
209 fio_ro_check(td, io_u);
210
211 ret = fio_binject_doio(td, io_u);
212
213 if (ret < 0)
214 io_u->error = errno;
215
216 if (io_u->error) {
217 td_verror(td, io_u->error, "xfer");
218 return FIO_Q_COMPLETED;
219 }
220
221 return ret;
222}
223
224static struct io_u *fio_binject_event(struct thread_data *td, int event)
225{
226 struct binject_data *bd = td->io_ops->data;
227
228 return bd->events[event];
229}
230
0e238572
JA
231static void binject_unmap_dev(struct thread_data *td, struct binject_file *bf)
232{
233 struct b_ioctl_cmd bic;
234 int fdb;
235
236 if (bf->fd >= 0) {
237 close(bf->fd);
238 bf->fd = -1;
239 }
240
241 fdb = open("/dev/binject-ctl", O_RDWR);
242 if (fdb < 0) {
243 td_verror(td, errno, "open binject-ctl");
244 return;
245 }
246
247 bic.minor = bf->minor;
248
249 if (ioctl(fdb, 1, &bic) < 0) {
250 td_verror(td, errno, "binject dev unmap");
251 close(fdb);
252 return;
253 }
254
255 close(fdb);
256}
257
258static int binject_map_dev(struct thread_data *td, struct binject_file *bf,
259 int fd)
260{
261 struct b_ioctl_cmd bic;
262 char name[80];
263 struct stat sb;
264 int fdb, dev_there, loops;
265
266 fdb = open("/dev/binject-ctl", O_RDWR);
267 if (fdb < 0) {
268 td_verror(td, errno, "binject ctl open");
269 return 1;
270 }
271
272 bic.fd = fd;
273
274 if (ioctl(fdb, 0, &bic) < 0) {
275 td_verror(td, errno, "binject dev map");
276 close(fdb);
277 return 1;
278 }
279
280 bf->minor = bic.minor;
281
282 sprintf(name, "/dev/binject%u", bf->minor);
283
284 /*
285 * Wait for udev to create the node...
286 */
287 dev_there = loops = 0;
288 do {
289 if (!stat(name, &sb)) {
290 dev_there = 1;
291 break;
292 }
293
294 usleep(10000);
295 } while (++loops < 100);
296
297 close(fdb);
298
299 if (!dev_there) {
300 log_err("fio: timed out waiting for binject dev\n");
301 goto err_unmap;
302 }
303
304 bf->fd = open(name, O_RDWR);
305 if (bf->fd < 0) {
306 td_verror(td, errno, "binject dev open");
307err_unmap:
308 binject_unmap_dev(td, bf);
309 return 1;
310 }
311
312 return 0;
313}
314
315static int fio_binject_close_file(struct thread_data *td, struct fio_file *f)
316{
d01c404b 317 struct binject_file *bf = f->file_data;
0e238572
JA
318
319 if (bf) {
320 binject_unmap_dev(td, bf);
321 free(bf);
d01c404b 322 f->file_data = NULL;
0e238572
JA
323 return generic_close_file(td, f);
324 }
325
326 return 0;
327}
328
4a435dac
JA
329static int fio_binject_open_file(struct thread_data *td, struct fio_file *f)
330{
0e238572 331 struct binject_file *bf;
4a435dac
JA
332 unsigned int bs;
333 int ret;
334
335 ret = generic_open_file(td, f);
336 if (ret)
337 return 1;
338
339 if (f->filetype != FIO_TYPE_BD) {
340 log_err("fio: binject only works with block devices\n");
0e238572 341 goto err_close;
4a435dac
JA
342 }
343 if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
344 td_verror(td, errno, "BLKSSZGET");
0e238572
JA
345 goto err_close;
346 }
347
348 bf = malloc(sizeof(*bf));
349 bf->bs = bs;
350 bf->minor = bf->fd = -1;
d01c404b 351 f->file_data = bf;
0e238572
JA
352
353 if (binject_map_dev(td, bf, f->fd)) {
354err_close:
355 ret = generic_close_file(td, f);
4a435dac
JA
356 return 1;
357 }
358
4a435dac
JA
359 return 0;
360}
361
79a43187
JA
362static void fio_binject_cleanup(struct thread_data *td)
363{
364 struct binject_data *bd = td->io_ops->data;
365
366 if (bd) {
367 free(bd->events);
368 free(bd->cmds);
369 free(bd->fd_flags);
370 free(bd->pfds);
371 free(bd);
372 }
373}
374
375static int fio_binject_init(struct thread_data *td)
376{
377 struct binject_data *bd;
378
379 bd = malloc(sizeof(*bd));
380 memset(bd, 0, sizeof(*bd));
381
382 bd->cmds = malloc(td->o.iodepth * sizeof(struct b_user_cmd));
383 memset(bd->cmds, 0, td->o.iodepth * sizeof(struct b_user_cmd));
384
385 bd->events = malloc(td->o.iodepth * sizeof(struct io_u *));
386 memset(bd->events, 0, td->o.iodepth * sizeof(struct io_u *));
387
388 bd->pfds = malloc(sizeof(struct pollfd) * td->o.nr_files);
389 memset(bd->pfds, 0, sizeof(struct pollfd) * td->o.nr_files);
390
391 bd->fd_flags = malloc(sizeof(int) * td->o.nr_files);
392 memset(bd->fd_flags, 0, sizeof(int) * td->o.nr_files);
393
394 td->io_ops->data = bd;
395 return 0;
396}
397
398static struct ioengine_ops ioengine = {
399 .name = "binject",
400 .version = FIO_IOOPS_VERSION,
401 .init = fio_binject_init,
402 .prep = fio_binject_prep,
403 .queue = fio_binject_queue,
404 .getevents = fio_binject_getevents,
405 .event = fio_binject_event,
406 .cleanup = fio_binject_cleanup,
4a435dac 407 .open_file = fio_binject_open_file,
0e238572 408 .close_file = fio_binject_close_file,
79a43187
JA
409 .get_file_size = generic_get_file_size,
410 .flags = FIO_RAWIO,
411};
412
413#else /* FIO_HAVE_BINJECT */
414
415/*
416 * When we have a proper configure system in place, we simply wont build
417 * and install this io engine. For now install a crippled version that
418 * just complains and fails to load.
419 */
420static int fio_binject_init(struct thread_data fio_unused *td)
421{
a3edaf76 422 log_err("fio: ioengine binject not available\n");
79a43187
JA
423 return 1;
424}
425
426static struct ioengine_ops ioengine = {
427 .name = "binject",
428 .version = FIO_IOOPS_VERSION,
429 .init = fio_binject_init,
430};
431
432#endif
433
434static void fio_init fio_binject_register(void)
435{
436 register_ioengine(&ioengine);
437}
438
439static void fio_exit fio_binject_unregister(void)
440{
441 unregister_ioengine(&ioengine);
442}