Resize cowfile bitmap if necessary

This commit is contained in:
Martin 2017-01-27 20:49:05 +01:00
parent b4a1842053
commit 577c36d048
2 changed files with 68 additions and 2 deletions

View File

@ -30,6 +30,7 @@
#include "fs/ntfs.h"
#include <errno.h>
#include <memory>
#include <assert.h>
#include "FileWrapper.h"
#include "ClientBitmap.h"
@ -276,6 +277,12 @@ _u32 CowFile::Write(const char* buffer, _u32 bsize, bool *has_error)
Server->Log("Write to CowFile failed. errno="+convert(errno), LL_DEBUG);
return 0;
}
if(curr_offset+w>filesize)
{
filesize = curr_offset+w);
resizeBitmap();
}
setBitmapRange(curr_offset, curr_offset+w, true);
curr_offset+=w;
@ -477,6 +484,15 @@ bool CowFile::hasBitmapRange(uint64 offset_start, uint64 offset_end)
bool CowFile::setUnused(_i64 unused_start, _i64 unused_end)
{
if(unused_end>filesize && unused_start<filesize)
{
unused_end = filesize;
}
else if(unused_start>=filesize)
{
return false;
}
#if !defined(__FreeBSD__) && defined(HAVE_FALLOCATE64)
int rc = fallocate64(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, unused_start, unused_end-unused_start);
if(rc==0)
@ -595,6 +611,16 @@ bool CowFile::trimUnused(_i64 fs_offset, _i64 trim_blocksize, ITrimCallback* tri
{
int64 unused_start = fs_offset + unused_start_block*bitmap_blocksize;
int64 unused_end = fs_offset + ntfs_block*bitmap_blocksize;
if(unused_start>=filesize)
{
return true;
}
else if(unused_end>filesize)
{
unused_end = filesize;
}
if(hasBitmapRange(unused_start, unused_end))
{
setBitmapRange(unused_start, unused_end, false);
@ -611,6 +637,25 @@ bool CowFile::trimUnused(_i64 fs_offset, _i64 trim_blocksize, ITrimCallback* tri
unused_start_block=-1;
}
}
if(unused_start_block!=-1)
{
int64 unused_start = fs_offset + unused_start_block*bitmap_blocksize;
if(hasBitmapRange(unused_start, filesize))
{
setBitmapRange(unused_start, filesize, false);
if(!setUnused(unused_start, filesize))
{
Server->Log("Trimming syscall failed. Stopping trimming (end).", LL_WARNING);
return false;
}
if(trim_callback!=NULL)
{
trim_callback->trimmed(unused_start - fs_offset, filesize - fs_offset);
}
}
}
return true;
}
@ -644,16 +689,37 @@ bool CowFile::syncBitmap(_i64 fs_offset)
{
if(bitmap_source->hasBlock(ntfs_block))
{
used_start_block=ntfs_block;
if(used_start_block==-1)
{
used_start_block=ntfs_block;
}
}
else if(used_start_block!=-1)
{
int64 used_start = fs_offset + used_start_block*bitmap_blocksize;
int64 used_end = fs_offset + ntfs_block*bitmap_blocksize;
if(used_start>=filesize)
{
return true;
}
else if(unused_end>filesize)
{
unused_end = filesize;
}
setBitmapRange(used_start, used_end, true);
used_start_block=-1;
}
}
if(used_start_block!=-1)
{
int64 used_start = fs_offset + used_start_block*bitmap_blocksize;
setBitmapRange(used_start, filesize, true);
}
return true;
}

View File

@ -1009,7 +1009,7 @@ bool ImageBackup::doImage(const std::string &pLetter, const std::string &pParent
if (vhd_size>0 && vhd_size >= 2040LL * 1024 * 1024 * 1024
&& image_file_format != image_file_format_cowraw)
{
ServerLogger::Log(logid, "Data on volume is to large for VHD files with " + PrettyPrintBytes(vhd_size) +
ServerLogger::Log(logid, "Data on volume is too large for VHD files with " + PrettyPrintBytes(vhd_size) +
". VHD files have a maximum size of 2040GB. Please use another image file format.", LL_ERROR);
goto do_image_cleanup;
}