From: Sitsofe Wheeler Date: Fri, 30 Jun 2017 06:32:19 +0000 (+0100) Subject: filesetup: add native fallocate X-Git-Tag: fio-2.99~11^2~1 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=2c3e17be filesetup: add native fallocate - 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 --- diff --git a/HOWTO b/HOWTO index 6e53cff8..cf463492 100644 --- 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 9801bb58..84daa5f6 100644 --- 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, }; /* diff --git a/filesetup.c b/filesetup.c index f3e3865e..38ad9edc 100644 --- a/filesetup.c +++ b/filesetup.c @@ -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 ab042081..9783646d 100644 --- 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 diff --git a/options.c b/options.c index 09a21af0..b21f09ae 100644 --- 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", diff --git a/os/os-linux.h b/os/os-linux.h index 8c1e93be..e7d600dd 100644 --- a/os/os-linux.h +++ b/os/os-linux.h @@ -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 diff --git a/os/os-mac.h b/os/os-mac.h index 7de36ea7..a1536c70 100644 --- a/os/os-mac.h +++ b/os/os-mac.h @@ -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 1d400c8f..afee9f9c 100644 --- 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