From 1f3de3f0e20d20e8f388f07339630090edaba56c Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 16 Mar 2018 10:07:07 +0100 Subject: [SERVER] Make sparse file mode actually work --- src/server/fileutil.c | 15 +++++++++++---- src/server/fileutil.h | 1 + src/server/image.c | 17 ++++++++++++----- 3 files changed, 24 insertions(+), 9 deletions(-) (limited to 'src/server') diff --git a/src/server/fileutil.c b/src/server/fileutil.c index d41dc85..336ab68 100644 --- a/src/server/fileutil.c +++ b/src/server/fileutil.c @@ -58,11 +58,18 @@ bool file_alloc(int fd, uint64_t offset, uint64_t size) #elif defined(__FreeBSD__) if ( posix_fallocate( fd, offset, size ) == 0 ) return true; // slow way #endif + return false; +} + +bool file_setSize(int fd, uint64_t size) +{ + if ( ftruncate( fd, size ) == 0 ) return true; - /* This doesn't make any sense, AFAIK - if ( lseek( fd, offset + size - 1, SEEK_SET ) != (off_t)offset ) return false; // dumb way - if ( write( fd, "", 1 ) != 1 ) return false; - */ + // Try really hard... image loading logic relies on the file + // having the proper apparent size + uint8_t byte = 0; + pread( fd, &byte, 1, size - 1 ); + if ( pwrite( fd, &byte, 1, size - 1 ) == 1 ) return true; return false; } diff --git a/src/server/fileutil.h b/src/server/fileutil.h index a4458a3..fcb5c20 100644 --- a/src/server/fileutil.h +++ b/src/server/fileutil.h @@ -9,6 +9,7 @@ bool file_isReadable(char *file); bool file_isWritable(char *file); bool mkdir_p(const char* path); bool file_alloc(int fd, uint64_t offset, uint64_t size); +bool file_setSize(int fd, uint64_t size); bool file_freeDiskSpace(const char * const path, uint64_t *total, uint64_t *avail); time_t file_lastModification(const char * const file); int file_loadLineBased(const char * const file, int minFields, int maxFields, void (*cb)(int argc, char **argv, void *data), void *data); diff --git a/src/server/image.c b/src/server/image.c index 78091f1..cb01181 100644 --- a/src/server/image.c +++ b/src/server/image.c @@ -1123,19 +1123,22 @@ bool image_create(char *image, int revision, uint64_t size) goto failure_cleanup; } // Try cache map first - if ( !file_alloc( fdCache, 0, mapsize ) ) { + if ( !file_alloc( fdCache, 0, mapsize ) && !file_setSize( fdCache, mapsize ) ) { const int err = errno; logadd( LOG_DEBUG1, "Could not allocate %d bytes for %s (errno=%d)", mapsize, cache, err ); } // Now write image if ( !_sparseFiles && !file_alloc( fdImage, 0, size ) ) { - const int err = errno; - logadd( LOG_ERROR, "Could not allocate %" PRIu64 " bytes for %s (errno=%d)", size, path, err ); + logadd( LOG_ERROR, "Could not allocate %" PRIu64 " bytes for %s (errno=%d)", size, path, errno ); logadd( LOG_ERROR, "It is highly recommended to use a file system that supports preallocating disk" " space without actually writing all zeroes to the block device." ); logadd( LOG_ERROR, "If you cannot fix this, try setting sparseFiles=true, but don't expect" " divine performance during replication." ); goto failure_cleanup; + } else if ( _sparseFiles && !file_setSize( fdImage, size ) ) { + logadd( LOG_ERROR, "Could not create sparse file of %" PRIu64 " bytes for %s (errno=%d)", size, path, errno ); + logadd( LOG_ERROR, "Make sure you have enough disk space, check directory permissions, fs errors etc." ); + goto failure_cleanup; } close( fdImage ); close( fdCache ); @@ -1741,8 +1744,12 @@ static bool image_ensureDiskSpace(uint64_t size, bool force) current = image_release( current ); } declare_now; - if ( oldest == NULL || timing_diff( &oldest->atime, &now ) < 86400 ) { - logadd( LOG_DEBUG1, "No image is old enough (all have been in use in past 24h) :-(\n" ); + if ( oldest == NULL || ( !_sparseFiles && timing_diff( &oldest->atime, &now ) < 86400 ) ) { + if ( oldest == NULL ) { + logadd( LOG_INFO, "All images are currently in use :-(" ); + } else { + logadd( LOG_INFO, "Won't free any image, all have been in use in the past 24 hours :-(" ); + } return false; } oldest = image_lock( oldest ); -- cgit v1.2.3-55-g7522