filesetup: add native fallocate
authorSitsofe Wheeler <sitsofe@yahoo.com>
Fri, 30 Jun 2017 06:32:19 +0000 (07:32 +0100)
committerSitsofe Wheeler <sitsofe@yahoo.com>
Mon, 3 Jul 2017 21:38:20 +0000 (22:38 +0100)
- Implement a native fallocate mode that only logs an error (if it's
  implemented) and falls back to the same behaviour as fallocate=none if
  it fails
- Add a native OSX and Linux fallocate
- Update man page and HOWTO with new native and defaults

v4:
- Update commit message
- Update man page and HOWTO

Fixes https://github.com/axboe/fio/issues/22 - we now print a message if
fallocate fails which gives the user a hint that behaviour might differ
from other case along with a workaround suggestion (fallocate=none).

Fixes https://github.com/axboe/fio/issues/376 - we now have
fallocate=none fallback behaviour if native fallocate fails. On at least
glibc platforms, posix_fallocate emulates fallocate if the
platform/filesystem doesn't support it (see
https://www.gnu.org/software/libc/manual/html_node/Storage-Allocation.html#index-posix_005ffallocate
for some of the caveats) resulting in strange layout performance thus
making it less attractive than fallocate=none behaviour for fio.

Signed-off-by: Sitsofe Wheeler <sitsofe@yahoo.com>
HOWTO
file.h
filesetup.c
fio.1
options.c
os/os-linux.h
os/os-mac.h
os/os.h

diff --git a/HOWTO b/HOWTO
index 6e53cff81fec4cf4f4b5533a2c9cd6ccdb2793c7..cf46349233f095bf5c786e4fed3bad5dc12ec8a3 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -1049,6 +1049,10 @@ I/O type
                **none**
                        Do not pre-allocate space.
 
+               **native**
+                       Use a platform's native pre-allocation call but fall back to
+                       **none** behavior if it fails/is not implemented.
+
                **posix**
                        Pre-allocate via :manpage:`posix_fallocate(3)`.
 
@@ -1063,8 +1067,9 @@ I/O type
                        Backward-compatible alias for **posix**.
 
        May not be available on all supported platforms. **keep** is only available
-       on Linux. If using ZFS on Solaris this must be set to **none** because ZFS
-       doesn't support it. Default: **posix**.
+       on Linux. If using ZFS on Solaris this cannot be set to **posix**
+       because ZFS doesn't support pre-allocation. Default: **native** if any
+       pre-allocation methods are available, **none** if not.
 
 .. option:: fadvise_hint=str
 
diff --git a/file.h b/file.h
index 9801bb584007558da4d7c2a17e78f50133c22fb6..84daa5f66b74a1c871796dd20c1f3375e0eacf89 100644 (file)
--- a/file.h
+++ b/file.h
@@ -63,6 +63,7 @@ enum fio_fallocate_mode {
        FIO_FALLOCATE_NONE      = 1,
        FIO_FALLOCATE_POSIX     = 2,
        FIO_FALLOCATE_KEEP_SIZE = 3,
+       FIO_FALLOCATE_NATIVE    = 4,
 };
 
 /*
index f3e3865ef20a788e49a1f14f98cbdd201f0735e5..38ad9edc6e206fd919309087bf4590dd76231ea1 100644 (file)
@@ -38,6 +38,25 @@ 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;
@@ -45,10 +64,16 @@ static void fallocate_file(struct thread_data *td, struct fio_file *f)
        if (td->o.fill_device)
                return;
 
-#ifdef CONFIG_POSIX_FALLOCATE
        switch (td->o.fallocate_mode) {
+       case FIO_FALLOCATE_NATIVE:
+               r = native_fallocate(td, f);
+               if (r != 0)
+                       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,
@@ -58,6 +83,7 @@ static void fallocate_file(struct thread_data *td, struct fio_file *f)
                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) "
@@ -74,7 +100,7 @@ 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);
        }
-#endif /* CONFIG_POSIX_FALLOCATE */
+
 }
 
 /*
diff --git a/fio.1 b/fio.1
index ab042081ddc83ddf270c1ad9dfcc1573e4f12b48..9783646d752988a455b24a2fc029f1725c848e48 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -436,6 +436,10 @@ are:
 .B none
 Do not pre-allocate space.
 .TP
+.B native
+Use a platform's native pre-allocation call but fall back to 'none' behavior if
+it fails/is not implemented.
+.TP
 .B posix
 Pre-allocate via \fBposix_fallocate\fR\|(3).
 .TP
@@ -450,8 +454,9 @@ Backward-compatible alias for 'posix'.
 .RE
 .P
 May not be available on all supported platforms. 'keep' is only
-available on Linux. If using ZFS on Solaris this must be set to 'none'
-because ZFS doesn't support it. Default: 'posix'.
+available on Linux. If using ZFS on Solaris this cannot be set to 'posix'
+because ZFS doesn't support it. Default: 'native' if any pre-allocation methods
+are available, 'none' if not.
 .RE
 .TP
 .BI fadvise_hint \fR=\fPstr
index 09a21af0f441d8ea67bb30a9b05075109f3a6a9a..b21f09ae169a2287c70adadc6e931f9bd52042c1 100644 (file)
--- a/options.c
+++ b/options.c
@@ -2289,14 +2289,14 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .parent = "nrfiles",
                .hide   = 1,
        },
-#ifdef CONFIG_POSIX_FALLOCATE
+#if defined(CONFIG_POSIX_FALLOCATE) || defined(FIO_HAVE_NATIVE_FALLOCATE)
        {
                .name   = "fallocate",
                .lname  = "Fallocate",
                .type   = FIO_OPT_STR,
                .off1   = offsetof(struct thread_options, fallocate_mode),
                .help   = "Whether pre-allocation is performed when laying out files",
-               .def    = "posix",
+               .def    = "native",
                .category = FIO_OPT_C_FILE,
                .group  = FIO_OPT_G_INVALID,
                .posval = {
@@ -2304,10 +2304,16 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                            .oval = FIO_FALLOCATE_NONE,
                            .help = "Do not pre-allocate space",
                          },
+                         { .ival = "native",
+                           .oval = FIO_FALLOCATE_NATIVE,
+                           .help = "Use native pre-allocation if possible",
+                         },
+#ifdef CONFIG_POSIX_FALLOCATE
                          { .ival = "posix",
                            .oval = FIO_FALLOCATE_POSIX,
                            .help = "Use posix_fallocate()",
                          },
+#endif
 #ifdef CONFIG_LINUX_FALLOCATE
                          { .ival = "keep",
                            .oval = FIO_FALLOCATE_KEEP_SIZE,
@@ -2319,10 +2325,12 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                            .oval = FIO_FALLOCATE_NONE,
                            .help = "Alias for 'none'",
                          },
+#ifdef CONFIG_POSIX_FALLOCATE
                          { .ival = "1",
                            .oval = FIO_FALLOCATE_POSIX,
                            .help = "Alias for 'posix'",
                          },
+#endif
                },
        },
 #else  /* CONFIG_POSIX_FALLOCATE */
@@ -2332,7 +2340,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .type   = FIO_OPT_UNSUPPORTED,
                .help   = "Your platform does not support fallocate",
        },
-#endif /* CONFIG_POSIX_FALLOCATE */
+#endif /* CONFIG_POSIX_FALLOCATE || FIO_HAVE_NATIVE_FALLOCATE */
        {
                .name   = "fadvise_hint",
                .lname  = "Fadvise hint",
index 8c1e93be067c9e0cd702ed23b4e8baba5a7f5ef7..e7d600dd58cbb3f6ffd1e43f5516fdd6fc0bd18a 100644 (file)
@@ -392,4 +392,22 @@ static inline int shm_attach_to_open_removed(void)
        return 1;
 }
 
+#ifdef CONFIG_LINUX_FALLOCATE
+#define FIO_HAVE_NATIVE_FALLOCATE
+static inline bool fio_fallocate(struct fio_file *f, uint64_t offset,
+                                uint64_t len)
+{
+       int ret;
+       ret = fallocate(f->fd, 0, 0, len);
+       if (ret == 0)
+               return true;
+
+       /* Work around buggy old glibc versions... */
+       if (ret > 0)
+               errno = ret;
+
+       return false;
+}
+#endif
+
 #endif
index 7de36ea79aa7b43a7f962796526cf000a2458527..a1536c70fabaf9e2de907eab9ffec0740f2bb3db 100644 (file)
@@ -20,6 +20,7 @@
 #define FIO_USE_GENERIC_INIT_RANDOM_STATE
 #define FIO_HAVE_GETTID
 #define FIO_HAVE_CHARDEV_SIZE
+#define FIO_HAVE_NATIVE_FALLOCATE
 
 #define OS_MAP_ANON            MAP_ANON
 
@@ -101,4 +102,15 @@ static inline int gettid(void)
  */
 extern int fdatasync(int fd);
 
+static inline bool fio_fallocate(struct fio_file *f, uint64_t offset, uint64_t len)
+{
+       fstore_t store = {F_ALLOCATEALL, F_PEOFPOSMODE, offset, len};
+       if (fcntl(f->fd, F_PREALLOCATE, &store) != -1) {
+               if (ftruncate(f->fd, len) == 0)
+                       return true;
+       }
+
+       return false;
+}
+
 #endif
diff --git a/os/os.h b/os/os.h
index 1d400c8f0e303fc3420a5abc40e4a4c0c9955796..afee9f9c65456fb5e50ac5139eb6fc398d6a24f3 100644 (file)
--- a/os/os.h
+++ b/os/os.h
@@ -361,4 +361,12 @@ static inline int shm_attach_to_open_removed(void)
 }
 #endif
 
+#ifndef FIO_HAVE_NATIVE_FALLOCATE
+static inline bool fio_fallocate(struct fio_file *f, uint64_t offset, uint64_t len)
+{
+       errno = ENOSYS;
+       return false;
+}
+#endif
+
 #endif