create subdirs if specified in the filename_format
[fio.git] / filesetup.c
index 38ad9edc6e206fd919309087bf4590dd76231ea1..b390caa295263e1327d56cc250dee84485edf46a 100644 (file)
@@ -67,7 +67,7 @@ static void fallocate_file(struct thread_data *td, struct fio_file *f)
        switch (td->o.fallocate_mode) {
        case FIO_FALLOCATE_NATIVE:
                r = native_fallocate(td, f);
-               if (r != 0)
+               if (r != 0 && errno != ENOSYS)
                        log_err("fio: native_fallocate call failed: %s\n",
                                        strerror(errno));
                break;
@@ -100,7 +100,6 @@ static void fallocate_file(struct thread_data *td, struct fio_file *f)
                log_err("fio: unknown fallocate mode: %d\n", td->o.fallocate_mode);
                assert(0);
        }
-
 }
 
 /*
@@ -528,8 +527,6 @@ static int __file_invalidate_cache(struct thread_data *td, struct fio_file *f,
                }
                if (ret < 0)
                        errval = errno;
-               else if (ret) /* probably not supported */
-                       errval = ret;
        } else if (f->filetype == FIO_TYPE_CHAR ||
                   f->filetype == FIO_TYPE_PIPE) {
                dprint(FD_IO, "invalidate not supported %s\n", f->file_name);
@@ -1345,6 +1342,7 @@ void close_and_free_files(struct thread_data *td)
 {
        struct fio_file *f;
        unsigned int i;
+       bool use_free = td_ioengine_flagged(td, FIO_NOFILEHASH);
 
        dprint(FD_FILE, "close files\n");
 
@@ -1364,13 +1362,19 @@ void close_and_free_files(struct thread_data *td)
                        td_io_unlink_file(td, f);
                }
 
-               sfree(f->file_name);
+               if (use_free)
+                       free(f->file_name);
+               else
+                       sfree(f->file_name);
                f->file_name = NULL;
                if (fio_file_axmap(f)) {
                        axmap_free(f->io_axmap);
                        f->io_axmap = NULL;
                }
-               sfree(f);
+               if (use_free)
+                       free(f);
+               else
+                       sfree(f);
        }
 
        td->o.filename = NULL;
@@ -1484,7 +1488,10 @@ static struct fio_file *alloc_new_file(struct thread_data *td)
 {
        struct fio_file *f;
 
-       f = smalloc(sizeof(*f));
+       if (td_ioengine_flagged(td, FIO_NOFILEHASH))
+               f = calloc(1, sizeof(*f));
+       else
+               f = smalloc(sizeof(*f));
        if (!f) {
                assert(0);
                return NULL;
@@ -1516,6 +1523,45 @@ bool exists_and_not_regfile(const char *filename)
        return true;
 }
 
+static void create_work_dirs(struct thread_data *td, const char *fname)
+{
+       char path[PATH_MAX];
+       char *start, *end;
+       int dirfd;
+       bool need_close = true;
+
+       if (td->o.directory) {
+               dirfd = open(td->o.directory, O_DIRECTORY | O_RDONLY);
+               if (dirfd < 0) {
+                       log_err("fio: failed to open dir (%s): %d\n",
+                               td->o.directory, errno);
+                       assert(0);
+               }
+       } else {
+               dirfd = AT_FDCWD;
+               need_close = false;
+       }
+
+       memcpy(path, fname, PATH_MAX);
+       start = end = path;
+       while ((end = strchr(end, FIO_OS_PATH_SEPARATOR)) != NULL) {
+               if (end == start)
+                       break;
+               *end = '\0';
+               errno = 0;
+               if (mkdirat(dirfd, start, 0600) && errno != EEXIST) {
+                       log_err("fio: failed to create dir (%s): %d\n",
+                               start, errno);
+                       assert(0);
+               }
+               *end = FIO_OS_PATH_SEPARATOR;
+               end++;
+       }
+       if (need_close)
+               close(dirfd);
+       td->flags |= TD_F_DIRS_CREATED;
+}
+
 int add_file(struct thread_data *td, const char *fname, int numjob, int inc)
 {
        int cur_files = td->files_index;
@@ -1531,6 +1577,10 @@ int add_file(struct thread_data *td, const char *fname, int numjob, int inc)
 
        sprintf(file_name + len, "%s", fname);
 
+       if (strchr(fname, FIO_OS_PATH_SEPARATOR) &&
+           !(td->flags & TD_F_DIRS_CREATED))
+               create_work_dirs(td, fname);
+
        /* clean cloned siblings using existing files */
        if (numjob && is_already_allocated(file_name) &&
            !exists_and_not_regfile(fname))
@@ -1567,7 +1617,10 @@ int add_file(struct thread_data *td, const char *fname, int numjob, int inc)
        if (td->io_ops && td_ioengine_flagged(td, FIO_DISKLESSIO))
                f->real_file_size = -1ULL;
 
-       f->file_name = smalloc_strdup(file_name);
+       if (td_ioengine_flagged(td, FIO_NOFILEHASH))
+               f->file_name = strdup(file_name);
+       else
+               f->file_name = smalloc_strdup(file_name);
        if (!f->file_name)
                assert(0);
 
@@ -1591,7 +1644,8 @@ int add_file(struct thread_data *td, const char *fname, int numjob, int inc)
        if (f->filetype == FIO_TYPE_FILE)
                td->nr_normal_files++;
 
-       set_already_allocated(file_name);
+       if (td->o.numjobs > 1)
+               set_already_allocated(file_name);
 
        if (inc)
                td->o.nr_files++;
@@ -1714,7 +1768,7 @@ static int recurse_dir(struct thread_data *td, const char *dirname)
                if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
                        continue;
 
-               sprintf(full_path, "%s%s%s", dirname, FIO_OS_PATH_SEPARATOR, dir->d_name);
+               sprintf(full_path, "%s%c%s", dirname, FIO_OS_PATH_SEPARATOR, dir->d_name);
 
                if (lstat(full_path, &sb) == -1) {
                        if (errno != ENOENT) {
@@ -1771,7 +1825,10 @@ void dup_files(struct thread_data *td, struct thread_data *org)
                __f = alloc_new_file(td);
 
                if (f->file_name) {
-                       __f->file_name = smalloc_strdup(f->file_name);
+                       if (td_ioengine_flagged(td, FIO_NOFILEHASH))
+                               __f->file_name = strdup(f->file_name);
+                       else
+                               __f->file_name = smalloc_strdup(f->file_name);
                        if (!__f->file_name)
                                assert(0);
 
@@ -1846,3 +1903,32 @@ void filesetup_mem_free(void)
 {
        free_already_allocated();
 }
+
+/*
+ * This function is for platforms which support direct I/O but not O_DIRECT.
+ */
+int fio_set_directio(struct thread_data *td, struct fio_file *f)
+{
+#ifdef FIO_OS_DIRECTIO
+       int ret = fio_set_odirect(f);
+
+       if (ret) {
+               td_verror(td, ret, "fio_set_directio");
+#if defined(__sun__)
+               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");
+               }
+#else
+               log_err("fio: the file system does not seem to support direct IO\n");
+#endif
+               return -1;
+       }
+
+       return 0;
+#else
+       log_err("fio: direct IO is not supported on this host operating system\n");
+       return -1;
+#endif
+}