X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=ioengines.c;h=965581aa4157c8594fbc20735a8ac36f438d24b7;hp=c90a2ca5bde30e75dec5261130b6b77fb6a1999b;hb=ae626d4ead6416adf464cf209cdf3e8b85d58190;hpb=e2c75fc49d028736eccea411fcb34b1d1b9efd36 diff --git a/ioengines.c b/ioengines.c index c90a2ca5..965581aa 100644 --- a/ioengines.c +++ b/ioengines.c @@ -52,14 +52,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,26 +121,52 @@ static struct ioengine_ops *dlopen_ioengine(struct thread_data *td, return ops; } -struct ioengine_ops *load_ioengine(struct thread_data *td, const char *name) +static struct ioengine_ops *__load_ioengine(const char *name) { - struct ioengine_ops *ops; char engine[64]; - dprint(FD_IO, "load ioengine %s\n", name); - 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) || !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; @@ -170,8 +194,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; } @@ -198,7 +224,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; @@ -281,12 +308,14 @@ int td_io_queue(struct thread_data *td, struct io_u *io_u) */ if (td->o.read_iolog_file) memcpy(&td->last_issue, &io_u->issue_time, - sizeof(struct timeval)); + sizeof(io_u->issue_time)); } 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; } @@ -318,8 +347,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) { @@ -328,7 +357,7 @@ 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]++; } @@ -337,7 +366,7 @@ int td_io_queue(struct thread_data *td, struct io_u *io_u) 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) { @@ -356,7 +385,7 @@ int td_io_queue(struct thread_data *td, struct io_u *io_u) */ if (td->o.read_iolog_file) memcpy(&td->last_issue, &io_u->issue_time, - sizeof(struct timeval)); + sizeof(io_u->issue_time)); } return ret; @@ -412,6 +441,7 @@ 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) @@ -468,43 +498,36 @@ 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_STREAMID - if (td->o.fadvise_stream && +#ifdef FIO_HAVE_WRITE_HINT + if (fio_option_is_set(&td->o, write_hint) && (f->filetype == FIO_TYPE_BLOCK || f->filetype == FIO_TYPE_FILE)) { - off_t stream = td->o.fadvise_stream; - - if (posix_fadvise(f->fd, stream, f->io_size, POSIX_FADV_STREAMID) < 0) { - td_verror(td, errno, "fadvise streamid"); - goto err; - } - } -#endif - -#ifdef FIO_OS_DIRECTIO - /* - * Some OS's have a distinct call to mark the file non-buffered, - * instead of using O_DIRECT (Solaris) - */ - if (td->o.odirect) { - int ret = fio_set_odirect(f->fd); + uint64_t hint = td->o.write_hint; + int cmd; - if (ret) { - td_verror(td, ret, "fio_set_odirect"); - if (ret == ENOTTY) { /* ENOTTY suggests RAW device or ZFS */ - log_err("fio: doing directIO to RAW devices or ZFS not supported\n"); - } else { - log_err("fio: the file system does not seem to support direct IO\n"); - } + /* + * For direct IO, we just need/want to set the hint on + * the file descriptor. For buffered IO, we need to set + * it on the inode. + */ + if (td->o.odirect) + cmd = F_SET_FILE_RW_HINT; + else + cmd = F_SET_RW_HINT; + if (fcntl(f->fd, cmd, &hint) < 0) { + td_verror(td, errno, "fcntl write hint"); goto err; } } #endif + if (td->o.odirect && !OS_O_DIRECT && fio_set_directio(td, f)) + goto err; + done: log_file(td, f, FIO_LOG_OPEN_FILE); return 0; @@ -559,7 +582,6 @@ int td_io_get_file_size(struct thread_data *td, struct fio_file *f) int fio_show_ioengine_help(const char *engine) { struct flist_head *entry; - struct thread_data td; struct ioengine_ops *io_ops; char *sep; int ret = 1; @@ -578,9 +600,7 @@ int fio_show_ioengine_help(const char *engine) sep++; } - memset(&td, 0, sizeof(td)); - - io_ops = load_ioengine(&td, engine); + io_ops = __load_ioengine(engine); if (!io_ops) { log_info("IO engine %s not found\n", engine); return 1; @@ -591,7 +611,5 @@ int fio_show_ioengine_help(const char *engine) else log_info("IO engine %s has no options\n", io_ops->name); - free_ioengine(&td); - return ret; }