X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=ioengines.c;h=3561bb4e6ed0da7289e1079a2d0ffbc7e8f9aa1d;hp=7e5a50cc81ba328875b605a55f1fde8c16122cec;hb=6308ef297145e73add65ba86bfdbeaf967957d1f;hpb=d9ed3e63e5280899e2e0bc7e55124c2a1acb30ca diff --git a/ioengines.c b/ioengines.c index 7e5a50cc..3561bb4e 100644 --- a/ioengines.c +++ b/ioengines.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include "fio.h" #include "diskutil.h" @@ -22,7 +24,7 @@ static FLIST_HEAD(engine_list); -static bool check_engine_ops(struct ioengine_ops *ops) +static bool check_engine_ops(struct thread_data *td, struct ioengine_ops *ops) { if (ops->version != FIO_IOOPS_VERSION) { log_err("bad ioops version %d (want %d)\n", ops->version, @@ -41,6 +43,16 @@ static bool check_engine_ops(struct ioengine_ops *ops) if (ops->flags & FIO_SYNCIO) return false; + /* + * async engines aren't reliable with offload + */ + if ((td->o.io_submit_mode == IO_MODE_OFFLOAD) && + (ops->flags & FIO_NO_OFFLOAD)) { + log_err("%s: can't be used with offloaded submit. Use a sync " + "engine\n", ops->name); + return true; + } + if (!ops->event || !ops->getevents) { log_err("%s: no event/getevents handler\n", ops->name); return true; @@ -75,19 +87,46 @@ static struct ioengine_ops *find_ioengine(const char *name) return NULL; } +#ifdef CONFIG_DYNAMIC_ENGINES +static void *dlopen_external(struct thread_data *td, const char *engine) +{ + char engine_path[PATH_MAX]; + void *dlhandle; + + sprintf(engine_path, "%s/fio-%s.so", FIO_EXT_ENG_DIR, engine); + + dprint(FD_IO, "dlopen external %s\n", engine_path); + dlhandle = dlopen(engine_path, RTLD_LAZY); + if (!dlhandle) + log_info("Engine %s not found; Either name is invalid, was not built, or fio-engine-%s package is missing.\n", + engine, engine); + + return dlhandle; +} +#else +#define dlopen_external(td, engine) (NULL) +#endif + static struct ioengine_ops *dlopen_ioengine(struct thread_data *td, const char *engine_lib) { struct ioengine_ops *ops; void *dlhandle; - dprint(FD_IO, "dload engine %s\n", engine_lib); + if (!strncmp(engine_lib, "linuxaio", 8) || + !strncmp(engine_lib, "aio", 3)) + engine_lib = "libaio"; + + dprint(FD_IO, "dlopen engine %s\n", engine_lib); dlerror(); dlhandle = dlopen(engine_lib, RTLD_LAZY); if (!dlhandle) { - td_vmsg(td, -1, dlerror(), "dlopen"); - return NULL; + dlhandle = dlopen_external(td, engine_lib); + if (!dlhandle) { + td_vmsg(td, -1, dlerror(), "dlopen"); + return NULL; + } } /* @@ -117,23 +156,19 @@ static struct ioengine_ops *dlopen_ioengine(struct thread_data *td, return NULL; } - td->io_ops_dlhandle = dlhandle; + ops->dlhandle = dlhandle; return ops; } -static struct ioengine_ops *__load_ioengine(const char *name) +static struct ioengine_ops *__load_ioengine(const char *engine) { - char engine[64]; - - engine[sizeof(engine) - 1] = '\0'; - strncpy(engine, name, sizeof(engine) - 1); - /* * linux libaio has alias names, so convert to what we want */ - if (!strncmp(engine, "linuxaio", 8)) { - dprint(FD_IO, "converting ioengine name: %s -> libaio\n", name); - strcpy(engine, "libaio"); + if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3)) { + dprint(FD_IO, "converting ioengine name: %s -> libaio\n", + engine); + engine = "libaio"; } dprint(FD_IO, "load ioengine %s\n", engine); @@ -160,7 +195,9 @@ struct ioengine_ops *load_ioengine(struct thread_data *td) * so as not to break job files not using the prefix. */ ops = __load_ioengine(td->o.ioengine); - if (!ops) + + /* We do re-dlopen existing handles, for reference counting */ + if (!ops || ops->dlhandle) ops = dlopen_ioengine(td, name); /* @@ -175,7 +212,7 @@ struct ioengine_ops *load_ioengine(struct thread_data *td) /* * Check that the required methods are there. */ - if (check_engine_ops(ops)) + if (check_engine_ops(td, ops)) return NULL; return ops; @@ -194,9 +231,10 @@ void free_ioengine(struct thread_data *td) td->eo = NULL; } - if (td->io_ops_dlhandle) { - dlclose(td->io_ops_dlhandle); - td->io_ops_dlhandle = NULL; + if (td->io_ops->dlhandle) { + dprint(FD_IO, "dlclose ioengine %s\n", td->io_ops->name); + dlclose(td->io_ops->dlhandle); + td->io_ops->dlhandle = NULL; } td->io_ops = NULL; @@ -295,8 +333,10 @@ enum fio_q_status td_io_queue(struct thread_data *td, struct io_u *io_u) * started the overlap check because the IO_U_F_FLIGHT * flag is now set */ - if (td_offload_overlap(td)) - pthread_mutex_unlock(&overlap_check); + if (td_offload_overlap(td)) { + int res = pthread_mutex_unlock(&overlap_check); + assert(res == 0); + } assert(fio_file_open(io_u->file)); @@ -308,7 +348,9 @@ enum fio_q_status td_io_queue(struct thread_data *td, struct io_u *io_u) io_u->error = 0; io_u->resid = 0; - if (td_ioengine_flagged(td, FIO_SYNCIO)) { + if (td_ioengine_flagged(td, FIO_SYNCIO) || + (td_ioengine_flagged(td, FIO_ASYNCIO_SYNC_TRIM) && + io_u->ddir == DDIR_TRIM)) { if (fio_fill_issue_time(td)) fio_gettime(&io_u->issue_time, NULL); @@ -320,6 +362,7 @@ enum fio_q_status td_io_queue(struct thread_data *td, struct io_u *io_u) sizeof(io_u->issue_time)); } + if (ddir_rw(ddir)) { if (!(io_u->flags & IO_U_F_VER_LIST)) { td->io_issues[ddir]++; @@ -329,7 +372,7 @@ enum fio_q_status td_io_queue(struct thread_data *td, struct io_u *io_u) } ret = td->io_ops->queue(td, io_u); - zbd_queue_io_u(io_u, ret); + zbd_queue_io_u(td, io_u, ret); unlock_file(td, io_u->file); @@ -371,25 +414,28 @@ enum fio_q_status td_io_queue(struct thread_data *td, struct io_u *io_u) if (!td->io_ops->commit) { io_u_mark_submit(td, 1); io_u_mark_complete(td, 1); - zbd_put_io_u(io_u); } if (ret == FIO_Q_COMPLETED) { - if (ddir_rw(io_u->ddir) || ddir_sync(io_u->ddir)) { + if (ddir_rw(io_u->ddir) || + (ddir_sync(io_u->ddir) && td->runstate != TD_FSYNCING)) { io_u_mark_depth(td, 1); td->ts.total_io_u[io_u->ddir]++; } } else if (ret == FIO_Q_QUEUED) { td->io_u_queued++; - if (ddir_rw(io_u->ddir) || ddir_sync(io_u->ddir)) + if (ddir_rw(io_u->ddir) || + (ddir_sync(io_u->ddir) && td->runstate != TD_FSYNCING)) td->ts.total_io_u[io_u->ddir]++; if (td->io_u_queued >= td->o.iodepth_batch) td_io_commit(td); } - if (!td_ioengine_flagged(td, FIO_SYNCIO)) { + if (!td_ioengine_flagged(td, FIO_SYNCIO) && + (!td_ioengine_flagged(td, FIO_ASYNCIO_SYNC_TRIM) || + io_u->ddir != DDIR_TRIM)) { if (fio_fill_issue_time(td)) fio_gettime(&io_u->issue_time, NULL); @@ -593,6 +639,34 @@ int td_io_get_file_size(struct thread_data *td, struct fio_file *f) return td->io_ops->get_file_size(td, f); } +#ifdef CONFIG_DYNAMIC_ENGINES +/* Load all dynamic engines in FIO_EXT_ENG_DIR for enghelp command */ +static void +fio_load_dynamic_engines(struct thread_data *td) +{ + DIR *dirhandle = NULL; + struct dirent *dirent = NULL; + char engine_path[PATH_MAX]; + + dirhandle = opendir(FIO_EXT_ENG_DIR); + if (!dirhandle) + return; + + while ((dirent = readdir(dirhandle)) != NULL) { + if (!strcmp(dirent->d_name, ".") || + !strcmp(dirent->d_name, "..")) + continue; + + sprintf(engine_path, "%s/%s", FIO_EXT_ENG_DIR, dirent->d_name); + dlopen_ioengine(td, engine_path); + } + + closedir(dirhandle); +} +#else +#define fio_load_dynamic_engines(td) do { } while (0) +#endif + int fio_show_ioengine_help(const char *engine) { struct flist_head *entry; @@ -601,8 +675,11 @@ int fio_show_ioengine_help(const char *engine) char *sep; int ret = 1; + memset(&td, 0, sizeof(struct thread_data)); + if (!engine || !*engine) { log_info("Available IO engines:\n"); + fio_load_dynamic_engines(&td); flist_for_each(entry, &engine_list) { io_ops = flist_entry(entry, struct ioengine_ops, list); log_info("\t%s\n", io_ops->name); @@ -615,7 +692,6 @@ int fio_show_ioengine_help(const char *engine) sep++; } - memset(&td, 0, sizeof(struct thread_data)); td.o.ioengine = (char *)engine; io_ops = load_ioengine(&td);