convert FIO_OS_PATH_SEPARATOR to a character
[fio.git] / filesetup.c
index 8a0968d66debfe329e816ee0f5f92abc749f018e..a7bbcede08d199cb7660a2771f4b715600ca8af3 100644 (file)
@@ -38,12 +38,76 @@ static inline void clear_error(struct thread_data *td)
        td->verror[0] = '\0';
 }
 
+static inline int native_fallocate(struct thread_data *td, struct fio_file *f)
+{
+       bool success;
+
+       success = fio_fallocate(f, 0, f->real_file_size);
+       dprint(FD_FILE, "native fallocate of file %s size %llu was "
+                       "%ssuccessful\n", f->file_name,
+                       (unsigned long long) f->real_file_size,
+                       !success ? "un": "");
+
+       if (success)
+               return 0;
+
+       if (errno == ENOSYS)
+               dprint(FD_FILE, "native fallocate is not implemented\n");
+
+       return -1;
+}
+
+static void fallocate_file(struct thread_data *td, struct fio_file *f)
+{
+       int r;
+
+       if (td->o.fill_device)
+               return;
+
+       switch (td->o.fallocate_mode) {
+       case FIO_FALLOCATE_NATIVE:
+               r = native_fallocate(td, f);
+               if (r != 0 && errno != ENOSYS)
+                       log_err("fio: native_fallocate call failed: %s\n",
+                                       strerror(errno));
+               break;
+       case FIO_FALLOCATE_NONE:
+               break;
+#ifdef CONFIG_POSIX_FALLOCATE
+       case FIO_FALLOCATE_POSIX:
+               dprint(FD_FILE, "posix_fallocate file %s size %llu\n",
+                                f->file_name,
+                                (unsigned long long) f->real_file_size);
+
+               r = posix_fallocate(f->fd, 0, f->real_file_size);
+               if (r > 0)
+                       log_err("fio: posix_fallocate fails: %s\n", strerror(r));
+               break;
+#endif /* CONFIG_POSIX_FALLOCATE */
+#ifdef CONFIG_LINUX_FALLOCATE
+       case FIO_FALLOCATE_KEEP_SIZE:
+               dprint(FD_FILE, "fallocate(FALLOC_FL_KEEP_SIZE) "
+                               "file %s size %llu\n", f->file_name,
+                               (unsigned long long) f->real_file_size);
+
+               r = fallocate(f->fd, FALLOC_FL_KEEP_SIZE, 0, f->real_file_size);
+               if (r != 0)
+                       td_verror(td, errno, "fallocate");
+
+               break;
+#endif /* CONFIG_LINUX_FALLOCATE */
+       default:
+               log_err("fio: unknown fallocate mode: %d\n", td->o.fallocate_mode);
+               assert(0);
+       }
+}
+
 /*
  * Leaves f->fd open on success, caller must close
  */
 static int extend_file(struct thread_data *td, struct fio_file *f)
 {
-       int r, new_layout = 0, unlink_file = 0, flags;
+       int new_layout = 0, unlink_file = 0, flags;
        unsigned long long left;
        unsigned int bs;
        char *b = NULL;
@@ -100,43 +164,7 @@ static int extend_file(struct thread_data *td, struct fio_file *f)
                return 1;
        }
 
-#ifdef CONFIG_POSIX_FALLOCATE
-       if (!td->o.fill_device) {
-               switch (td->o.fallocate_mode) {
-               case FIO_FALLOCATE_NONE:
-                       break;
-               case FIO_FALLOCATE_POSIX:
-                       dprint(FD_FILE, "posix_fallocate file %s size %llu\n",
-                                f->file_name,
-                                (unsigned long long) f->real_file_size);
-
-                       r = posix_fallocate(f->fd, 0, f->real_file_size);
-                       if (r > 0) {
-                               log_err("fio: posix_fallocate fails: %s\n",
-                                               strerror(r));
-                       }
-                       break;
-#ifdef CONFIG_LINUX_FALLOCATE
-               case FIO_FALLOCATE_KEEP_SIZE:
-                       dprint(FD_FILE,
-                               "fallocate(FALLOC_FL_KEEP_SIZE) "
-                               "file %s size %llu\n", f->file_name,
-                               (unsigned long long) f->real_file_size);
-
-                       r = fallocate(f->fd, FALLOC_FL_KEEP_SIZE, 0,
-                                       f->real_file_size);
-                       if (r != 0)
-                               td_verror(td, errno, "fallocate");
-
-                       break;
-#endif /* CONFIG_LINUX_FALLOCATE */
-               default:
-                       log_err("fio: unknown fallocate mode: %d\n",
-                               td->o.fallocate_mode);
-                       assert(0);
-               }
-       }
-#endif /* CONFIG_POSIX_FALLOCATE */
+       fallocate_file(td, f);
 
        /*
         * If our jobs don't require regular files initially, we're done.
@@ -171,6 +199,8 @@ static int extend_file(struct thread_data *td, struct fio_file *f)
        }
 
        while (left && !td->terminate) {
+               ssize_t r;
+
                if (bs > left)
                        bs = left;
 
@@ -497,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);
@@ -833,12 +861,42 @@ static unsigned long long get_fs_free_counts(struct thread_data *td)
 uint64_t get_start_offset(struct thread_data *td, struct fio_file *f)
 {
        struct thread_options *o = &td->o;
+       unsigned long long align_bs;
+       unsigned long long offset;
 
        if (o->file_append && f->filetype == FIO_TYPE_FILE)
                return f->real_file_size;
 
-       return td->o.start_offset +
-               td->subjob_number * td->o.offset_increment;
+       if (o->start_offset_percent > 0) {
+               /*
+                * if blockalign is provided, find the min across read, write,
+                * and trim
+                */
+               if (fio_option_is_set(o, ba)) {
+                       align_bs = (unsigned long long) min(o->ba[DDIR_READ], o->ba[DDIR_WRITE]);
+                       align_bs = min((unsigned long long) o->ba[DDIR_TRIM], align_bs);
+               } else {
+                       /* else take the minimum block size */
+                       align_bs = td_min_bs(td);
+               }
+
+               /* calculate the raw offset */
+               offset = (f->real_file_size * o->start_offset_percent / 100) +
+                       (td->subjob_number * o->offset_increment);
+
+               /*
+                * block align the offset at the next available boundary at
+                * ceiling(offset / align_bs) * align_bs
+                */
+               offset = (offset / align_bs + (offset % align_bs != 0)) * align_bs;
+
+       } else {
+               /* start_offset_percent not set */
+               offset = o->start_offset +
+                               td->subjob_number * o->offset_increment;
+       }
+
+       return offset;
 }
 
 /*
@@ -1284,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");
 
@@ -1303,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;
@@ -1423,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;
@@ -1506,7 +1574,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);
 
@@ -1530,7 +1601,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++;
@@ -1653,7 +1725,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) {
@@ -1710,7 +1782,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);
 
@@ -1785,3 +1860,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
+}