d83b1180000269a3c507e377753b5d81c87dfd32
[fio.git] / engines / binject.c
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
20 struct binject_data {
21         struct b_user_cmd *cmds;
22         struct io_u **events;
23         struct pollfd *pfds;
24         int *fd_flags;
25 };
26
27 struct binject_file {
28         unsigned int bs;
29         int minor;
30         int fd;
31 };
32
33 static 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
49 static 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
60 static 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;
68         struct binject_file *bf;
69
70         /*
71          * Fill in the file descriptors
72          */
73         for_each_file(td, f, i) {
74                 bf = (struct binject_file *) f->file_data;
75
76                 /*
77                  * don't block for min events == 0
78                  */
79                 if (!min) {
80                         bd->fd_flags[i] = fcntl(bf->fd, F_GETFL);
81                         fcntl(bf->fd, F_SETFL, bd->fd_flags[i] | O_NONBLOCK);
82                 }
83                 bd->pfds[i].fd = bf->fd;
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
110 re_read:
111                 p = buf;
112                 events = 0;
113                 for_each_file(td, f, i) {
114                         bf = (struct binject_file *) f->file_data;
115
116                         ret = read(bf->fd, p, left * sizeof(struct b_user_cmd));
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) {
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                 }
152         }
153
154         if (r > 0)
155                 assert(ev_index == r);
156
157         return r;
158 }
159
160 static 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;
164         struct binject_file *bf = (struct binject_file *) f->file_data;
165         int ret;
166
167         ret = write(bf->fd, buc, sizeof(*buc));
168         if (ret < 0)
169                 return ret;
170
171         return FIO_Q_QUEUED;
172 }
173
174 static 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;
178         struct binject_file *bf = (struct binject_file *) io_u->file->file_data;
179
180         if (io_u->xfer_buflen & (bf->bs - 1)) {
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);
190                 buc->type = B_TYPE_WRITE;
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
201 static 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
220 static 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
227 static 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
254 static 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");
303 err_unmap:
304                 binject_unmap_dev(td, bf);
305                 return 1;
306         }
307
308         return 0;
309 }
310
311 static 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
325 static int fio_binject_open_file(struct thread_data *td, struct fio_file *f)
326 {
327         struct binject_file *bf;
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");
337                 goto err_close;
338         }
339         if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
340                 td_verror(td, errno, "BLKSSZGET");
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)) {
350 err_close:
351                 ret = generic_close_file(td, f);
352                 return 1;
353         }
354
355         return 0;
356 }
357
358 static 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
371 static 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
394 static 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,
403         .open_file      = fio_binject_open_file,
404         .close_file     = fio_binject_close_file,
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  */
416 static int fio_binject_init(struct thread_data fio_unused *td)
417 {
418         log_err("fio: ioengine binject not available\n");
419         return 1;
420 }
421
422 static struct ioengine_ops ioengine = {
423         .name           = "binject",
424         .version        = FIO_IOOPS_VERSION,
425         .init           = fio_binject_init,
426 };
427
428 #endif
429
430 static void fio_init fio_binject_register(void)
431 {
432         register_ioengine(&ioengine);
433 }
434
435 static void fio_exit fio_binject_unregister(void)
436 {
437         unregister_ioengine(&ioengine);
438 }