Fio 1.50-rc4
[fio.git] / ioengines.c
... / ...
CommitLineData
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#include <fcntl.h>
18#include <assert.h>
19
20#include "fio.h"
21#include "diskutil.h"
22
23static FLIST_HEAD(engine_list);
24
25static int check_engine_ops(struct ioengine_ops *ops)
26{
27 if (ops->version != FIO_IOOPS_VERSION) {
28 log_err("bad ioops version %d (want %d)\n", ops->version,
29 FIO_IOOPS_VERSION);
30 return 1;
31 }
32
33 if (!ops->queue) {
34 log_err("%s: no queue handler\n", ops->name);
35 return 1;
36 }
37
38 /*
39 * sync engines only need a ->queue()
40 */
41 if (ops->flags & FIO_SYNCIO)
42 return 0;
43
44 if (!ops->event) {
45 log_err("%s: no event handler\n", ops->name);
46 return 1;
47 }
48 if (!ops->getevents) {
49 log_err("%s: no getevents handler\n", ops->name);
50 return 1;
51 }
52 if (!ops->queue) {
53 log_err("%s: no queue handler\n", ops->name);
54 return 1;
55 }
56
57 return 0;
58}
59
60void unregister_ioengine(struct ioengine_ops *ops)
61{
62 dprint(FD_IO, "ioengine %s unregistered\n", ops->name);
63 flist_del(&ops->list);
64 INIT_FLIST_HEAD(&ops->list);
65}
66
67void register_ioengine(struct ioengine_ops *ops)
68{
69 dprint(FD_IO, "ioengine %s registered\n", ops->name);
70 INIT_FLIST_HEAD(&ops->list);
71 flist_add_tail(&ops->list, &engine_list);
72}
73
74static struct ioengine_ops *find_ioengine(const char *name)
75{
76 struct ioengine_ops *ops;
77 struct flist_head *entry;
78
79 flist_for_each(entry, &engine_list) {
80 ops = flist_entry(entry, struct ioengine_ops, list);
81 if (!strcmp(name, ops->name))
82 return ops;
83 }
84
85 return NULL;
86}
87
88static struct ioengine_ops *dlopen_ioengine(struct thread_data *td,
89 const char *engine_lib)
90{
91 struct ioengine_ops *ops;
92 void *dlhandle;
93
94 dprint(FD_IO, "dload engine %s\n", engine_lib);
95
96 dlerror();
97 dlhandle = dlopen(engine_lib, RTLD_LAZY);
98 if (!dlhandle) {
99 td_vmsg(td, -1, dlerror(), "dlopen");
100 return NULL;
101 }
102
103 /*
104 * Unlike the included modules, external engines should have a
105 * non-static ioengine structure that we can reference.
106 */
107 ops = dlsym(dlhandle, "ioengine");
108 if (!ops) {
109 td_vmsg(td, -1, dlerror(), "dlsym");
110 dlclose(dlhandle);
111 return NULL;
112 }
113
114 ops->dlhandle = dlhandle;
115 return ops;
116}
117
118struct ioengine_ops *load_ioengine(struct thread_data *td, const char *name)
119{
120 struct ioengine_ops *ops, *ret;
121 char engine[16];
122
123 dprint(FD_IO, "load ioengine %s\n", name);
124
125 strncpy(engine, name, sizeof(engine) - 1);
126
127 /*
128 * linux libaio has alias names, so convert to what we want
129 */
130 if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3))
131 strcpy(engine, "libaio");
132
133 ops = find_ioengine(engine);
134 if (!ops)
135 ops = dlopen_ioengine(td, name);
136
137 if (!ops) {
138 log_err("fio: engine %s not loadable\n", name);
139 return NULL;
140 }
141
142 /*
143 * Check that the required methods are there.
144 */
145 if (check_engine_ops(ops))
146 return NULL;
147
148 ret = malloc(sizeof(*ret));
149 memcpy(ret, ops, sizeof(*ret));
150 ret->data = NULL;
151
152 return ret;
153}
154
155void close_ioengine(struct thread_data *td)
156{
157 dprint(FD_IO, "close ioengine %s\n", td->io_ops->name);
158
159 if (td->io_ops->cleanup) {
160 td->io_ops->cleanup(td);
161 td->io_ops->data = NULL;
162 }
163
164 if (td->io_ops->dlhandle)
165 dlclose(td->io_ops->dlhandle);
166
167 free(td->io_ops);
168 td->io_ops = NULL;
169}
170
171int td_io_prep(struct thread_data *td, struct io_u *io_u)
172{
173 dprint_io_u(io_u, "prep");
174 fio_ro_check(td, io_u);
175
176 lock_file(td, io_u->file, io_u->ddir);
177
178 if (td->io_ops->prep) {
179 int ret = td->io_ops->prep(td, io_u);
180
181 dprint(FD_IO, "->prep(%p)=%d\n", io_u, ret);
182 if (ret)
183 unlock_file(td, io_u->file);
184 return ret;
185 }
186
187 return 0;
188}
189
190int td_io_getevents(struct thread_data *td, unsigned int min, unsigned int max,
191 struct timespec *t)
192{
193 int r = 0;
194
195 if (min > 0 && td->io_ops->commit) {
196 r = td->io_ops->commit(td);
197 if (r < 0)
198 goto out;
199 }
200 if (max > td->cur_depth)
201 max = td->cur_depth;
202 if (min > max)
203 max = min;
204
205 r = 0;
206 if (max && td->io_ops->getevents)
207 r = td->io_ops->getevents(td, min, max, t);
208out:
209 if (r >= 0)
210 io_u_mark_complete(td, r);
211 else
212 td_verror(td, r, "get_events");
213
214 dprint(FD_IO, "getevents: %d\n", r);
215 return r;
216}
217
218int td_io_queue(struct thread_data *td, struct io_u *io_u)
219{
220 int ret;
221
222 dprint_io_u(io_u, "queue");
223 fio_ro_check(td, io_u);
224
225 assert((io_u->flags & IO_U_F_FLIGHT) == 0);
226 io_u->flags |= IO_U_F_FLIGHT;
227
228 assert(fio_file_open(io_u->file));
229
230 io_u->error = 0;
231 io_u->resid = 0;
232
233 if (td->io_ops->flags & FIO_SYNCIO) {
234 if (fio_fill_issue_time(td))
235 fio_gettime(&io_u->issue_time, NULL);
236
237 /*
238 * only used for iolog
239 */
240 if (td->o.read_iolog_file)
241 memcpy(&td->last_issue, &io_u->issue_time,
242 sizeof(struct timeval));
243 }
244
245 if (ddir_rw(io_u->ddir))
246 td->io_issues[io_u->ddir]++;
247
248 ret = td->io_ops->queue(td, io_u);
249
250 unlock_file(td, io_u->file);
251
252 /*
253 * Add warning for O_DIRECT so that users have an easier time
254 * spotting potentially bad alignment. If this triggers for the first
255 * IO, then it's likely an alignment problem or because the host fs
256 * does not support O_DIRECT
257 */
258 if (io_u->error == EINVAL && td->io_issues[io_u->ddir & 1] == 1 &&
259 td->o.odirect) {
260 log_info("fio: first direct IO errored. File system may not "
261 "support direct IO, or iomem_align= is bad.\n");
262 }
263
264 if (!td->io_ops->commit) {
265 io_u_mark_submit(td, 1);
266 io_u_mark_complete(td, 1);
267 }
268
269 if (ret == FIO_Q_COMPLETED) {
270 if (ddir_rw(io_u->ddir)) {
271 io_u_mark_depth(td, 1);
272 td->ts.total_io_u[io_u->ddir]++;
273 } else if (io_u->ddir == DDIR_TRIM)
274 td->ts.total_io_u[2]++;
275 } else if (ret == FIO_Q_QUEUED) {
276 int r;
277
278 if (ddir_rw(io_u->ddir)) {
279 td->io_u_queued++;
280 td->ts.total_io_u[io_u->ddir]++;
281 }
282
283 if (td->io_u_queued >= td->o.iodepth_batch) {
284 r = td_io_commit(td);
285 if (r < 0)
286 return r;
287 }
288 }
289
290 if ((td->io_ops->flags & FIO_SYNCIO) == 0) {
291 if (fio_fill_issue_time(td))
292 fio_gettime(&io_u->issue_time, NULL);
293
294 /*
295 * only used for iolog
296 */
297 if (td->o.read_iolog_file)
298 memcpy(&td->last_issue, &io_u->issue_time,
299 sizeof(struct timeval));
300 }
301
302 return ret;
303}
304
305int td_io_init(struct thread_data *td)
306{
307 int ret = 0;
308
309 if (td->io_ops->init) {
310 ret = td->io_ops->init(td);
311 if (ret && td->o.iodepth > 1) {
312 log_err("fio: io engine init failed. Perhaps try"
313 " reducing io depth?\n");
314 }
315 }
316
317 return ret;
318}
319
320int td_io_commit(struct thread_data *td)
321{
322 int ret;
323
324 dprint(FD_IO, "calling ->commit(), depth %d\n", td->cur_depth);
325
326 if (!td->cur_depth || !td->io_u_queued)
327 return 0;
328
329 io_u_mark_depth(td, td->io_u_queued);
330 td->io_u_queued = 0;
331
332 if (td->io_ops->commit) {
333 ret = td->io_ops->commit(td);
334 if (ret)
335 td_verror(td, -ret, "io commit");
336 }
337
338 return 0;
339}
340
341int td_io_open_file(struct thread_data *td, struct fio_file *f)
342{
343 assert(!fio_file_open(f));
344 assert(f->fd == -1);
345
346 if (td->io_ops->open_file(td, f)) {
347 if (td->error == EINVAL && td->o.odirect)
348 log_err("fio: destination does not support O_DIRECT\n");
349 if (td->error == EMFILE) {
350 log_err("fio: try reducing/setting openfiles (failed"
351 " at %u of %u)\n", td->nr_open_files,
352 td->o.nr_files);
353 }
354
355 assert(f->fd == -1);
356 assert(!fio_file_open(f));
357 return 1;
358 }
359
360 fio_file_reset(f);
361 fio_file_set_open(f);
362 fio_file_clear_closing(f);
363 disk_util_inc(f->du);
364
365 td->nr_open_files++;
366 get_file(f);
367
368 if (f->filetype == FIO_TYPE_PIPE) {
369 if (td_random(td)) {
370 log_err("fio: can't seek on pipes (no random io)\n");
371 goto err;
372 }
373 }
374
375 if (td->io_ops->flags & FIO_DISKLESSIO)
376 goto done;
377
378 if (td->o.invalidate_cache && file_invalidate_cache(td, f))
379 goto err;
380
381 if (td->o.fadvise_hint &&
382 (f->filetype == FIO_TYPE_BD || f->filetype == FIO_TYPE_FILE)) {
383 int flags;
384
385 if (td_random(td))
386 flags = POSIX_FADV_RANDOM;
387 else
388 flags = POSIX_FADV_SEQUENTIAL;
389
390 if (posix_fadvise(f->fd, f->file_offset, f->io_size, flags) < 0) {
391 td_verror(td, errno, "fadvise");
392 goto err;
393 }
394 }
395
396#ifdef FIO_OS_DIRECTIO
397 /*
398 * Some OS's have a distinct call to mark the file non-buffered,
399 * instead of using O_DIRECT (Solaris)
400 */
401 if (td->o.odirect) {
402 int ret = fio_set_odirect(f->fd);
403
404 if (ret) {
405 td_verror(td, ret, "fio_set_odirect");
406 log_err("fio: the file system does not seem to support direct IO\n");
407 goto err;
408 }
409 }
410#endif
411
412done:
413 log_file(td, f, FIO_LOG_OPEN_FILE);
414 return 0;
415err:
416 disk_util_dec(f->du);
417 if (td->io_ops->close_file)
418 td->io_ops->close_file(td, f);
419 return 1;
420}
421
422int td_io_close_file(struct thread_data *td, struct fio_file *f)
423{
424 if (!fio_file_closing(f))
425 log_file(td, f, FIO_LOG_CLOSE_FILE);
426
427 /*
428 * mark as closing, do real close when last io on it has completed
429 */
430 fio_file_set_closing(f);
431
432 disk_util_dec(f->du);
433 unlock_file_all(td, f);
434
435 return put_file(td, f);
436}
437
438int td_io_get_file_size(struct thread_data *td, struct fio_file *f)
439{
440 if (!td->io_ops->get_file_size)
441 return 0;
442
443 return td->io_ops->get_file_size(td, f);
444}
445
446static int do_sync_file_range(struct thread_data *td, struct fio_file *f)
447{
448 off64_t offset, nbytes;
449
450 offset = f->first_write;
451 nbytes = f->last_write - f->first_write;
452
453 if (!nbytes)
454 return 0;
455
456 return sync_file_range(f->fd, offset, nbytes, td->o.sync_file_range);
457}
458
459int do_io_u_sync(struct thread_data *td, struct io_u *io_u)
460{
461 int ret;
462
463 if (io_u->ddir == DDIR_SYNC) {
464 ret = fsync(io_u->file->fd);
465 } else if (io_u->ddir == DDIR_DATASYNC) {
466#ifdef FIO_HAVE_FDATASYNC
467 ret = fdatasync(io_u->file->fd);
468#else
469 ret = io_u->xfer_buflen;
470 io_u->error = EINVAL;
471#endif
472 } else if (io_u->ddir == DDIR_SYNC_FILE_RANGE)
473 ret = do_sync_file_range(td, io_u->file);
474 else {
475 ret = io_u->xfer_buflen;
476 io_u->error = EINVAL;
477 }
478
479 if (ret < 0)
480 io_u->error = errno;
481
482 return ret;
483}
484
485int do_io_u_trim(struct thread_data *td, struct io_u *io_u)
486{
487#ifndef FIO_HAVE_TRIM
488 io_u->error = EINVAL;
489 return 0;
490#else
491 struct fio_file *f = io_u->file;
492 int ret;
493
494 ret = os_trim(f->fd, io_u->offset, io_u->xfer_buflen);
495 if (!ret)
496 return io_u->xfer_buflen;;
497
498 io_u->error = ret;
499 return 0;
500#endif
501}