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