ioengines.c revision 429ca0735f71961ffe52c5ac102b0a14ee1b2c4c
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
21static LIST_HEAD(engine_list);
22
23static int check_engine_ops(struct ioengine_ops *ops)
24{
25	if (ops->version != FIO_IOOPS_VERSION) {
26		log_err("bad ioops version %d (want %d)\n", ops->version, FIO_IOOPS_VERSION);
27		return 1;
28	}
29
30	/*
31	 * cpu thread doesn't need to provide anything
32	 */
33	if (ops->flags & FIO_CPUIO)
34		return 0;
35
36	if (!ops->event) {
37		log_err("%s: no event handler)\n", ops->name);
38		return 1;
39	}
40	if (!ops->getevents) {
41		log_err("%s: no getevents handler)\n", ops->name);
42		return 1;
43	}
44	if (!ops->queue) {
45		log_err("%s: no queue handler)\n", ops->name);
46		return 1;
47	}
48
49	return 0;
50}
51
52void unregister_ioengine(struct ioengine_ops *ops)
53{
54	list_del(&ops->list);
55	INIT_LIST_HEAD(&ops->list);
56}
57
58int register_ioengine(struct ioengine_ops *ops)
59{
60	INIT_LIST_HEAD(&ops->list);
61	list_add_tail(&ops->list, &engine_list);
62	return 0;
63}
64
65static struct ioengine_ops *find_ioengine(const char *name)
66{
67	struct ioengine_ops *ops;
68	struct list_head *entry;
69	char engine[16];
70
71	strncpy(engine, name, sizeof(engine) - 1);
72
73	if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3))
74		strcpy(engine, "libaio");
75
76	list_for_each(entry, &engine_list) {
77		ops = list_entry(entry, struct ioengine_ops, list);
78		if (!strcmp(engine, ops->name))
79			return ops;
80	}
81
82	return NULL;
83}
84
85static struct ioengine_ops *dlopen_ioengine(struct thread_data *td,
86					    const char *engine_lib)
87{
88	struct ioengine_ops *ops;
89	void *dlhandle;
90
91	dlerror();
92	dlhandle = dlopen(engine_lib, RTLD_LAZY);
93	if (!dlhandle) {
94		td_vmsg(td, -1, dlerror());
95		return NULL;
96	}
97
98	/*
99	 * Unlike the included modules, external engines should have a
100	 * non-static ioengine structure that we can reference.
101	 */
102	ops = dlsym(dlhandle, "ioengine");
103	if (!ops) {
104		td_vmsg(td, -1, dlerror());
105		dlclose(dlhandle);
106		return NULL;
107	}
108
109	ops->dlhandle = dlhandle;
110	return ops;
111}
112
113struct ioengine_ops *load_ioengine(struct thread_data *td, const char *name)
114{
115	struct ioengine_ops *ops, *ret;
116	char engine[16];
117
118	strncpy(engine, name, sizeof(engine) - 1);
119
120	/*
121	 * linux libaio has alias names, so convert to what we want
122	 */
123	if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3))
124		strcpy(engine, "libaio");
125
126	ops = find_ioengine(engine);
127	if (!ops)
128		ops = dlopen_ioengine(td, name);
129
130	if (!ops) {
131		log_err("fio: engine %s not loadable\n", name);
132		return NULL;
133	}
134
135	/*
136	 * Check that the required methods are there.
137	 */
138	if (check_engine_ops(ops))
139		return NULL;
140
141	ret = malloc(sizeof(*ret));
142	memcpy(ret, ops, sizeof(*ret));
143	ret->data = NULL;
144
145	return ret;
146}
147
148void close_ioengine(struct thread_data *td)
149{
150	if (td->io_ops->cleanup)
151		td->io_ops->cleanup(td);
152
153	if (td->io_ops->dlhandle)
154		dlclose(td->io_ops->dlhandle);
155
156	free(td->io_ops);
157	td->io_ops = NULL;
158}
159
160int td_io_prep(struct thread_data *td, struct io_u *io_u)
161{
162	if (td->io_ops->prep && td->io_ops->prep(td, io_u))
163		return 1;
164
165	return 0;
166}
167
168int td_io_getevents(struct thread_data *td, int min, int max,
169		    struct timespec *t)
170{
171	return td->io_ops->getevents(td, min, max, t);
172}
173
174int td_io_queue(struct thread_data *td, struct io_u *io_u)
175{
176	fio_gettime(&io_u->issue_time, NULL);
177
178	return td->io_ops->queue(td, io_u);
179}
180
181int td_io_init(struct thread_data *td)
182{
183	if (td->io_ops->init)
184		return td->io_ops->init(td);
185
186	return 0;
187}
188