96a96360750038ea87909c8fdfd45f36a89c9d13
[fio.git] / ioengines.c
1 /*
2  * The io parts of the fio tool, includes workers for sync and mmap'ed
3  * io, as well as both posix and linux libaio support.
4  *
5  * sync io is implemented on top of aio.
6  *
7  * This is not really specific to fio, if the get_io_u/put_io_u and
8  * structures was pulled into this as well it would be a perfectly
9  * generic io engine that could be used for other projects.
10  *
11  */
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <dlfcn.h>
17
18 #include "fio.h"
19 #include "os.h"
20
21 static int check_engine_ops(struct ioengine_ops *ops)
22 {
23         /*
24          * cpu thread doesn't need to provide anything
25          */
26         if (ops->flags & FIO_CPUIO)
27                 return 0;
28
29         if (!ops->event) {
30                 log_err("%s: no event handler)\n", ops->name);
31                 return 1;
32         }
33         if (!ops->getevents) {
34                 log_err("%s: no getevents handler)\n", ops->name);
35                 return 1;
36         }
37         if (!ops->queue) {
38                 log_err("%s: no queue handler)\n", ops->name);
39                 return 1;
40         }
41                 
42         return 0;
43 }
44
45 struct ioengine_ops *load_ioengine(struct thread_data *td, const char *name)
46 {
47         char engine[16], engine_lib[256];
48         struct ioengine_ops *ops, *ret;
49         void *dlhandle;
50
51         strncpy(engine, name, sizeof(engine) - 1);
52
53         /*
54          * linux libaio has alias names, so convert to what we want
55          */
56         if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3))
57                 strcpy(engine, "libaio");
58
59         sprintf(engine_lib, "%s/lib/fio/fio-engine-%s.o", fio_inst_prefix, engine);
60         dlerror();
61         dlhandle = dlopen(engine_lib, RTLD_LAZY);
62         if (!dlhandle) {
63                 td_vmsg(td, -1, dlerror());
64                 return NULL;
65         }
66
67         ops = dlsym(dlhandle, "ioengine");
68         if (!ops) {
69                 td_vmsg(td, -1, dlerror());
70                 dlclose(dlhandle);
71                 return NULL;
72         }
73
74         if (ops->version != FIO_IOOPS_VERSION) {
75                 log_err("bad ioops version %d (want %d)\n", ops->version, FIO_IOOPS_VERSION);
76                 dlclose(dlhandle);
77                 return NULL;
78         }
79
80         /*
81          * Check that the required methods are there.
82          */
83         if (check_engine_ops(ops)) {
84                 dlclose(dlhandle);
85                 return NULL;
86         }
87
88         ret = malloc(sizeof(*ret));
89         memcpy(ret, ops, sizeof(*ret));
90         ret->data = NULL;
91         ret->dlhandle = dlhandle;
92
93         return ret;
94 }
95
96 void close_ioengine(struct thread_data *td)
97 {
98         if (td->io_ops->cleanup)
99                 td->io_ops->cleanup(td);
100
101         dlclose(td->io_ops->dlhandle);
102         free(td->io_ops);
103         td->io_ops = NULL;
104 }
105
106 int td_io_prep(struct thread_data *td, struct io_u *io_u)
107 {
108         if (td->io_ops->prep && td->io_ops->prep(td, io_u))
109                 return 1;
110
111         return 0;
112 }
113
114 int td_io_getevents(struct thread_data *td, int min, int max,
115                     struct timespec *t)
116 {
117         return td->io_ops->getevents(td, min, max, t);
118 }
119
120 int td_io_queue(struct thread_data *td, struct io_u *io_u)
121 {
122         gettimeofday(&io_u->issue_time, NULL);
123
124         return td->io_ops->queue(td, io_u);
125 }
126
127 int td_io_init(struct thread_data *td)
128 {
129         if (td->io_ops->init)
130                 return td->io_ops->init(td);
131
132         return 0;
133 }