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