summaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
authorSimon Rettberg2018-03-16 10:07:07 +0100
committerSimon Rettberg2018-03-16 10:07:07 +0100
commit1f3de3f0e20d20e8f388f07339630090edaba56c (patch)
tree9bf99629a878019b55fa907852b19eedebc2fd37 /src/server
parent[SERVER] Experimental support for sparse files in proxy mode (diff)
downloaddnbd3-1f3de3f0e20d20e8f388f07339630090edaba56c.tar.gz
dnbd3-1f3de3f0e20d20e8f388f07339630090edaba56c.tar.xz
dnbd3-1f3de3f0e20d20e8f388f07339630090edaba56c.zip
[SERVER] Make sparse file mode actually work
Diffstat (limited to 'src/server')
-rw-r--r--src/server/fileutil.c15
-rw-r--r--src/server/fileutil.h1
-rw-r--r--src/server/image.c17
3 files changed, 24 insertions, 9 deletions
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 );