stat: fix alignment of the iops stats
[fio.git] / filesetup.c
index c9f2b5ff9111f7afd1be58446d702bfc2e123d7a..13079e493c50d34ea127e645ae5f250815fcc612 100644 (file)
@@ -159,11 +159,18 @@ static int extend_file(struct thread_data *td, struct fio_file *f)
                }
        }
 
-       b = malloc(td->o.max_bs[DDIR_WRITE]);
-
        left = f->real_file_size;
+       bs = td->o.max_bs[DDIR_WRITE];
+       if (bs > left)
+               bs = left;
+
+       b = malloc(bs);
+       if (!b) {
+               td_verror(td, errno, "malloc");
+               goto err;
+       }
+
        while (left && !td->terminate) {
-               bs = td->o.max_bs[DDIR_WRITE];
                if (bs > left)
                        bs = left;
 
@@ -228,7 +235,11 @@ static int pre_read_file(struct thread_data *td, struct fio_file *f)
        unsigned int bs;
        char *b;
 
-       if (td_ioengine_flagged(td, FIO_PIPEIO))
+       if (td_ioengine_flagged(td, FIO_PIPEIO) ||
+           td_ioengine_flagged(td, FIO_NOIO))
+               return 0;
+
+       if (f->filetype == FIO_TYPE_CHAR)
                return 0;
 
        if (!fio_file_open(f)) {
@@ -241,8 +252,17 @@ static int pre_read_file(struct thread_data *td, struct fio_file *f)
 
        old_runstate = td_bump_runstate(td, TD_PRE_READING);
 
+       left = f->io_size;
        bs = td->o.max_bs[DDIR_READ];
+       if (bs > left)
+               bs = left;
+
        b = malloc(bs);
+       if (!b) {
+               td_verror(td, errno, "malloc");
+               ret = 1;
+               goto error;
+       }
        memset(b, 0, bs);
 
        if (lseek(f->fd, f->file_offset, SEEK_SET) < 0) {
@@ -252,8 +272,6 @@ static int pre_read_file(struct thread_data *td, struct fio_file *f)
                goto error;
        }
 
-       left = f->io_size;
-
        while (left && !td->terminate) {
                if (bs > left)
                        bs = left;
@@ -815,12 +833,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;
 }
 
 /*
@@ -932,10 +980,11 @@ int setup_files(struct thread_data *td)
                        }
 
                        /*
-                        * We normally don't come here, but if the result is 0,
-                        * set it to the real file size. This could be size of
-                        * the existing one if it already exists, but otherwise
-                        * will be set to 0. A new file won't be created because
+                        * We normally don't come here for regular files, but
+                        * if the result is 0 for a regular file, set it to the
+                        * real file size. This could be size of the existing
+                        * one if it already exists, but otherwise will be set
+                        * to 0. A new file won't be created because
                         * ->io_size + ->file_offset equals ->real_file_size.
                         */
                        if (!f->io_size) {
@@ -967,7 +1016,14 @@ int setup_files(struct thread_data *td)
                        total_size = -1ULL;
                else {
                         if (o->size_percent) {
-                               f->io_size = (f->io_size * o->size_percent) / 100;
+                               uint64_t file_size;
+
+                               file_size = f->io_size + f->file_offset;
+                               f->io_size = (file_size *
+                                             o->size_percent) / 100;
+                               if (f->io_size > (file_size - f->file_offset))
+                                       f->io_size = file_size - f->file_offset;
+
                                f->io_size -= (f->io_size % td_min_bs(td));
                        }
                        total_size += f->io_size;
@@ -1103,10 +1159,11 @@ int pre_read_files(struct thread_data *td)
        dprint(FD_FILE, "pre_read files\n");
 
        for_each_file(td, f, i) {
-               pre_read_file(td, f);
+               if (pre_read_file(td, f))
+                       return -1;
        }
 
-       return 1;
+       return 0;
 }
 
 static int __init_rand_distribution(struct thread_data *td, struct fio_file *f)