Add missing file.h f->file_data change
[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 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
67 one_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
91 static 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;
99         struct binject_file *bf;
100
101         /*
102          * Fill in the file descriptors
103          */
104         for_each_file(td, f, i) {
105                 bf = f->file_data;
106
107                 /*
108                  * don't block for min events == 0
109                  */
110                 if (!min) {
111                         bd->fd_flags[i] = fcntl(bf->fd, F_GETFL);
112                         fcntl(bf->fd, F_SETFL, bd->fd_flags[i] | O_NONBLOCK);
113                 }
114                 bd->pfds[i].fd = bf->fd;
115                 bd->pfds[i].events = POLLIN;
116         }
117
118         while (left) {
119                 while (!min) {
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;
131                 }
132
133                 if (r < 0)
134                         break;
135
136                 events = binject_read_commands(td, buf, left, &r);
137
138                 if (r < 0)
139                         break;
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) {
153                 for_each_file(td, f, i) {
154                         bf = f->file_data;
155                         fcntl(bf->fd, F_SETFL, bd->fd_flags[i]);
156                 }
157         }
158
159         if (r > 0)
160                 assert(ev_index == r);
161
162         return r;
163 }
164
165 static int fio_binject_doio(struct thread_data *td, struct io_u *io_u)
166 {
167         struct b_user_cmd *buc = &io_u->buc;
168         struct binject_file *bf = io_u->file->file_data;
169         int ret;
170
171         ret = write(bf->fd, buc, sizeof(*buc));
172         if (ret < 0)
173                 return ret;
174
175         return FIO_Q_QUEUED;
176 }
177
178 static 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;
182         struct binject_file *bf = io_u->file->file_data;
183
184         if (io_u->xfer_buflen & (bf->bs - 1)) {
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);
194                 buc->type = B_TYPE_WRITE;
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
205 static 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
224 static 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
231 static 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
258 static 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");
307 err_unmap:
308                 binject_unmap_dev(td, bf);
309                 return 1;
310         }
311
312         return 0;
313 }
314
315 static int fio_binject_close_file(struct thread_data *td, struct fio_file *f)
316 {
317         struct binject_file *bf = f->file_data;
318
319         if (bf) {
320                 binject_unmap_dev(td, bf);
321                 free(bf);
322                 f->file_data = NULL;
323                 return generic_close_file(td, f);
324         }
325
326         return 0;
327 }
328
329 static int fio_binject_open_file(struct thread_data *td, struct fio_file *f)
330 {
331         struct binject_file *bf;
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");
341                 goto err_close;
342         }
343         if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
344                 td_verror(td, errno, "BLKSSZGET");
345                 goto err_close;
346         }
347
348         bf = malloc(sizeof(*bf));
349         bf->bs = bs;
350         bf->minor = bf->fd = -1;
351         f->file_data = bf;
352
353         if (binject_map_dev(td, bf, f->fd)) {
354 err_close:
355                 ret = generic_close_file(td, f);
356                 return 1;
357         }
358
359         return 0;
360 }
361
362 static 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
375 static 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
398 static 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,
407         .open_file      = fio_binject_open_file,
408         .close_file     = fio_binject_close_file,
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  */
420 static int fio_binject_init(struct thread_data fio_unused *td)
421 {
422         log_err("fio: ioengine binject not available\n");
423         return 1;
424 }
425
426 static struct ioengine_ops ioengine = {
427         .name           = "binject",
428         .version        = FIO_IOOPS_VERSION,
429         .init           = fio_binject_init,
430 };
431
432 #endif
433
434 static void fio_init fio_binject_register(void)
435 {
436         register_ioengine(&ioengine);
437 }
438
439 static void fio_exit fio_binject_unregister(void)
440 {
441         unregister_ioengine(&ioengine);
442 }