From 2bebc5d953641a17afd9637db9c79b4aa5912474 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Sun, 1 May 2016 18:11:55 +0200 Subject: [PATCH] Add fallocate in Windows and comment about its use --- cmdline/mingw.c | 9 +++++++++ cmdline/mingw.h | 8 ++++++++ cmdline/parity.c | 47 ++++++++++++++++++++++++++++++++++++----------- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/cmdline/mingw.c b/cmdline/mingw.c index 4d0b0d8e..554992af 100644 --- a/cmdline/mingw.c +++ b/cmdline/mingw.c @@ -904,6 +904,15 @@ int windows_ftruncate(int fd, off64_t off) return 0; } +int windows_fallocate(int fd, int mode, off64_t off, off64_t len) +{ + if (mode != 0) + return -1; + + /* no difference with ftruncate because Windows doesn't use sparse files */ + return windows_ftruncate(fd, off + len); +} + int windows_fsync(int fd) { HANDLE h; diff --git a/cmdline/mingw.h b/cmdline/mingw.h index 6233b3dc..f36e4fe3 100644 --- a/cmdline/mingw.h +++ b/cmdline/mingw.h @@ -58,6 +58,9 @@ #define HAVE_FTRUNCATE 1 #undef ftruncate #define ftruncate windows_ftruncate +#define HAVE_FALLOCATE 1 +#undef fallocate +#define fallocate windows_fallocate #define HAVE_FSYNC 1 #undef fsync #define fsync windows_fsync @@ -207,6 +210,11 @@ int lstat_sync(const char* file, struct windows_stat* st, uint64_t* physical); */ int windows_ftruncate(int fd, off64_t off); +/** + * Like the C fallocate(). + */ +int windows_fallocate(int fd, int mode, off64_t off, off64_t len); + /** * Like the C fsync(). */ diff --git a/cmdline/parity.c b/cmdline/parity.c index b18b594a..cf726621 100644 --- a/cmdline/parity.c +++ b/cmdline/parity.c @@ -258,16 +258,32 @@ static int parity_handle_grow(struct snapraid_split_handle* split, data_off_t si #if HAVE_FALLOCATE if (!skip_fallocate) { - /* allocate real space using the specific Linux fallocate() operation. */ - /* If the underline file-system doesn't support it, this operation fails, */ - /* instead posix_fallocate() fallbacks to write the whole file. */ + /* + * Allocate real space using the specific Linux fallocate() operation. + * If the underline file-system doesn't support it, this operation fails. + * + * Instead posix_fallocate() fallbacks to write the whole file, + * and we cannot use it as we may need to initialize a multi terabyte + * file. + * + * See: fallocate vs posix_fallocate + * http://stackoverflow.com/questions/14063046/fallocate-vs-posix-fallocate + */ ret = fallocate(split->f, 0, 0, size); - /* fallocate() returns the error number as positive integer, */ - /* and in this case it doesn't set errno, just like posix_fallocate() */ - /* Checking the glibc code (2.11.1 and 2.14.1) it seems that ENOSYS */ - /* may be returned in errno, so we support both the return way */ - if (ret > 0) { /* if a positive error is returned, convert it to errno */ + /* + * In some legacy system fallocate() may return the error number + * as positive integer, and in this case it doesn't set errno. + * + * Detect and handle this case. + * + * See: Fix fallocate error return on i386 + * https://sourceware.org/ml/libc-hacker/2010-04/msg00000.html + * + * See: [PATCH XFS] Fix error return for fallocate() on XFS + * http://oss.sgi.com/archives/xfs/2009-11/msg00201.html + */ + if (ret > 0) { /* LCOV_EXCL_START */ errno = ret; ret = -1; @@ -278,9 +294,18 @@ static int parity_handle_grow(struct snapraid_split_handle* split, data_off_t si ret = -1; } - /* we get EOPNOTSUPP if the operation is not supported, like in ext3/ext2 */ - /* or ENOSYS with kernel before 2.6.23 */ - if (errno == EOPNOTSUPP || errno == ENOSYS) { + /* + * Fallback to ftruncate() if the operation is not supported. + * + * We get EOPNOTSUPP if the operation is not supported, like in ext3/ext2 + * or ENOSYS with kernel before 2.6.23, because fallocate is not supported + * at all. + * + * See: man fallocate + * ENOSYS - This kernel does not implement fallocate(). + * EOPNOTSUPP - The file system containing the file referred to by fd does not support this operation + */ + if (ret != 0 && (errno == EOPNOTSUPP || errno == ENOSYS)) { /* fallback using ftruncate() */ ret = ftruncate(split->f, size); }