summaryrefslogtreecommitdiffstats
path: root/src/fuse/cowfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fuse/cowfile.c')
-rw-r--r--src/fuse/cowfile.c214
1 files changed, 132 insertions, 82 deletions
diff --git a/src/fuse/cowfile.c b/src/fuse/cowfile.c
index 07e7452..965e6f4 100644
--- a/src/fuse/cowfile.c
+++ b/src/fuse/cowfile.c
@@ -71,13 +71,13 @@ static int getBitfieldOffset( size_t offset )
* @param to end bit
* @param value set bits to 1 or 0
*/
-static void setBits( char *byte, int from, int to, bool value )
+static void setBits( atomic_char *byte, int from, int to, bool value )
{
char mask = (char)( ( 255 >> ( 7 - ( to - from ) ) ) << from );
- if (value) {
- atomic_fetch_or( byte, mask );
+ if ( value ) {
+ atomic_fetch_or( byte, mask );
} else {
- atomic_fetch_and( byte, ~mask );
+ atomic_fetch_and( byte, ~mask );
}
}
@@ -251,16 +251,22 @@ bool mergeRequest()
curl_mime *mime;
curl_mimepart *part;
mime = curl_mime_init( curl );
- part = curl_mime_addpart( mime );
+ part = curl_mime_addpart( mime );
curl_mime_name( part, "guid" );
curl_mime_data( part, metadata->uuid, CURL_ZERO_TERMINATED );
- part = curl_mime_addpart( mime );
- curl_mime_name( part, "fileSize" );
+ part = curl_mime_addpart( mime );
+ curl_mime_name( part, "originalFileSize" );
char buf[21];
+ snprintf( buf, sizeof buf, "%" PRIu64, metadata->originalImageSize );
+ curl_mime_data( part, buf, CURL_ZERO_TERMINATED );
+
+ part = curl_mime_addpart( mime );
+ curl_mime_name( part, "newFileSize" );
snprintf( buf, sizeof buf, "%" PRIu64, metadata->imageSize );
curl_mime_data( part, buf, CURL_ZERO_TERMINATED );
+
curl_easy_setopt( curl, CURLOPT_MIMEPOST, mime );
@@ -431,8 +437,8 @@ bool addUpload( CURLM *cm, cow_curl_read_upload_t *curlUploadBlock, struct curl_
curl_easy_setopt( eh, CURLOPT_READDATA, (void *)curlUploadBlock );
curl_easy_setopt( eh, CURLOPT_PRIVATE, (void *)curlUploadBlock );
// min upload speed of 1kb/s over 10 sec otherwise the upload is canceled.
- curl_easy_setopt( eh, CURLOPT_LOW_SPEED_TIME, 10L);
- curl_easy_setopt( eh, CURLOPT_LOW_SPEED_LIMIT, 1000L);
+ curl_easy_setopt( eh, CURLOPT_LOW_SPEED_TIME, 10L );
+ curl_easy_setopt( eh, CURLOPT_LOW_SPEED_LIMIT, 1000L );
curl_easy_setopt(
eh, CURLOPT_POSTFIELDSIZE_LARGE, (long)( metadata->bitfieldSize + COW_METADATA_STORAGE_CAPACITY ) );
@@ -942,23 +948,29 @@ bool cowfile_load( char *path, atomic_uint_fast64_t **imageSizePtr, char *server
* @param block
* @param inBlockOffset
*/
-static void writeData( const char *buffer, ssize_t size, size_t netSize, cow_request_t *cowRequest,
- cow_block_metadata_t *block, off_t inBlockOffset )
+static void writeData( const char *buffer, ssize_t size, size_t netSize, atomic_int *errorCode,
+ atomic_size_t *bytesWorkedOn, cow_block_metadata_t *block, off_t inBlockOffset )
{
ssize_t totalBytesWritten = 0;
while ( totalBytesWritten < size ) {
ssize_t bytesWritten = pwrite( cow.fhd, ( buffer + totalBytesWritten ), size - totalBytesWritten,
block->offset + inBlockOffset + totalBytesWritten );
if ( bytesWritten == -1 ) {
- cowRequest->errorCode = errno;
+ logadd( LOG_ERROR,
+ "size:%zu netSize:%zu errorCode:%i bytesWorkedOn:%zu inBlockOffset:%lld block->offset:%lld \n", size,
+ netSize, *errorCode, *bytesWorkedOn, inBlockOffset, block->offset );
+ *errorCode = errno;
break;
} else if ( bytesWritten == 0 ) {
- cowRequest->errorCode = EIO;
+ logadd( LOG_ERROR,
+ "size:%zu netSize:%zu errorCode:%i bytesWorkedOn:%zu inBlockOffset:%lld block->offset:%lld \n", size,
+ netSize, *errorCode, *bytesWorkedOn, inBlockOffset, block->offset );
+ *errorCode = EIO;
break;
}
totalBytesWritten += bytesWritten;
}
- atomic_fetch_add( &cowRequest->bytesWorkedOn, netSize );
+ atomic_fetch_add( bytesWorkedOn, netSize );
setBitsInBitfield( block->bitfield, (int)( inBlockOffset / DNBD3_BLOCK_SIZE ),
(int)( ( inBlockOffset + totalBytesWritten - 1 ) / DNBD3_BLOCK_SIZE ), 1 );
@@ -1049,7 +1061,8 @@ static void writePaddedBlock( cow_sub_request_t *sRequest )
//copy write Data
memcpy( ( sRequest->writeBuffer + ( sRequest->inBlockOffset % DNBD3_BLOCK_SIZE ) ), sRequest->writeSrc,
sRequest->size );
- writeData( sRequest->writeBuffer, DNBD3_BLOCK_SIZE, (ssize_t)sRequest->size, sRequest->cowRequest, sRequest->block,
+ writeData( sRequest->writeBuffer, DNBD3_BLOCK_SIZE, (ssize_t)sRequest->size, &sRequest->cowRequest->errorCode,
+ &sRequest->cowRequest->bytesWorkedOn, sRequest->block,
( sRequest->inBlockOffset - ( sRequest->inBlockOffset % DNBD3_BLOCK_SIZE ) ) );
@@ -1070,13 +1083,15 @@ static void padBlockFromRemote( fuse_req_t req, off_t offset, cow_request_t *cow
{
if ( offset > (off_t)metadata->originalImageSize ) {
//pad 0 and done
+ inBlockOffset -= inBlockOffset % DNBD3_BLOCK_SIZE;
char buf[DNBD3_BLOCK_SIZE] = { 0 };
- memcpy( buf, buffer, size );
+ memcpy( buf + ( offset % 4096 ), buffer, size );
- writeData( buf, DNBD3_BLOCK_SIZE, (ssize_t)size, cowRequest, block, inBlockOffset );
+ writeData( buf, DNBD3_BLOCK_SIZE, (ssize_t)size, &cowRequest->errorCode, &cowRequest->bytesWorkedOn, block,
+ inBlockOffset );
return;
}
- cow_sub_request_t *sRequest = malloc( sizeof( cow_sub_request_t ) + DNBD3_BLOCK_SIZE );
+ cow_sub_request_t *sRequest = calloc( sizeof( cow_sub_request_t ) + DNBD3_BLOCK_SIZE, sizeof( char ) );
sRequest->callback = writePaddedBlock;
sRequest->inBlockOffset = inBlockOffset;
sRequest->block = block;
@@ -1088,7 +1103,6 @@ static void padBlockFromRemote( fuse_req_t req, off_t offset, cow_request_t *cow
sRequest->dRequest.length = DNBD3_BLOCK_SIZE;
sRequest->dRequest.offset = start;
sRequest->dRequest.fuse_req = req;
- sRequest->cowRequest = cowRequest;
if ( ( (size_t)( offset + DNBD3_BLOCK_SIZE ) ) > metadata->originalImageSize ) {
sRequest->dRequest.length =
@@ -1130,6 +1144,9 @@ void readRemoteData( cow_sub_request_t *sRequest )
atomic_fetch_add( &sRequest->cowRequest->bytesWorkedOn, sRequest->dRequest.length );
if ( atomic_fetch_sub( &sRequest->cowRequest->workCounter, 1 ) == 1 ) {
+ if ( sRequest->cowRequest->bytesWorkedOn < sRequest->cowRequest->fuseRequestSize ) {
+ logadd( LOG_ERROR, "pad read to small\n" );
+ }
fuse_reply_buf(
sRequest->dRequest.fuse_req, sRequest->cowRequest->readBuffer, sRequest->cowRequest->bytesWorkedOn );
free( sRequest->cowRequest->readBuffer );
@@ -1138,7 +1155,6 @@ void readRemoteData( cow_sub_request_t *sRequest )
free( sRequest );
}
-
/**
* @brief changes the imageSize
*
@@ -1147,65 +1163,79 @@ void readRemoteData( cow_sub_request_t *sRequest )
* @param ino fuse_ino_t
* @param fi fuse_file_info
*/
-void cowfile_setSize( fuse_req_t req, size_t size , fuse_ino_t ino, struct fuse_file_info *fi) {
- if( metadata->imageSize < size ) {
- int l1EndOffset = getL1Offset( size );
+
+void cowfile_setSize( fuse_req_t req, size_t size, fuse_ino_t ino, struct fuse_file_info *fi )
+{
+ // decrease
+ if ( metadata->imageSize > size ) {
+ if ( size < metadata->originalImageSize ) {
+ metadata->originalImageSize = size;
+ }
+
+ // increase
+ } else if ( metadata->imageSize < size ) {
+ off_t offset = metadata->imageSize;
+ int l1Offset = getL1Offset( offset );
+ int l2Offset = getL2Offset( offset );
+ int l1EndOffset = getL1Offset( size );
int l2EndOffset = getL2Offset( size );
- int l1Offset = getL1Offset( metadata->imageSize );
- int l2Offset = getL2Offset( metadata->imageSize );
- off_t offset = size;
- // imagesize is not on block border
- if ( size %4096 != 0 ) {
- off_t inBlockOffset = (size % 4096);
- size_t sizeToWrite = 4096 - inBlockOffset;
- if ( cow.l1[l1Offset] != -1 ) {
- char buf[sizeToWrite];
- memset( buf, 0, sizeToWrite );
- cow_block_metadata_t * block = getBlock( l1Offset, l2Offset );
- ssize_t bytesWritten = pwrite( cow.fhd, buf, sizeToWrite,
- block->offset + inBlockOffset );
-
- if( bytesWritten < (ssize_t) sizeToWrite ) {
- fuse_reply_err( req, bytesWritten == -1? errno : EIO);
- return;
- }
- off_t blockOffset = l1Offset * COW_L2_STORAGE_CAPACITY + l2Offset * COW_METADATA_STORAGE_CAPACITY;
- int start = MIN((int)( ( metadata->imageSize - blockOffset ) / DNBD3_BLOCK_SIZE ) , 0 );
- setBitsInBitfield(block->bitfield, start, COW_BITFIELD_SIZE * 8, 0);
- l2Offset++;
- if(l2Offset >= COW_L2_SIZE ){
- l2Offset = 0;
- l1Offset++;
+ // special case first block
+ if ( cow.l1[l1Offset] != -1 ) {
+ cow_block_metadata_t *block = getBlock( l1Offset, l2Offset );
+ if ( metadata->imageSize % DNBD3_BLOCK_SIZE != 0 ) {
+ off_t inBlockOffset = metadata->imageSize % COW_METADATA_STORAGE_CAPACITY;
+ size_t sizeToWrite = DNBD3_BLOCK_SIZE - ( metadata->imageSize % DNBD3_BLOCK_SIZE );
+
+ if ( checkBit( block->bitfield, (int)( inBlockOffset / DNBD3_BLOCK_SIZE ) ) ) {
+ char buf[sizeToWrite];
+ memset( buf, 0, sizeToWrite );
+
+ ssize_t bytesWritten = pwrite( cow.fhd, buf, sizeToWrite, block->offset + inBlockOffset );
+
+ if ( bytesWritten < (ssize_t)sizeToWrite ) {
+ fuse_reply_err( req, bytesWritten == -1 ? errno : EIO );
+ return;
+ }
+ block->timeChanged = time( NULL );
+ offset += sizeToWrite;
}
}
+ // rest of block set bits 0
+ l1Offset = getL1Offset( offset );
+ l2Offset = getL2Offset( offset );
+ block = getBlock( l1Offset, l2Offset );
+ off_t inBlockOffset = offset % COW_METADATA_STORAGE_CAPACITY;
+ setBitsInBitfield(
+ block->bitfield, (int)( inBlockOffset / DNBD3_BLOCK_SIZE ), ( COW_BITFIELD_SIZE * 8 ) - 1, 0 );
+ block->timeChanged = time( NULL );
+ l2Offset++;
+ if ( l2Offset >= COW_L2_SIZE ) {
+ l2Offset = 0;
+ l1Offset++;
+ }
}
-
// null all bitfields
-
- while( !( l1Offset > l1EndOffset || ( l1Offset == l1EndOffset && l2EndOffset < l2Offset ) ) ) {
-
+ while ( !( l1Offset > l1EndOffset || ( l1Offset == l1EndOffset && l2EndOffset < l2Offset ) ) ) {
if ( cow.l1[l1Offset] == -1 ) {
l1Offset++;
l2Offset = 0;
continue;
}
-
- cow_block_metadata_t * block = getBlock( l1Offset, l2Offset );
- setBitsInBitfield(block->bitfield, 0, COW_BITFIELD_SIZE * 8, 0);
+
+ cow_block_metadata_t *block = getBlock( l1Offset, l2Offset );
+ setBitsInBitfield( block->bitfield, 0, ( COW_BITFIELD_SIZE * 8 ) - 1, 0 );
+ block->timeChanged = time( NULL );
l2Offset++;
- if(l2Offset >= COW_L2_SIZE ){
+ if ( l2Offset >= COW_L2_SIZE ) {
l2Offset = 0;
l1Offset++;
}
}
}
-
- if( size < metadata->originalImageSize ) {
- metadata->originalImageSize = size;
- }
-
metadata->imageSize = size;
- image_ll_getattr( req, ino, fi );
+ if ( req != NULL ) {
+ image_ll_getattr( req, ino, fi );
+ }
}
/**
@@ -1220,11 +1250,7 @@ void cowfile_write( fuse_req_t req, cow_request_t *cowRequest, off_t offset, siz
{
// if beyond end of file, pad with 0
if ( offset > (off_t)metadata->imageSize ) {
- size_t pSize = offset - metadata->imageSize;
- // half end block will be padded with original write
- pSize = pSize - ( ( pSize + offset ) % DNBD3_BLOCK_SIZE );
- atomic_fetch_add( &cowRequest->workCounter, 1 );
- cowfile_write( req, cowRequest, metadata->imageSize, pSize );
+ cowfile_setSize( NULL, offset, NULL, NULL );
}
@@ -1258,7 +1284,7 @@ void cowfile_write( fuse_req_t req, cow_request_t *cowRequest, off_t offset, siz
// write remote
size_t padSize = MIN( sizeToWriteToBlock, DNBD3_BLOCK_SIZE - ( (size_t)currentOffset % DNBD3_BLOCK_SIZE ) );
const char *sbuf = cowRequest->writeBuffer + ( ( currentOffset - offset ) );
- padBlockFromRemote( req, offset, cowRequest, sbuf, padSize, metaBlock, (off_t)inBlockOffset );
+ padBlockFromRemote( req, currentOffset, cowRequest, sbuf, padSize, metaBlock, (off_t)inBlockOffset );
currentOffset += padSize;
continue;
}
@@ -1278,10 +1304,8 @@ void cowfile_write( fuse_req_t req, cow_request_t *cowRequest, off_t offset, siz
endPaddedSize = (currentEndOffset)-padStartOffset;
}
}
-
-
- writeData( cowRequest->writeBuffer + ( ( currentOffset - offset ) ),
- (ssize_t)sizeToWriteToBlock, sizeToWriteToBlock, cowRequest, metaBlock, inBlockOffset );
+ writeData( cowRequest->writeBuffer + ( ( currentOffset - offset ) ), (ssize_t)sizeToWriteToBlock,
+ sizeToWriteToBlock, &cowRequest->errorCode, &cowRequest->bytesWorkedOn, metaBlock, inBlockOffset );
currentOffset += sizeToWriteToBlock;
currentOffset += endPaddedSize;
@@ -1309,6 +1333,15 @@ void cowfile_write( fuse_req_t req, cow_request_t *cowRequest, off_t offset, siz
*/
static void readRemote( fuse_req_t req, off_t offset, ssize_t size, char *buffer, cow_request_t *cowRequest )
{
+ // edgecase: Image size got reduced before on a non block border
+ if ( offset + size > metadata->originalImageSize ) {
+ size_t padZeroSize = ( offset + size ) - metadata->originalImageSize;
+ off_t padZeroOffset = metadata->originalImageSize - offset;
+ assert( offset > 0 );
+ memset( ( buffer + padZeroOffset ), 0, padZeroOffset );
+
+ atomic_fetch_add( &cowRequest->bytesWorkedOn, padZeroSize );
+ }
cow_sub_request_t *sRequest = malloc( sizeof( cow_sub_request_t ) );
sRequest->callback = readRemoteData;
sRequest->dRequest.length = (uint32_t)size;
@@ -1338,12 +1371,12 @@ static void readRemote( fuse_req_t req, off_t offset, ssize_t size, char *buffer
* @param offset
* @return enum dataSource
*/
-enum dataSource getBlockDataSource( cow_block_metadata_t * block , off_t bitfieldOffset, off_t offset ) {
-
- if( block != NULL && checkBit( block->bitfield, bitfieldOffset ) ) {
+enum dataSource getBlockDataSource( cow_block_metadata_t *block, off_t bitfieldOffset, off_t offset )
+{
+ if ( block != NULL && checkBit( block->bitfield, (int)bitfieldOffset ) ) {
return local;
}
- if( offset >= metadata->originalImageSize ) {
+ if ( offset >= (off_t)metadata->originalImageSize ) {
return zero;
}
return remote;
@@ -1387,8 +1420,8 @@ void cowfile_read( fuse_req_t req, size_t size, off_t offset )
if ( firstLoop ) {
firstLoop = false;
lastReadOffset = searchOffset;
- dataState = getBlockDataSource( block , bitfieldOffset, searchOffset );
- } else if ( getBlockDataSource( block , bitfieldOffset, searchOffset ) != dataState ) {
+ dataState = getBlockDataSource( block, bitfieldOffset, searchOffset );
+ } else if ( getBlockDataSource( block, bitfieldOffset, searchOffset ) != dataState ) {
doRead = true;
} else {
bitfieldOffset++;
@@ -1410,14 +1443,25 @@ void cowfile_read( fuse_req_t req, size_t size, off_t offset )
searchOffset = DNBD3_BLOCK_SIZE * ( bitfieldOffset ) + l2Offset * COW_METADATA_STORAGE_CAPACITY
+ l1Offset * COW_L2_STORAGE_CAPACITY;
if ( doRead || searchOffset >= endOffset ) {
- ssize_t sizeToRead = MIN( searchOffset, endOffset ) - lastReadOffset;
- if ( dataState == remote) {
+ ssize_t sizeToRead = MIN( searchOffset, endOffset );
+ if ( dataState == remote ) {
+ if ( sizeToRead > metadata->originalImageSize ) {
+ //pad rest with 0
+ memset( cowRequest->readBuffer
+ + ( ( lastReadOffset - offset ) + ( metadata->originalImageSize - offset ) ),
+ 0, sizeToRead - metadata->originalImageSize );
+ atomic_fetch_add( &cowRequest->bytesWorkedOn, sizeToRead - metadata->originalImageSize );
+ sizeToRead = metadata->originalImageSize;
+ }
+ sizeToRead -= lastReadOffset;
readRemote(
req, lastReadOffset, sizeToRead, cowRequest->readBuffer + ( lastReadOffset - offset ), cowRequest );
- }else if( dataState == zero) {
- memset( cowRequest->readBuffer + ( lastReadOffset - offset ), 0 , sizeToRead );
+ } else if ( dataState == zero ) {
+ sizeToRead -= lastReadOffset;
+ memset( cowRequest->readBuffer + ( lastReadOffset - offset ), 0, sizeToRead );
atomic_fetch_add( &cowRequest->bytesWorkedOn, sizeToRead );
} else {
+ sizeToRead -= lastReadOffset;
// Compute the offset in the data file where the read starts
off_t localRead =
block->offset + ( ( lastReadOffset % COW_L2_STORAGE_CAPACITY ) % COW_METADATA_STORAGE_CAPACITY );
@@ -1454,9 +1498,15 @@ void cowfile_read( fuse_req_t req, size_t size, off_t offset )
fail:;
if ( atomic_fetch_sub( &cowRequest->workCounter, 1 ) == 1 ) {
if ( cowRequest->errorCode != 0 ) {
+ if ( cowRequest->bytesWorkedOn < size ) {
+ logadd( LOG_ERROR, " read to small" );
+ }
fuse_reply_err( req, cowRequest->errorCode );
} else {
+ if ( cowRequest->bytesWorkedOn < size ) {
+ logadd( LOG_ERROR, " read to small" );
+ }
fuse_reply_buf( req, cowRequest->readBuffer, cowRequest->bytesWorkedOn );
}
free( cowRequest->readBuffer );