Retry bdev cache invalidation for EAGAIN errors
[fio.git] / filesetup.c
index cf8ae94c86b83c516411396b336f720e5ab03931..e1dedcd8bdec6d074d37f2ea07d6bde45007f9e5 100644 (file)
@@ -267,11 +267,13 @@ error:
 static unsigned long long get_rand_file_size(struct thread_data *td)
 {
        unsigned long long ret, sized;
+       uint64_t frand_max;
        unsigned long r;
 
+       frand_max = rand_max(&td->file_size_state);
        r = __rand(&td->file_size_state);
        sized = td->o.file_size_high - td->o.file_size_low;
-       ret = (unsigned long long) ((double) sized * (r / (FRAND_MAX + 1.0)));
+       ret = (unsigned long long) ((double) sized * (r / (frand_max + 1.0)));
        ret += td->o.file_size_low;
        ret -= (ret % td->o.rw_min_bs);
        return ret;
@@ -411,7 +413,19 @@ static int __file_invalidate_cache(struct thread_data *td, struct fio_file *f,
        else if (f->filetype == FIO_TYPE_FILE)
                ret = posix_fadvise(f->fd, off, len, POSIX_FADV_DONTNEED);
        else if (f->filetype == FIO_TYPE_BD) {
+               int retry_count = 0;
+
                ret = blockdev_invalidate_cache(f);
+               while (ret < 0 && errno == EAGAIN && retry_count++ < 25) {
+                       /*
+                        * Linux multipath devices reject ioctl while
+                        * the maps are being updated. That window can
+                        * last tens of milliseconds; we'll try up to
+                        * a quarter of a second.
+                        */
+                       usleep(10000);
+                       ret = blockdev_invalidate_cache(f);
+               }
                if (ret < 0 && errno == EACCES && geteuid()) {
                        if (!root_warn) {
                                log_err("fio: only root may flush block "
@@ -730,7 +744,7 @@ static unsigned long long get_fs_free_counts(struct thread_data *td)
                fm = flist_entry(n, struct fio_mount, list);
                flist_del(&fm->list);
 
-               sz = get_fs_size(fm->base);
+               sz = get_fs_free_size(fm->base);
                if (sz && sz != -1ULL)
                        ret += sz;
 
@@ -1049,6 +1063,43 @@ static int init_rand_distribution(struct thread_data *td)
        return 1;
 }
 
+/*
+ * Check if the number of blocks exceeds the randomness capability of
+ * the selected generator. Tausworthe is 32-bit, the others are fullly
+ * 64-bit capable.
+ */
+static int check_rand_gen_limits(struct thread_data *td, struct fio_file *f,
+                                uint64_t blocks)
+{
+       if (blocks <= FRAND32_MAX)
+               return 0;
+       if (td->o.random_generator != FIO_RAND_GEN_TAUSWORTHE)
+               return 0;
+
+       /*
+        * If the user hasn't specified a random generator, switch
+        * to tausworthe64 with informational warning. If the user did
+        * specify one, just warn.
+        */
+       log_info("fio: file %s exceeds 32-bit tausworthe random generator.\n",
+                       f->file_name);
+
+       if (!fio_option_is_set(&td->o, random_generator)) {
+               log_info("fio: Switching to tausworthe64. Use the "
+                        "random_generator= option to get rid of this "
+                        " warning.\n");
+               td->o.random_generator = FIO_RAND_GEN_TAUSWORTHE64;
+               return 0;
+       }
+
+       /*
+        * Just make this information to avoid breaking scripts.
+        */
+       log_info("fio: Use the random_generator= option to switch to lfsr or "
+                        "tausworthe64.\n");
+       return 0;
+}
+
 int init_random_map(struct thread_data *td)
 {
        unsigned long long blocks;
@@ -1065,6 +1116,9 @@ int init_random_map(struct thread_data *td)
 
                blocks = fsize / (unsigned long long) td->o.rw_min_bs;
 
+               if (check_rand_gen_limits(td, f, blocks))
+                       return 1;
+
                if (td->o.random_generator == FIO_RAND_GEN_LFSR) {
                        unsigned long seed;