Add fallocate in Windows and comment about its use

This commit is contained in:
Andrea Mazzoleni 2016-05-01 18:11:55 +02:00
parent f564e9b91a
commit 2bebc5d953
3 changed files with 53 additions and 11 deletions

View file

@ -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;

View file

@ -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().
*/

View file

@ -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);
}