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