move skip_bad= option to engines/mtd.c
[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 #include <sys/types.h>
16 #include <sys/stat.h>
17
18 #include "../fio.h"
19
20 #ifdef FIO_HAVE_BINJECT
21
22 struct binject_data {
23         struct b_user_cmd *cmds;
24         struct io_u **events;
25         struct pollfd *pfds;
26         int *fd_flags;
27 };
28
29 struct binject_file {
30         unsigned int bs;
31         int minor;
32         int fd;
33 };
34
35 static 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
51 static 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
62 static unsigned int binject_read_commands(struct thread_data *td, void *buf,
63                                           int left, int *err)
64 {
65         struct fio_file *f;
66         int i, ret, events;
67         char *p = buf;
68
69 one_more:
70         events = 0;
71         for_each_file(td, f, i) {
72                 struct binject_file *bf = FILE_ENG_DATA(f);
73
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
94 static int fio_binject_getevents(struct thread_data *td, unsigned int min,
95                                  unsigned int max,
96                                  const struct timespec fio_unused *t)
97 {
98         struct binject_data *bd = td->io_ops_data;
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) {
108                 struct binject_file *bf = FILE_ENG_DATA(f);
109
110                 /*
111                  * don't block for min events == 0
112                  */
113                 if (!min)
114                         bd->fd_flags[i] = fio_set_fd_nonblocking(bf->fd, "binject");
115                 else
116                         bd->fd_flags[i] = -1;
117
118                 bd->pfds[i].fd = bf->fd;
119                 bd->pfds[i].events = POLLIN;
120         }
121
122         while (left) {
123                 while (!min) {
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;
135                 }
136
137                 if (r < 0)
138                         break;
139
140                 events = binject_read_commands(td, buf, left, &r);
141
142                 if (r < 0)
143                         break;
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
151                         bd->events[ev_index] = (struct io_u *) (unsigned long) buc->usr_ptr;
152                         ev_index++;
153                 }
154         }
155
156         if (!min) {
157                 for_each_file(td, f, i) {
158                         struct binject_file *bf = FILE_ENG_DATA(f);
159
160                         if (bd->fd_flags[i] == -1)
161                                 continue;
162
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));
165                 }
166         }
167
168         if (r > 0)
169                 assert(ev_index == r);
170
171         return r;
172 }
173
174 static int fio_binject_doio(struct thread_data *td, struct io_u *io_u)
175 {
176         struct b_user_cmd *buc = &io_u->buc;
177         struct binject_file *bf = FILE_ENG_DATA(io_u->file);
178         int ret;
179
180         ret = write(bf->fd, buc, sizeof(*buc));
181         if (ret < 0)
182                 return ret;
183
184         return FIO_Q_QUEUED;
185 }
186
187 static int fio_binject_prep(struct thread_data *td, struct io_u *io_u)
188 {
189         struct binject_data *bd = td->io_ops_data;
190         struct b_user_cmd *buc = &io_u->buc;
191         struct binject_file *bf = FILE_ENG_DATA(io_u->file);
192
193         if (io_u->xfer_buflen & (bf->bs - 1)) {
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);
203                 if (io_u->flags & IO_U_F_BARRIER)
204                         buc->type = B_TYPE_WRITEBARRIER;
205                 else
206                         buc->type = B_TYPE_WRITE;
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
217 static 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
236 static struct io_u *fio_binject_event(struct thread_data *td, int event)
237 {
238         struct binject_data *bd = td->io_ops_data;
239
240         return bd->events[event];
241 }
242
243 static 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
254 static 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
264         fdb = binject_open_ctl(td);
265         if (fdb < 0)
266                 return;
267
268         bic.minor = bf->minor;
269
270         if (ioctl(fdb, B_IOCTL_DEL, &bic) < 0)
271                 td_verror(td, errno, "binject dev unmap");
272
273         close(fdb);
274 }
275
276 static 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
284         fdb = binject_open_ctl(td);
285         if (fdb < 0)
286                 return 1;
287
288         bic.fd = fd;
289
290         if (ioctl(fdb, B_IOCTL_ADD, &bic) < 0) {
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");
323 err_unmap:
324                 binject_unmap_dev(td, bf);
325                 return 1;
326         }
327
328         return 0;
329 }
330
331 static int fio_binject_close_file(struct thread_data *td, struct fio_file *f)
332 {
333         struct binject_file *bf = FILE_ENG_DATA(f);
334
335         if (bf) {
336                 binject_unmap_dev(td, bf);
337                 free(bf);
338                 FILE_SET_ENG_DATA(f, NULL);
339                 return generic_close_file(td, f);
340         }
341
342         return 0;
343 }
344
345 static int fio_binject_open_file(struct thread_data *td, struct fio_file *f)
346 {
347         struct binject_file *bf;
348         unsigned int bs;
349         int ret;
350
351         ret = generic_open_file(td, f);
352         if (ret)
353                 return 1;
354
355         if (f->filetype != FIO_TYPE_BLOCK) {
356                 log_err("fio: binject only works with block devices\n");
357                 goto err_close;
358         }
359         if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
360                 td_verror(td, errno, "BLKSSZGET");
361                 goto err_close;
362         }
363
364         bf = malloc(sizeof(*bf));
365         bf->bs = bs;
366         bf->minor = bf->fd = -1;
367         FILE_SET_ENG_DATA(f, bf);
368
369         if (binject_map_dev(td, bf, f->fd)) {
370 err_close:
371                 ret = generic_close_file(td, f);
372                 return 1;
373         }
374
375         return 0;
376 }
377
378 static void fio_binject_cleanup(struct thread_data *td)
379 {
380         struct binject_data *bd = td->io_ops_data;
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
391 static 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
410         td->io_ops_data = bd;
411         return 0;
412 }
413
414 static 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,
423         .open_file      = fio_binject_open_file,
424         .close_file     = fio_binject_close_file,
425         .get_file_size  = generic_get_file_size,
426         .flags          = FIO_RAWIO | FIO_BARRIER | FIO_MEMALIGN,
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  */
436 static int fio_binject_init(struct thread_data fio_unused *td)
437 {
438         log_err("fio: ioengine binject not available\n");
439         return 1;
440 }
441
442 static struct ioengine_ops ioengine = {
443         .name           = "binject",
444         .version        = FIO_IOOPS_VERSION,
445         .init           = fio_binject_init,
446 };
447
448 #endif
449
450 static void fio_init fio_binject_register(void)
451 {
452         register_ioengine(&ioengine);
453 }
454
455 static void fio_exit fio_binject_unregister(void)
456 {
457         unregister_ioengine(&ioengine);
458 }