Initial support for explicit write barriers
[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                 if (io_u->flags & IO_U_F_BARRIER)
195                         buc->type = B_TYPE_WRITEBARRIER;
196                 else
197                         buc->type = B_TYPE_WRITE;
198         } else if (io_u->ddir == DDIR_TRIM) {
199                 binject_buc_init(bd, io_u);
200                 buc->type = B_TYPE_DISCARD;
201         } else {
202                 assert(0);
203         }
204
205         return 0;
206 }
207
208 static int fio_binject_queue(struct thread_data *td, struct io_u *io_u)
209 {
210         int ret;
211
212         fio_ro_check(td, io_u);
213
214         ret = fio_binject_doio(td, io_u);
215
216         if (ret < 0)
217                 io_u->error = errno;
218
219         if (io_u->error) {
220                 td_verror(td, io_u->error, "xfer");
221                 return FIO_Q_COMPLETED;
222         }
223
224         return ret;
225 }
226
227 static struct io_u *fio_binject_event(struct thread_data *td, int event)
228 {
229         struct binject_data *bd = td->io_ops->data;
230
231         return bd->events[event];
232 }
233
234 static void binject_unmap_dev(struct thread_data *td, struct binject_file *bf)
235 {
236         struct b_ioctl_cmd bic;
237         int fdb;
238
239         if (bf->fd >= 0) {
240                 close(bf->fd);
241                 bf->fd = -1;
242         }
243
244         fdb = open("/dev/binject-ctl", O_RDWR);
245         if (fdb < 0) {
246                 td_verror(td, errno, "open binject-ctl");
247                 return;
248         }
249
250         bic.minor = bf->minor;
251
252         if (ioctl(fdb, 1, &bic) < 0) {
253                 td_verror(td, errno, "binject dev unmap");
254                 close(fdb);
255                 return;
256         }
257
258         close(fdb);
259 }
260
261 static int binject_map_dev(struct thread_data *td, struct binject_file *bf,
262                            int fd)
263 {
264         struct b_ioctl_cmd bic;
265         char name[80];
266         struct stat sb;
267         int fdb, dev_there, loops;
268
269         fdb = open("/dev/binject-ctl", O_RDWR);
270         if (fdb < 0) {
271                 td_verror(td, errno, "binject ctl open");
272                 return 1;
273         }
274
275         bic.fd = fd;
276
277         if (ioctl(fdb, 0, &bic) < 0) {
278                 td_verror(td, errno, "binject dev map");
279                 close(fdb);
280                 return 1;
281         }
282
283         bf->minor = bic.minor;
284
285         sprintf(name, "/dev/binject%u", bf->minor);
286
287         /*
288          * Wait for udev to create the node...
289          */
290         dev_there = loops = 0;
291         do {
292                 if (!stat(name, &sb)) {
293                         dev_there = 1;
294                         break;
295                 }
296
297                 usleep(10000);
298         } while (++loops < 100);
299
300         close(fdb);
301
302         if (!dev_there) {
303                 log_err("fio: timed out waiting for binject dev\n");
304                 goto err_unmap;
305         }
306
307         bf->fd = open(name, O_RDWR);
308         if (bf->fd < 0) {
309                 td_verror(td, errno, "binject dev open");
310 err_unmap:
311                 binject_unmap_dev(td, bf);
312                 return 1;
313         }
314
315         return 0;
316 }
317
318 static int fio_binject_close_file(struct thread_data *td, struct fio_file *f)
319 {
320         struct binject_file *bf = f->file_data;
321
322         if (bf) {
323                 binject_unmap_dev(td, bf);
324                 free(bf);
325                 f->file_data = NULL;
326                 return generic_close_file(td, f);
327         }
328
329         return 0;
330 }
331
332 static int fio_binject_open_file(struct thread_data *td, struct fio_file *f)
333 {
334         struct binject_file *bf;
335         unsigned int bs;
336         int ret;
337
338         ret = generic_open_file(td, f);
339         if (ret)
340                 return 1;
341
342         if (f->filetype != FIO_TYPE_BD) {
343                 log_err("fio: binject only works with block devices\n");
344                 goto err_close;
345         }
346         if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
347                 td_verror(td, errno, "BLKSSZGET");
348                 goto err_close;
349         }
350
351         bf = malloc(sizeof(*bf));
352         bf->bs = bs;
353         bf->minor = bf->fd = -1;
354         f->file_data = bf;
355
356         if (binject_map_dev(td, bf, f->fd)) {
357 err_close:
358                 ret = generic_close_file(td, f);
359                 return 1;
360         }
361
362         return 0;
363 }
364
365 static void fio_binject_cleanup(struct thread_data *td)
366 {
367         struct binject_data *bd = td->io_ops->data;
368
369         if (bd) {
370                 free(bd->events);
371                 free(bd->cmds);
372                 free(bd->fd_flags);
373                 free(bd->pfds);
374                 free(bd);
375         }
376 }
377
378 static int fio_binject_init(struct thread_data *td)
379 {
380         struct binject_data *bd;
381
382         bd = malloc(sizeof(*bd));
383         memset(bd, 0, sizeof(*bd));
384
385         bd->cmds = malloc(td->o.iodepth * sizeof(struct b_user_cmd));
386         memset(bd->cmds, 0, td->o.iodepth * sizeof(struct b_user_cmd));
387
388         bd->events = malloc(td->o.iodepth * sizeof(struct io_u *));
389         memset(bd->events, 0, td->o.iodepth * sizeof(struct io_u *));
390
391         bd->pfds = malloc(sizeof(struct pollfd) * td->o.nr_files);
392         memset(bd->pfds, 0, sizeof(struct pollfd) * td->o.nr_files);
393
394         bd->fd_flags = malloc(sizeof(int) * td->o.nr_files);
395         memset(bd->fd_flags, 0, sizeof(int) * td->o.nr_files);
396
397         td->io_ops->data = bd;
398         return 0;
399 }
400
401 static struct ioengine_ops ioengine = {
402         .name           = "binject",
403         .version        = FIO_IOOPS_VERSION,
404         .init           = fio_binject_init,
405         .prep           = fio_binject_prep,
406         .queue          = fio_binject_queue,
407         .getevents      = fio_binject_getevents,
408         .event          = fio_binject_event,
409         .cleanup        = fio_binject_cleanup,
410         .open_file      = fio_binject_open_file,
411         .close_file     = fio_binject_close_file,
412         .get_file_size  = generic_get_file_size,
413         .flags          = FIO_RAWIO | FIO_BARRIER,
414 };
415
416 #else /* FIO_HAVE_BINJECT */
417
418 /*
419  * When we have a proper configure system in place, we simply wont build
420  * and install this io engine. For now install a crippled version that
421  * just complains and fails to load.
422  */
423 static int fio_binject_init(struct thread_data fio_unused *td)
424 {
425         log_err("fio: ioengine binject not available\n");
426         return 1;
427 }
428
429 static struct ioengine_ops ioengine = {
430         .name           = "binject",
431         .version        = FIO_IOOPS_VERSION,
432         .init           = fio_binject_init,
433 };
434
435 #endif
436
437 static void fio_init fio_binject_register(void)
438 {
439         register_ioengine(&ioengine);
440 }
441
442 static void fio_exit fio_binject_unregister(void)
443 {
444         unregister_ioengine(&ioengine);
445 }