This partly revert 97bb54c9606c(add __load_ioengine() to separate ioengine loading...
[fio.git] / ioengines.c
index 54aa5a623aafd42541dd1affdd0498c6014dba80..d579682f4a051ce332b509b811e043c55b592c62 100644 (file)
@@ -9,7 +9,6 @@
  * generic io engine that could be used for other projects.
  *
  */
-#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
@@ -52,14 +51,12 @@ static bool check_engine_ops(struct ioengine_ops *ops)
 void unregister_ioengine(struct ioengine_ops *ops)
 {
        dprint(FD_IO, "ioengine %s unregistered\n", ops->name);
-       flist_del(&ops->list);
-       INIT_FLIST_HEAD(&ops->list);
+       flist_del_init(&ops->list);
 }
 
 void register_ioengine(struct ioengine_ops *ops)
 {
        dprint(FD_IO, "ioengine %s registered\n", ops->name);
-       INIT_FLIST_HEAD(&ops->list);
        flist_add_tail(&ops->list, &engine_list);
 }
 
@@ -123,15 +120,9 @@ static struct ioengine_ops *dlopen_ioengine(struct thread_data *td,
        return ops;
 }
 
-struct ioengine_ops *load_ioengine(struct thread_data *td)
+static struct ioengine_ops *__load_ioengine(const char *name)
 {
-       struct ioengine_ops *ops;
        char engine[64];
-       char *name;
-
-       name = td->o.ioengine_so_path ?: td->o.ioengine;
-
-       dprint(FD_IO, "load ioengine %s\n", name);
 
        engine[sizeof(engine) - 1] = '\0';
        strncpy(engine, name, sizeof(engine) - 1);
@@ -139,13 +130,42 @@ struct ioengine_ops *load_ioengine(struct thread_data *td)
        /*
         * linux libaio has alias names, so convert to what we want
         */
-       if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3))
+       if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3)) {
+               dprint(FD_IO, "converting ioengine name: %s -> libaio\n", name);
                strcpy(engine, "libaio");
+       }
+
+       dprint(FD_IO, "load ioengine %s\n", engine);
+       return find_ioengine(engine);
+}
 
-       ops = find_ioengine(engine);
+struct ioengine_ops *load_ioengine(struct thread_data *td)
+{
+       struct ioengine_ops *ops = NULL;
+       const char *name;
+
+       /*
+        * Use ->ioengine_so_path if an external ioengine path is specified.
+        * In this case, ->ioengine is "external" which also means the prefix
+        * for external ioengines "external:" is properly used.
+        */
+       name = td->o.ioengine_so_path ?: td->o.ioengine;
+
+       /*
+        * Try to load ->ioengine first, and if failed try to dlopen(3) either
+        * ->ioengine or ->ioengine_so_path.  This is redundant for an external
+        * ioengine with prefix, and also leaves the possibility of unexpected
+        * behavior (e.g. if the "external" ioengine exists), but we do this
+        * so as not to break job files not using the prefix.
+        */
+       ops = __load_ioengine(td->o.ioengine);
        if (!ops)
                ops = dlopen_ioengine(td, name);
 
+       /*
+        * If ops is NULL, we failed to load ->ioengine, and also failed to
+        * dlopen(3) either ->ioengine or ->ioengine_so_path as a path.
+        */
        if (!ops) {
                log_err("fio: engine %s not loadable\n", name);
                return NULL;
@@ -173,8 +193,10 @@ void free_ioengine(struct thread_data *td)
                td->eo = NULL;
        }
 
-       if (td->io_ops_dlhandle)
+       if (td->io_ops_dlhandle) {
                dlclose(td->io_ops_dlhandle);
+               td->io_ops_dlhandle = NULL;
+       }
 
        td->io_ops = NULL;
 }
@@ -201,7 +223,8 @@ int td_io_prep(struct thread_data *td, struct io_u *io_u)
        if (td->io_ops->prep) {
                int ret = td->io_ops->prep(td, io_u);
 
-               dprint(FD_IO, "->prep(%p)=%d\n", io_u, ret);
+               dprint(FD_IO, "prep: io_u %p: ret=%d\n", io_u, ret);
+
                if (ret)
                        unlock_file(td, io_u->file);
                return ret;
@@ -253,11 +276,11 @@ out:
        return r;
 }
 
-int td_io_queue(struct thread_data *td, struct io_u *io_u)
+enum fio_q_status td_io_queue(struct thread_data *td, struct io_u *io_u)
 {
        const enum fio_ddir ddir = acct_ddir(io_u);
        unsigned long buflen = io_u->xfer_buflen;
-       int ret;
+       enum fio_q_status ret;
 
        dprint_io_u(io_u, "queue");
        fio_ro_check(td, io_u);
@@ -288,8 +311,10 @@ int td_io_queue(struct thread_data *td, struct io_u *io_u)
        }
 
        if (ddir_rw(ddir)) {
-               td->io_issues[ddir]++;
-               td->io_issue_bytes[ddir] += buflen;
+               if (!(io_u->flags & IO_U_F_VER_LIST)) {
+                       td->io_issues[ddir]++;
+                       td->io_issue_bytes[ddir] += buflen;
+               }
                td->rate_io_issue_bytes[ddir] += buflen;
        }
 
@@ -321,8 +346,8 @@ int td_io_queue(struct thread_data *td, struct io_u *io_u)
            td->o.odirect) {
 
                log_info("fio: first direct IO errored. File system may not "
-                        "support direct IO, or iomem_align= is bad. Try "
-                        "setting direct=0.\n");
+                        "support direct IO, or iomem_align= is bad, or "
+                        "invalid block size. Try setting direct=0.\n");
        }
 
        if (!td->io_ops->commit || io_u->ddir == DDIR_TRIM) {
@@ -331,23 +356,18 @@ int td_io_queue(struct thread_data *td, struct io_u *io_u)
        }
 
        if (ret == FIO_Q_COMPLETED) {
-               if (ddir_rw(io_u->ddir)) {
+               if (ddir_rw(io_u->ddir) || ddir_sync(io_u->ddir)) {
                        io_u_mark_depth(td, 1);
                        td->ts.total_io_u[io_u->ddir]++;
                }
        } else if (ret == FIO_Q_QUEUED) {
-               int r;
-
                td->io_u_queued++;
 
-               if (ddir_rw(io_u->ddir))
+               if (ddir_rw(io_u->ddir) || ddir_sync(io_u->ddir))
                        td->ts.total_io_u[io_u->ddir]++;
 
-               if (td->io_u_queued >= td->o.iodepth_batch) {
-                       r = td_io_commit(td);
-                       if (r < 0)
-                               return r;
-               }
+               if (td->io_u_queued >= td->o.iodepth_batch)
+                       td_io_commit(td);
        }
 
        if (!td_ioengine_flagged(td, FIO_SYNCIO)) {
@@ -385,14 +405,14 @@ int td_io_init(struct thread_data *td)
        return ret;
 }
 
-int td_io_commit(struct thread_data *td)
+void td_io_commit(struct thread_data *td)
 {
        int ret;
 
        dprint(FD_IO, "calling ->commit(), depth %d\n", td->cur_depth);
 
        if (!td->cur_depth || !td->io_u_queued)
-               return 0;
+               return;
 
        io_u_mark_depth(td, td->io_u_queued);
 
@@ -407,14 +427,13 @@ int td_io_commit(struct thread_data *td)
         */
        td->io_u_in_flight += td->io_u_queued;
        td->io_u_queued = 0;
-
-       return 0;
 }
 
 int td_io_open_file(struct thread_data *td, struct fio_file *f)
 {
        assert(!fio_file_open(f));
        assert(f->fd == -1);
+       assert(td->io_ops->open_file);
 
        if (td->io_ops->open_file(td, f)) {
                if (td->error == EINVAL && td->o.odirect)
@@ -471,8 +490,8 @@ int td_io_open_file(struct thread_data *td, struct fio_file *f)
                }
 
                if (posix_fadvise(f->fd, f->file_offset, f->io_size, flags) < 0) {
-                       td_verror(td, errno, "fadvise");
-                       goto err;
+                       if (!fio_did_warn(FIO_WARN_FADVISE))
+                               log_err("fio: fadvise hint failed\n");
                }
        }
 #ifdef FIO_HAVE_WRITE_HINT
@@ -574,10 +593,10 @@ int fio_show_ioengine_help(const char *engine)
                sep++;
        }
 
-       memset(&td, 0, sizeof(td));
-
+       memset(&td, 0, sizeof(struct thread_data));
        td.o.ioengine = (char *)engine;
        io_ops = load_ioengine(&td);
+
        if (!io_ops) {
                log_info("IO engine %s not found\n", engine);
                return 1;
@@ -589,6 +608,5 @@ int fio_show_ioengine_help(const char *engine)
                log_info("IO engine %s has no options\n", io_ops->name);
 
        free_ioengine(&td);
-
        return ret;
 }