Merge branch 'div-by-zero' of https://github.com/vincentkfu/fio
[fio.git] / filesetup.c
index 94a025e6c1064e442dc18254d08e3f002dcae644..b45a58265a140700bfb96b4e6dd0930e4ed1a6c2 100644 (file)
@@ -14,6 +14,7 @@
 #include "hash.h"
 #include "lib/axmap.h"
 #include "rwlock.h"
+#include "zbd.h"
 
 #ifdef CONFIG_LINUX_FALLOCATE
 #include <linux/falloc.h>
@@ -94,6 +95,18 @@ static void fallocate_file(struct thread_data *td, struct fio_file *f)
                break;
                }
 #endif /* CONFIG_LINUX_FALLOCATE */
+       case FIO_FALLOCATE_TRUNCATE: {
+               int r;
+
+               dprint(FD_FILE, "ftruncate file %s size %llu\n",
+                               f->file_name,
+                               (unsigned long long) f->real_file_size);
+               r = ftruncate(f->fd, f->real_file_size);
+               if (r != 0)
+                       td_verror(td, errno, "ftruncate");
+
+               break;
+       }
        default:
                log_err("fio: unknown fallocate mode: %d\n", td->o.fallocate_mode);
                assert(0);
@@ -330,7 +343,7 @@ unsigned long long get_rand_file_size(struct thread_data *td)
 {
        unsigned long long ret, sized;
        uint64_t frand_max;
-       unsigned long r;
+       uint64_t r;
 
        frand_max = rand_max(&td->file_size_state);
        r = __rand(&td->file_size_state);
@@ -804,8 +817,7 @@ static unsigned long long get_fs_free_counts(struct thread_data *td)
                } else if (f->filetype != FIO_TYPE_FILE)
                        continue;
 
-               buf[255] = '\0';
-               strncpy(buf, f->file_name, 255);
+               snprintf(buf, ARRAY_SIZE(buf), "%s", f->file_name);
 
                if (stat(buf, &sb) < 0) {
                        if (errno != ENOENT)
@@ -828,7 +840,7 @@ static unsigned long long get_fs_free_counts(struct thread_data *td)
                        continue;
 
                fm = calloc(1, sizeof(*fm));
-               strncpy(fm->__base, buf, sizeof(fm->__base) - 1);
+               snprintf(fm->__base, ARRAY_SIZE(fm->__base), "%s", buf);
                fm->base = basename(fm->__base);
                fm->key = sb.st_dev;
                flist_add(&fm->list, &list);
@@ -852,16 +864,37 @@ 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)
 {
+       bool align = false;
        struct thread_options *o = &td->o;
        unsigned long long align_bs;
        unsigned long long offset;
+       unsigned long long increment;
 
        if (o->file_append && f->filetype == FIO_TYPE_FILE)
                return f->real_file_size;
 
+       if (o->offset_increment_percent) {
+               assert(!o->offset_increment);
+               increment = o->offset_increment_percent * f->real_file_size / 100;
+               align = true;
+       } else
+               increment = o->offset_increment;
+
        if (o->start_offset_percent > 0) {
+               /* calculate the raw offset */
+               offset = (f->real_file_size * o->start_offset_percent / 100) +
+                       (td->subjob_number * increment);
+
+               align = true;
+       } else {
+               /* start_offset_percent not set */
+               offset = o->start_offset +
+                               td->subjob_number * increment;
+       }
+
+       if (align) {
                /*
-                * if offset_align is provided, set initial offset
+                * if offset_align is provided, use it
                 */
                if (fio_option_is_set(o, start_offset_align)) {
                        align_bs = o->start_offset_align;
@@ -870,25 +903,44 @@ uint64_t get_start_offset(struct thread_data *td, struct fio_file *f)
                        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;
 }
 
+static bool create_work_dirs(struct thread_data *td, const char *fname)
+{
+       char path[PATH_MAX];
+       char *start, *end;
+
+       snprintf(path, PATH_MAX, "%s", fname);
+       start = path;
+
+       end = start;
+       while ((end = strchr(end, FIO_OS_PATH_SEPARATOR)) != NULL) {
+               if (end == start) {
+                       end++;
+                       continue;
+               }
+               *end = '\0';
+               errno = 0;
+               if (fio_mkdir(path, 0700) && errno != EEXIST) {
+                       log_err("fio: failed to create dir (%s): %d\n",
+                               start, errno);
+                       return false;
+               }
+               *end = FIO_OS_PATH_SEPARATOR;
+               end++;
+       }
+       td->flags |= TD_F_DIRS_CREATED;
+       return true;
+}
+
 /*
  * Open the files and setup files sizes, creating files if necessary.
  */
@@ -907,8 +959,13 @@ int setup_files(struct thread_data *td)
 
        old_state = td_bump_runstate(td, TD_SETTING_UP);
 
-       if (o->read_iolog_file)
-               goto done;
+       for_each_file(td, f, i) {
+               if (!td_ioengine_flagged(td, FIO_DISKLESSIO) &&
+                   strchr(f->file_name, FIO_OS_PATH_SEPARATOR) &&
+                   !(td->flags & TD_F_DIRS_CREATED) &&
+                   !create_work_dirs(td, f->file_name))
+                       goto err_out;
+       }
 
        /*
         * Find out physical size of files or devices for this thread,
@@ -925,6 +982,9 @@ int setup_files(struct thread_data *td)
        if (err)
                goto err_out;
 
+       if (o->read_iolog_file)
+               goto done;
+
        /*
         * check sizes. if the files/devices do not exist and the size
         * isn't passed to fio, abort.
@@ -1048,13 +1108,15 @@ int setup_files(struct thread_data *td)
                }
 
                if (f->filetype == FIO_TYPE_FILE &&
-                   (f->io_size + f->file_offset) > f->real_file_size &&
-                   !td_ioengine_flagged(td, FIO_DISKLESSIO)) {
-                       if (!o->create_on_open) {
+                   (f->io_size + f->file_offset) > f->real_file_size) {
+                       if (!td_ioengine_flagged(td, FIO_DISKLESSIO) &&
+                           !o->create_on_open) {
                                need_extend++;
                                extend_size += (f->io_size + f->file_offset);
                                fio_file_set_extend(f);
-                       } else
+                       } else if (!td_ioengine_flagged(td, FIO_DISKLESSIO) ||
+                                  (td_ioengine_flagged(td, FIO_DISKLESSIO) &&
+                                   td_ioengine_flagged(td, FIO_FAKEIO)))
                                f->real_file_size = f->io_size + f->file_offset;
                }
        }
@@ -1142,9 +1204,6 @@ int setup_files(struct thread_data *td)
        if (err)
                goto err_out;
 
-       if (!o->zone_size)
-               o->zone_size = o->size;
-
        /*
         * iolog already set the total io size, if we read back
         * stored entries.
@@ -1161,7 +1220,14 @@ done:
                td->done = 1;
 
        td_restore_runstate(td, old_state);
+
+       if (td->o.zone_mode == ZONE_MODE_ZBD) {
+               err = zbd_init(td);
+               if (err)
+                       goto err_out;
+       }
        return 0;
+
 err_offset:
        log_err("%s: you need to specify valid offset=\n", o->name);
 err_out:
@@ -1187,13 +1253,13 @@ bool pre_read_files(struct thread_data *td)
 static void __init_rand_distribution(struct thread_data *td, struct fio_file *f)
 {
        unsigned int range_size, seed;
-       unsigned long nranges;
+       uint64_t nranges;
        uint64_t fsize;
 
        range_size = min(td->o.min_bs[DDIR_READ], td->o.min_bs[DDIR_WRITE]);
        fsize = min(f->real_file_size, f->io_size);
 
-       nranges = (fsize + range_size - 1) / range_size;
+       nranges = (fsize + range_size - 1ULL) / range_size;
 
        seed = jhash(f->file_name, strlen(f->file_name), 0) * td->thread_number;
        if (!td->o.rand_repeatable)
@@ -1213,7 +1279,9 @@ static bool init_rand_distribution(struct thread_data *td)
        unsigned int i;
        int state;
 
-       if (td->o.random_distribution == FIO_RAND_DIST_RANDOM)
+       if (td->o.random_distribution == FIO_RAND_DIST_RANDOM ||
+           td->o.random_distribution == FIO_RAND_DIST_ZONED ||
+           td->o.random_distribution == FIO_RAND_DIST_ZONED_ABS)
                return false;
 
        state = td_bump_runstate(td, TD_SETTING_UP);
@@ -1276,19 +1344,25 @@ bool init_random_map(struct thread_data *td)
        for_each_file(td, f, i) {
                uint64_t fsize = min(f->real_file_size, f->io_size);
 
+               if (td->o.zone_mode == ZONE_MODE_STRIDED)
+                       fsize = td->o.zone_range;
+
                blocks = fsize / (unsigned long long) td->o.rw_min_bs;
 
                if (check_rand_gen_limits(td, f, blocks))
                        return false;
 
                if (td->o.random_generator == FIO_RAND_GEN_LFSR) {
-                       unsigned long seed;
+                       uint64_t seed;
 
                        seed = td->rand_seeds[FIO_RAND_BLOCK_OFF];
 
                        if (!lfsr_init(&f->lfsr, blocks, seed, 0)) {
                                fio_file_set_lfsr(f);
                                continue;
+                       } else {
+                               log_err("fio: failed initializing LFSR\n");
+                               return false;
                        }
                } else if (!td->o.norandommap) {
                        f->io_axmap = axmap_new(blocks);
@@ -1349,6 +1423,8 @@ void close_and_free_files(struct thread_data *td)
                        td_io_unlink_file(td, f);
                }
 
+               zbd_free_zone_info(f);
+
                if (use_free)
                        free(f->file_name);
                else
@@ -1510,42 +1586,6 @@ bool exists_and_not_regfile(const char *filename)
        return true;
 }
 
-static bool create_work_dirs(struct thread_data *td, const char *fname)
-{
-       char path[PATH_MAX];
-       char *start, *end;
-
-       if (td->o.directory) {
-               snprintf(path, PATH_MAX, "%s%c%s", td->o.directory,
-                        FIO_OS_PATH_SEPARATOR, fname);
-               start = strstr(path, fname);
-       } else {
-               snprintf(path, PATH_MAX, "%s", fname);
-               start = path;
-       }
-
-       end = start;
-       while ((end = strchr(end, FIO_OS_PATH_SEPARATOR)) != NULL) {
-               if (end == start)
-                       break;
-               *end = '\0';
-               errno = 0;
-#ifdef CONFIG_HAVE_MKDIR_TWO
-               if (mkdir(path, 0600) && errno != EEXIST) {
-#else
-               if (mkdir(path) && errno != EEXIST) {
-#endif
-                       log_err("fio: failed to create dir (%s): %d\n",
-                               start, errno);
-                       return false;
-               }
-               *end = FIO_OS_PATH_SEPARATOR;
-               end++;
-       }
-       td->flags |= TD_F_DIRS_CREATED;
-       return true;
-}
-
 int add_file(struct thread_data *td, const char *fname, int numjob, int inc)
 {
        int cur_files = td->files_index;
@@ -1561,11 +1601,6 @@ 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))
-               return 1;
-
        /* clean cloned siblings using existing files */
        if (numjob && is_already_allocated(file_name) &&
            !exists_and_not_regfile(fname))
@@ -1873,6 +1908,8 @@ void fio_file_reset(struct thread_data *td, struct fio_file *f)
                axmap_reset(f->io_axmap);
        else if (fio_file_lfsr(f))
                lfsr_reset(&f->lfsr, td->rand_seeds[FIO_RAND_BLOCK_OFF]);
+
+       zbd_file_reset(td, f);
 }
 
 bool fio_files_done(struct thread_data *td)