summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Scherle2022-03-31 20:26:55 +0200
committerMichael Scherle2022-03-31 20:26:55 +0200
commit0ab8f979fd25c66c73ac90839ff29a6a2ac884e7 (patch)
treef9fc1682a0e7b051c0a4391efd511277220a0a33
parentfirst round of fixes: static, setBits, MagicValues (diff)
downloaddnbd3-0ab8f979fd25c66c73ac90839ff29a6a2ac884e7.tar.gz
dnbd3-0ab8f979fd25c66c73ac90839ff29a6a2ac884e7.tar.xz
dnbd3-0ab8f979fd25c66c73ac90839ff29a6a2ac884e7.zip
multible bugfixes, test can verify existing file
-rw-r--r--inc/dnbd3/config.h3
-rw-r--r--src/cowtest/main.c317
-rw-r--r--src/fuse/cowfile.c560
-rw-r--r--src/fuse/cowfile.h54
-rw-r--r--src/fuse/main.c4
5 files changed, 617 insertions, 321 deletions
diff --git a/inc/dnbd3/config.h b/inc/dnbd3/config.h
index 160afe1..323a670 100644
--- a/inc/dnbd3/config.h
+++ b/inc/dnbd3/config.h
@@ -42,5 +42,6 @@
// +++++ COW +++++
#define COW_BITFIELD_SIZE 40 // NEVER CHANGE THIS OR THE WORLD WILL ALSO END!
-
+#define COW_FILE_META_MAGIC_VALUE ((uint64_t)0xEBE44D6E72F7825E) // Magic Value to recognize a Cow .meta file
+#define COW_FILE_DATA_MAGIC_VALUE ((uint64_t)0xEBE44D6E72F7825F) // Magic Value to recognize a Cow .data file
#endif /* CONFIG_H_ */
diff --git a/src/cowtest/main.c b/src/cowtest/main.c
index 22a2a57..71efe4c 100644
--- a/src/cowtest/main.c
+++ b/src/cowtest/main.c
@@ -9,18 +9,25 @@
#include <string.h>
#include <sys/stat.h>
#include <stdint.h>
+#include <dnbd3/types.h>
+typedef bool ( *func_ptr )();
+typedef struct verify_test
+{
+ off_t offset;
+ size_t size;
+ func_ptr test;
+} verify_test_t;
const size_t l2Size = 1024;
const size_t bitfieldByteSize = 40;
-const size_t blocksize = 4096;
-const size_t l2Capacity = l2Size * blocksize * bitfieldByteSize;
+const size_t l2Capacity = l2Size * DNBD3_BLOCK_SIZE * bitfieldByteSize;
+
+const size_t testFileSize = l2Size * bitfieldByteSize * DNBD3_BLOCK_SIZE * 8L * 2.9L;
-const size_t testFileSize = l2Size * bitfieldByteSize * blocksize * 8L * 2.9L;
-const char standartValue = 'a';
static char filePath[400];
static int fh = 0;
@@ -107,91 +114,136 @@ bool writeSizeTested( int fh, char *buf, ssize_t size, off_t off, char *error )
return true;
}
+bool verifyTestFirstBit()
+{
+ char buff[DNBD3_BLOCK_SIZE];
+ char expected[DNBD3_BLOCK_SIZE];
+ memset( expected, 0, DNBD3_BLOCK_SIZE );
+ expected[0] = 1;
+ if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE, 0, "FirstBit test Failed: read to small" ) )
+ return false;
+ if ( !compare( buff, expected, DNBD3_BLOCK_SIZE, "FirstBit test Failed: write not as expected" ) )
+ return false;
+ printf( "testFirstBit successful!\n" );
+ return true;
+}
+
bool testFirstBit()
{
- char buff[blocksize];
- char expected[blocksize];
- memset( expected, 0, blocksize );
- if ( !readSizeTested( fh, buff, 4096, 0, "FirstBit test Failed: read to small" ) )
+ char buff[DNBD3_BLOCK_SIZE];
+ char expected[DNBD3_BLOCK_SIZE];
+ memset( expected, 0, DNBD3_BLOCK_SIZE );
+ if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE, 0, "FirstBit test Failed: read to small" ) )
return false;
- if ( !compare( buff, expected, 4096, "FirstBit test Failed: initial read" ) )
+ if ( !compare( buff, expected, DNBD3_BLOCK_SIZE, "FirstBit test Failed: initial read" ) )
return false;
expected[0] = 1;
- if ( !writeSizeTested( fh, expected, 4096, 0, "FirstBit test Failed: write failed" ) )
+ if ( !writeSizeTested( fh, expected, DNBD3_BLOCK_SIZE, 0, "FirstBit test Failed: write failed" ) )
return false;
- if ( !readSizeTested( fh, buff, 4096, 0, "FirstBit test Failed: read to small" ) )
+ return verifyTestFirstBit();
+}
+
+bool verifyWriteOverTwoBlocks()
+{
+ char buff[DNBD3_BLOCK_SIZE * 2];
+ char expected[DNBD3_BLOCK_SIZE * 2];
+ memset( expected, 1, DNBD3_BLOCK_SIZE * 2 );
+ if ( !readSizeTested(
+ fh, buff, DNBD3_BLOCK_SIZE * 2, DNBD3_BLOCK_SIZE * 3, "writeOverTwoBlocks test Failed: read to small" ) )
return false;
- if ( !compare( buff, expected, 4096, "FirstBit test Failed: write not as expected" ) )
+ if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2, "OverTwoBlocks test Failed: write not as expected" ) )
return false;
- printf( "testFirstBit successful!\n" );
+ printf( "writeOverTwoBlocks successful!\n" );
return true;
}
bool writeOverTwoBlocks()
{
- char buff[blocksize * 2];
- char expected[blocksize * 2];
- memset( expected, 0, blocksize * 2 );
- if ( !readSizeTested( fh, buff, blocksize * 2, blocksize * 3, "writeOverTwoBlocks test Failed: read to small" ) )
+ char buff[DNBD3_BLOCK_SIZE * 2];
+ char expected[DNBD3_BLOCK_SIZE * 2];
+ memset( expected, 0, DNBD3_BLOCK_SIZE * 2 );
+ if ( !readSizeTested(
+ fh, buff, DNBD3_BLOCK_SIZE * 2, DNBD3_BLOCK_SIZE * 3, "writeOverTwoBlocks test Failed: read to small" ) )
return false;
- if ( !compare( buff, expected, blocksize * 2, "OverTwoBlocks test Failed: initial read" ) )
+ if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2, "OverTwoBlocks test Failed: initial read" ) )
return false;
- memset( expected, 1, blocksize * 2 );
- if ( !writeSizeTested( fh, expected, blocksize * 2, blocksize * 3, "writeOverTwoBlocks test Failed: write failed" ) )
+ memset( expected, 1, DNBD3_BLOCK_SIZE * 2 );
+ if ( !writeSizeTested( fh, expected, DNBD3_BLOCK_SIZE * 2, DNBD3_BLOCK_SIZE * 3,
+ "writeOverTwoBlocks test Failed: write failed" ) )
return false;
- if ( !readSizeTested( fh, buff, blocksize * 2, blocksize * 3, "writeOverTwoBlocks test Failed: read to small" ) )
+ return verifyWriteOverTwoBlocks();
+}
+
+
+bool verifyWriteOverL2()
+{
+ char buff[DNBD3_BLOCK_SIZE * 2];
+ char expected[DNBD3_BLOCK_SIZE * 2];
+
+ memset( expected, 1, DNBD3_BLOCK_SIZE * 2 );
+ size_t offset = l2Capacity * 2 - DNBD3_BLOCK_SIZE;
+ if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 2, offset, "writeOverL2 test Failed: read to small" ) ) {
return false;
- if ( !compare( buff, expected, blocksize * 2, "OverTwoBlocks test Failed: write not as expected" ) )
+ }
+ if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2, "writeOverL2 test Failed: write not as expected" ) ) {
return false;
- printf( "writeOverTwoBlocks successful!\n" );
+ }
+ printf( "writeOverL2 successful!\n" );
return true;
}
bool writeOverL2()
{
- char buff[blocksize * 2];
- char expected[blocksize * 2];
- memset( expected, 0, blocksize * 2 );
- size_t offset = l2Capacity * 2 - blocksize;
- if ( !readSizeTested( fh, buff, blocksize * 2, offset, "writeOverL2 test Failed: read to small" ) )
+ char buff[DNBD3_BLOCK_SIZE * 2];
+ char expected[DNBD3_BLOCK_SIZE * 2];
+ memset( expected, 0, DNBD3_BLOCK_SIZE * 2 );
+ size_t offset = l2Capacity * 2 - DNBD3_BLOCK_SIZE;
+ if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 2, offset, "writeOverL2 test Failed: read to small" ) )
return false;
- if ( !compare( buff, expected, blocksize * 2, "writeOverL2 test Failed: initial read" ) )
+ if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2, "writeOverL2 test Failed: initial read" ) )
return false;
- memset( expected, 1, blocksize * 2 );
- if ( !writeSizeTested( fh, expected, blocksize * 2, offset, "writeOverL2 test Failed: write failed" ) )
+ memset( expected, 1, DNBD3_BLOCK_SIZE * 2 );
+ if ( !writeSizeTested( fh, expected, DNBD3_BLOCK_SIZE * 2, offset, "writeOverL2 test Failed: write failed" ) )
return false;
- if ( !readSizeTested( fh, buff, blocksize * 2, offset, "writeOverL2 test Failed: read to small" ) )
+
+ return verifyWriteOverL2();
+}
+
+
+bool verifyWriteNotOnBlockBorder()
+{
+ char buff[DNBD3_BLOCK_SIZE * 2];
+ char expected[DNBD3_BLOCK_SIZE * 2];
+ memset( expected, 1, DNBD3_BLOCK_SIZE * 2 );
+ size_t offset = DNBD3_BLOCK_SIZE * 11 - DNBD3_BLOCK_SIZE / 2;
+ if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 2, offset, "writeNotOnBlockBorder test Failed: read to small" ) )
return false;
- if ( !compare( buff, expected, blocksize * 2, "writeOverL2 test Failed: write not as expected" ) )
+ if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2, "writeNotOnBlockBorder test Failed: write not as expected" ) )
return false;
- printf( "writeOverL2 successful!\n" );
+ printf( "writeNotOnBlockBorder successful!\n" );
return true;
}
-
// perhaps do some initial markers on the file
bool writeNotOnBlockBorder()
{
- char buff[blocksize * 2];
- char expected[blocksize * 2];
- memset( expected, 0, blocksize * 2 );
- size_t offset = blocksize * 11 - blocksize / 2;
- if ( !readSizeTested( fh, buff, blocksize * 2, offset, "writeNotOnBlockBorder test Failed: read to small" ) )
- return false;
- if ( !compare( buff, expected, blocksize * 2, "writeNotOnBlockBorder test Failed: initial read" ) )
+ char buff[DNBD3_BLOCK_SIZE * 2];
+ char expected[DNBD3_BLOCK_SIZE * 2];
+ memset( expected, 0, DNBD3_BLOCK_SIZE * 2 );
+ size_t offset = DNBD3_BLOCK_SIZE * 11 - DNBD3_BLOCK_SIZE / 2;
+ if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 2, offset, "writeNotOnBlockBorder test Failed: read to small" ) )
return false;
- memset( expected, 1, blocksize * 2 );
- if ( !writeSizeTested( fh, expected, blocksize * 2, offset, "writeNotOnBlockBorder test Failed: write failed" ) )
+ if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2, "writeNotOnBlockBorder test Failed: initial read" ) )
return false;
- if ( !readSizeTested( fh, buff, blocksize * 2, offset, "writeNotOnBlockBorder test Failed: read to small" ) )
+ memset( expected, 1, DNBD3_BLOCK_SIZE * 2 );
+ if ( !writeSizeTested(
+ fh, expected, DNBD3_BLOCK_SIZE * 2, offset, "writeNotOnBlockBorder test Failed: write failed" ) )
return false;
- if ( !compare( buff, expected, blocksize * 2, "writeNotOnBlockBorder test Failed: write not as expected" ) )
- return false;
- printf( "writeNotOnBlockBorder successful!\n" );
- return true;
+ return verifyWriteNotOnBlockBorder();
}
+
bool fileSizeChanges()
{
// increase filesize
@@ -211,22 +263,24 @@ bool fileSizeChanges()
return false;
}
// check if increased is 0
- char buff[blocksize * 10];
- char expected[blocksize * 10];
- memset( expected, 0, blocksize * 10 );
- if ( !readSizeTested(
- fh, buff, blocksize * 10, testFileSize + l2Capacity, "fileSizeChanges test Failed: read to small" ) )
+ char buff[DNBD3_BLOCK_SIZE * 10];
+ char expected[DNBD3_BLOCK_SIZE * 10];
+ memset( expected, 0, DNBD3_BLOCK_SIZE * 10 );
+ if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 10, testFileSize + l2Capacity,
+ "fileSizeChanges test Failed: read to small" ) )
return false;
- if ( !compare( buff, expected, blocksize * 10, "fileSizeChanges test Failed: increased data not 0" ) )
+ if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 10, "fileSizeChanges test Failed: increased data not 0" ) )
return false;
printf( "increased data is 0 as expected\n" );
// write on increased blocks
- memset( expected, 1, blocksize * 10 );
- if ( !writeSizeTested( fh, expected, blocksize * 10, testFileSize, "fileSizeChanges test Failed: write failed" ) )
+ memset( expected, 1, DNBD3_BLOCK_SIZE * 10 );
+ if ( !writeSizeTested(
+ fh, expected, DNBD3_BLOCK_SIZE * 10, testFileSize, "fileSizeChanges test Failed: write failed" ) )
return false;
- if ( !readSizeTested( fh, buff, blocksize * 10, testFileSize, "fileSizeChanges test Failed: read to small" ) )
+ if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 10, testFileSize, "fileSizeChanges test Failed: read to small" ) )
return false;
- if ( !compare( buff, expected, blocksize * 10, "fileSizeChanges test Failed: write on increased size failed" ) )
+ if ( !compare(
+ buff, expected, DNBD3_BLOCK_SIZE * 10, "fileSizeChanges test Failed: write on increased size failed" ) )
return false;
printf( "writes to new Block Ok\n" );
// decrease filesize
@@ -259,56 +313,71 @@ bool fileSizeChanges()
return false;
}
printf( "size verified\n" );
- memset( expected, 0, blocksize * 10 );
+ memset( expected, 0, DNBD3_BLOCK_SIZE * 10 );
- if ( !readSizeTested( fh, buff, blocksize * 10, testFileSize, "fileSizeChanges test Failed: read to small" ) )
+ if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 10, testFileSize, "fileSizeChanges test Failed: read to small" ) )
return false;
- if ( !compare( buff, expected, blocksize * 2, "fileSizeChanges test Failed: increased data (second time) not 0" ) )
+ if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2,
+ "fileSizeChanges test Failed: increased data (second time) not 0" ) )
return false;
printf( "fileSizeChanges successful!\n" );
return true;
}
+
+bool verifyInterleavedTest()
+{
+ char buff[DNBD3_BLOCK_SIZE * 10];
+ char expected[DNBD3_BLOCK_SIZE * 10];
+ off_t offset = 35 * DNBD3_BLOCK_SIZE;
+ memset( expected, 0, DNBD3_BLOCK_SIZE * 10 );
+ memset( expected, 10, DNBD3_BLOCK_SIZE );
+ memset( ( expected + ( DNBD3_BLOCK_SIZE * 2 ) ), 12, DNBD3_BLOCK_SIZE );
+ memset( ( expected + ( DNBD3_BLOCK_SIZE * 4 ) ), 14, DNBD3_BLOCK_SIZE );
+ memset( ( expected + ( DNBD3_BLOCK_SIZE * 5 ) ), 15, DNBD3_BLOCK_SIZE );
+ memset( ( expected + ( DNBD3_BLOCK_SIZE * 8 ) ), 18, DNBD3_BLOCK_SIZE );
+ if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 10, offset, "interleavedTest test Failed: read 2 to small" ) )
+ return false;
+ if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 10, "interleavedTest test Failed: read not as expected" ) )
+ return false;
+ printf( "interleavedTest successful!\n" );
+ return true;
+}
+
bool interleavedTest()
{
printf( "starting interleavedTest \n" );
- char buff[blocksize * 10];
- char expected[blocksize * 10];
- off_t offset = 35 * blocksize;
- memset( expected, 0, blocksize * 10 );
- if ( !readSizeTested( fh, buff, blocksize * 10, offset, "interleavedTest test Failed: read to small" ) )
+ char buff[DNBD3_BLOCK_SIZE * 10];
+ char expected[DNBD3_BLOCK_SIZE * 10];
+ off_t offset = 35 * DNBD3_BLOCK_SIZE;
+ memset( expected, 0, DNBD3_BLOCK_SIZE * 10 );
+ if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 10, offset, "interleavedTest test Failed: read to small" ) )
return false;
- if ( !compare( buff, expected, blocksize * 10, "interleavedTest test Failed: read data not 0" ) )
+ if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 10, "interleavedTest test Failed: read data not 0" ) )
return false;
- memset( expected, 10, blocksize );
- if ( !writeSizeTested( fh, expected, blocksize, offset, "interleavedTest test Failed: write 1 failed" ) )
+ memset( expected, 10, DNBD3_BLOCK_SIZE );
+ if ( !writeSizeTested( fh, expected, DNBD3_BLOCK_SIZE, offset, "interleavedTest test Failed: write 1 failed" ) )
return false;
- memset( ( expected + ( blocksize * 2 ) ), 12, blocksize );
- if ( !writeSizeTested( fh, ( expected + ( blocksize * 2 ) ), blocksize, offset + blocksize * 2,
+ memset( ( expected + ( DNBD3_BLOCK_SIZE * 2 ) ), 12, DNBD3_BLOCK_SIZE );
+ if ( !writeSizeTested( fh, ( expected + ( DNBD3_BLOCK_SIZE * 2 ) ), DNBD3_BLOCK_SIZE, offset + DNBD3_BLOCK_SIZE * 2,
"interleavedTest test Failed: write 2 failed" ) )
return false;
- memset( ( expected + ( blocksize * 4 ) ), 14, blocksize );
- memset( ( expected + ( blocksize * 5 ) ), 15, blocksize );
+ memset( ( expected + ( DNBD3_BLOCK_SIZE * 4 ) ), 14, DNBD3_BLOCK_SIZE );
+ memset( ( expected + ( DNBD3_BLOCK_SIZE * 5 ) ), 15, DNBD3_BLOCK_SIZE );
- if ( !writeSizeTested( fh, ( expected + ( blocksize * 4 ) ), blocksize * 2, offset + blocksize * 4,
- "interleavedTest test Failed: write 3 failed" ) )
+ if ( !writeSizeTested( fh, ( expected + ( DNBD3_BLOCK_SIZE * 4 ) ), DNBD3_BLOCK_SIZE * 2,
+ offset + DNBD3_BLOCK_SIZE * 4, "interleavedTest test Failed: write 3 failed" ) )
return false;
- memset( ( expected + ( blocksize * 8 ) ), 18, blocksize );
- if ( !writeSizeTested( fh, ( expected + ( blocksize * 8 ) ), blocksize, offset + blocksize * 8,
+ memset( ( expected + ( DNBD3_BLOCK_SIZE * 8 ) ), 18, DNBD3_BLOCK_SIZE );
+ if ( !writeSizeTested( fh, ( expected + ( DNBD3_BLOCK_SIZE * 8 ) ), DNBD3_BLOCK_SIZE, offset + DNBD3_BLOCK_SIZE * 8,
"interleavedTest test Failed: write 4 failed" ) )
return false;
-
- if ( !readSizeTested( fh, buff, blocksize * 10, offset, "interleavedTest test Failed: read 2 to small" ) )
- return false;
- if ( !compare( buff, expected, blocksize * 10, "interleavedTest test Failed: read not as expected" ) )
- return false;
- printf( "interleavedTest successful!\n" );
- return true;
+ return verifyInterleavedTest();
}
void runTest( char *path )
@@ -320,20 +389,38 @@ void runTest( char *path )
}
strcpy( filePath, path );
printf( "file opened: %s\n", path );
+
if ( !testFirstBit() )
return;
if ( !writeOverTwoBlocks() )
return;
+
+ if ( !writeNotOnBlockBorder() )
+ return;
+
if ( !writeOverL2() )
return;
if ( !fileSizeChanges() )
return;
if ( !interleavedTest() )
return;
+
printf( "All test's successful.\n" );
}
+void verifyTests( verify_test_t *tests )
+{
+ // offset, size, function
+
+ tests[0] = ( verify_test_t ){ 0, DNBD3_BLOCK_SIZE, verifyTestFirstBit };
+ tests[1] = ( verify_test_t ){ DNBD3_BLOCK_SIZE * 3, DNBD3_BLOCK_SIZE * 3, verifyWriteOverTwoBlocks };
+ tests[2] = ( verify_test_t ){ DNBD3_BLOCK_SIZE * 11 - DNBD3_BLOCK_SIZE / 2, DNBD3_BLOCK_SIZE * 2,
+ verifyWriteNotOnBlockBorder };
+ tests[3] = ( verify_test_t ){ 35 * DNBD3_BLOCK_SIZE, DNBD3_BLOCK_SIZE * 10, verifyInterleavedTest };
+ tests[4] = ( verify_test_t ){ l2Capacity * 2 - DNBD3_BLOCK_SIZE, DNBD3_BLOCK_SIZE * 2, verifyWriteOverL2 };
+}
+
void verifyFinalFile( char *path )
{
if ( ( fh = open( path, O_RDWR, S_IRUSR | S_IWUSR ) ) == -1 ) {
@@ -341,6 +428,64 @@ void verifyFinalFile( char *path )
printf( "Given path: %s \n", path );
return;
}
+ // verify file size
+
+ size_t fileSize = testFileSize + 2 * l2Capacity;
+ struct stat st;
+ stat( path, &st );
+ size_t size = st.st_size;
+ if ( size != fileSize ) {
+ printf( "verify Failed, wrong file size\n expectedSize: %zu\n got: %zu\n", fileSize, size );
+ return;
+ }
+
+ // read to whole file
+
+ int maxReadSize = DNBD3_BLOCK_SIZE * COW_BITFIELD_SIZE;
+ char buffer[maxReadSize];
+ char emptyData[maxReadSize];
+ memset( emptyData, 0, maxReadSize );
+ size_t offset = 0;
+
+
+ int numberOfTests = 5;
+ verify_test_t tests[numberOfTests];
+ verifyTests( tests );
+
+ int currentTest = 0;
+ //verifyWriteOverTwoBlocks();
+ //verifyWriteNotOnBlockBorder();
+ //verifyInterleavedTest();
+ //verifyWriteOverL2();
+
+
+ while ( offset < fileSize ) {
+ size_t sizeToRead = MIN( maxReadSize, fileSize - offset );
+ if ( currentTest < numberOfTests ) {
+ sizeToRead = MIN( sizeToRead, tests[currentTest].offset - offset );
+ }
+ if ( currentTest < numberOfTests && tests[currentTest].offset == (off_t)offset ) {
+ if ( !tests[currentTest].test() ) {
+ return;
+ }
+ offset += tests[currentTest].size;
+ currentTest++;
+ } else {
+ ssize_t sizeRead = pread( fh, buffer, sizeToRead, offset );
+ if ( sizeRead <= 0 ) {
+ perror( "Error while reading data: " );
+ printf( "verify failed. \n" );
+ return;
+ }
+ if ( !compare( buffer, emptyData, sizeRead, "verify failed. Expected 0 data" ) ) {
+ printf( "Offset: %zu \n", offset );
+ return;
+ }
+ offset += (size_t)sizeRead;
+ }
+ }
+
+ printf( "file verified successful.\n" );
}
void execCommand( char command, char *parameters )
@@ -367,7 +512,7 @@ void execCommand( char command, char *parameters )
break;
}
printf( "verifing file \n" );
- runTest( parameters );
+ verifyFinalFile( parameters );
break;
default:
printf( "Command not Found \n" );
diff --git a/src/fuse/cowfile.c b/src/fuse/cowfile.c
index 48b4174..d020aec 100644
--- a/src/fuse/cowfile.c
+++ b/src/fuse/cowfile.c
@@ -11,28 +11,41 @@ static struct cow
int fhm;
int fhd;
char *metadata_mmap;
- cow_block_metadata_t **l1;
- l2 nextL2;
- atomic_size_t metadataFileSize;
- atomic_size_t dataFileSize;
+ l1 *l1;
+ l2 *firstL2;
size_t maxImageSize;
-
size_t l1Size; //size of l1 array
- int l2Size; //size of an l2 array
- size_t metadataStorageCapacity;
- size_t l2StorageCapacity; // memory a l2 array can address
} cow;
+/**
+ * @brief computes the l1 offset from the absolute file offset
+ *
+ * @param offset absolute file offset
+ * @return int l2 offset
+ */
static int getL1Offset( size_t offset )
{
- return (int)( offset / cow.l2StorageCapacity );
+ return (int)( offset / COW_L2_STORAGE_CAPACITY );
}
+/**
+ * @brief computes the l2 offset from the absolute file offset
+ *
+ * @param offset absolute file offset
+ * @return int l2 offset
+ */
static int getL2Offset( size_t offset )
{
- return (int)( ( offset % cow.l2StorageCapacity ) / cow.metadataStorageCapacity );
+ return (int)( ( offset % COW_L2_STORAGE_CAPACITY ) / COW_METADAT_STORAGE_CAPACITY );
}
+
+/**
+ * @brief computes the bit in the bitfield from the absolute file offset
+ *
+ * @param offset absolute file offset
+ * @return int bit(0-39) in the bitfield
+ */
static int getBitfieldOffset( size_t offset )
{
return (int)( offset / DNBD3_BLOCK_SIZE ) % COW_BITFIELD_SIZE;
@@ -47,8 +60,8 @@ static int getBitfieldOffset( size_t offset )
*/
static void setBits( atomic_char *byte, int from, int to )
{
- char mask =(char) (((255-from) >> (7-(to-from))));
- atomic_fetch_or(byte, (mask));
+ char mask = (char)( 255 >> ( 7 - ( to - from ) ) ) << from;
+ atomic_fetch_or( byte, ( *byte | mask ) );
}
/**
@@ -60,6 +73,7 @@ static void setBits( atomic_char *byte, int from, int to )
*/
static void setBitsInBitfield( atomic_char *bitfield, int from, int to )
{
+ assert( from >= 0 || to < COW_BITFIELD_SIZE );
int start = from / 8;
int end = to / 8;
@@ -80,6 +94,13 @@ static bool checkBit( atomic_char *bitfield, int n )
return ( atomic_load( ( bitfield + ( n / 8 ) ) ) >> ( n % 8 ) ) & 1;
}
+/**
+ * @brief initializes the cow functionality, creates the .data & .meta file.
+ *
+ * @param path where the files should be stored
+ * @param image_Name name of the original file/image
+ * @param imageSizePtr
+ */
bool cowfile_init( char *path, const char *image_Name, size_t **imageSizePtr )
{
char pathMeta[strlen( path ) + 6];
@@ -97,146 +118,274 @@ bool cowfile_init( char *path, const char *image_Name, size_t **imageSizePtr )
logadd( LOG_ERROR, "Could not create cow data file. Bye.\n" );
return false;
}
- cow.dataFileSize = 0;
- // create Meta Data Mapping
- int pageSize = getpagesize();
+
int maxPageSize = 8192;
// TODO IMAGE NAME IS FIXED
size_t metaDataSizeHeader = sizeof( cowfile_metadata_header_t ) + strlen( image_Name );
- cow.maxImageSize = 1000LL * 1000LL * 1000LL * 1000LL; // tb*gb*mb*kb
- cow.l2Size = 1024;
-
- cow.metadataStorageCapacity = COW_BITFIELD_SIZE* DNBD3_BLOCK_SIZE;
- cow.l2StorageCapacity = ( cow.l2Size * cow.metadataStorageCapacity );
-
- cow.l1Size = ( ( cow.maxImageSize + cow.l2StorageCapacity - 1LL ) / cow.l2StorageCapacity );
-
- size_t metadata_size = cow.l1Size * sizeof( l1 ) + cow.l1Size * cow.l2Size * sizeof( l2 )
- + cow.l1Size * cow.l2Size * ( sizeof( cow_block_metadata_t ) );
+ cow.maxImageSize = 1000LL * 1000LL * 1000LL * 1000LL; // tb*gb*mb*kb todo make this changeable
+ cow.l1Size = ( ( cow.maxImageSize + COW_L2_STORAGE_CAPACITY - 1LL ) / COW_L2_STORAGE_CAPACITY );
+ // size of l1 array + number of l2's * size of l2
+ size_t metadata_size = cow.l1Size * sizeof( l1 ) + cow.l1Size * sizeof( l2 );
- //compute next fitting multiple of getpagesize()
+ // compute next fitting multiple of getpagesize()
size_t meta_data_start = ( ( metaDataSizeHeader + maxPageSize - 1 ) / maxPageSize ) * maxPageSize;
- cow.metadataFileSize = meta_data_start + metadata_size;
- if ( pwrite( cow.fhm, "", 1, cow.metadataFileSize ) != 1 ) {
+ size_t metadataFileSize = meta_data_start + metadata_size;
+ if ( pwrite( cow.fhm, "", 1, metadataFileSize ) != 1 ) {
logadd( LOG_ERROR, "Could not write cow meta_data_table to file. Bye.\n" );
return false;
}
- cow.metadata_mmap = mmap( NULL, cow.metadataFileSize, PROT_READ | PROT_WRITE, MAP_SHARED, cow.fhm, 0 );
+ cow.metadata_mmap = mmap( NULL, metadataFileSize, PROT_READ | PROT_WRITE, MAP_SHARED, cow.fhm, 0 );
if ( cow.metadata_mmap == MAP_FAILED ) {
- logadd( LOG_ERROR, "Error while mapping mmap. Bye.\n" );
+ logadd( LOG_ERROR, "Error while mapping mmap:\n%s \n Bye.\n", strerror( errno ) );
return false;
}
-
- size_t *metaDataHeaderSizePtr = (size_t *)cow.metadata_mmap;
- *metaDataHeaderSizePtr = metaDataSizeHeader;
- metadata = (cowfile_metadata_header_t *)( cow.metadata_mmap + sizeof( size_t ) );
+ metadata = (cowfile_metadata_header_t *)( cow.metadata_mmap );
+ metadata->magicValue = COW_FILE_META_MAGIC_VALUE;
metadata->version = cowFileVersion;
- metadata->blocksize = pageSize;
+ metadata->dataFileSize = ATOMIC_VAR_INIT( 0 );
+ metadata->metadataFileSize = ATOMIC_VAR_INIT( 0 );
+ metadata->metadataFileSize = metadataFileSize;
+ metadata->blocksize = DNBD3_BLOCK_SIZE;
metadata->originalImageSize = **imageSizePtr;
metadata->imageSize = metadata->originalImageSize;
+ metadata->creationTime = time( NULL );
*imageSizePtr = &metadata->imageSize;
-
metadata->metaDataStart = meta_data_start;
-
-
metadata->bitfieldSize = COW_BITFIELD_SIZE;
metadata->maxImageSize = cow.maxImageSize;
strcpy( metadata->imageName, image_Name );
- cow.l1 = (cow_block_metadata_t **)( cow.metadata_mmap + meta_data_start );
-
+ cow.l1 = (l1 *)( cow.metadata_mmap + meta_data_start );
+ metadata->nextL2 = 0;
for ( size_t i = 0; i < cow.l1Size; i++ ) {
- cow.l1[i] = NULL;
+ cow.l1[i] = -1;
}
- cow.nextL2 = (l2)( cow.l1 + cow.l1Size );
+ cow.firstL2 = (l2 *)( ( (char *)cow.l1 ) + cow.l1Size );
+
+ // write header to data file
+ uint64_t header = COW_FILE_DATA_MAGIC_VALUE;
+ if ( pwrite( cow.fhd, &header, sizeof( uint64_t ), 0 ) != sizeof( uint64_t ) ) {
+ logadd( LOG_ERROR, "Could not write header to cow data file. Bye.\n" );
+ return false;
+ }
+ // move the dataFileSize to make room for the header
+ atomic_store( &metadata->dataFileSize, COW_METADAT_STORAGE_CAPACITY );
+
pthread_mutex_init( &cow.l2CreateLock, NULL );
return 1;
}
+/**
+ * @brief loads an existing cow state from the .meta & .data files
+ *
+ * @param path where the .meta & .data file is located
+ * @param imageSizePtr
+ */
-bool cowfile_load( char *path )
+bool cowfile_load( char *path, size_t **imageSizePtr )
{
- if ( ( cow.fhm = open( strcat( path, ".meta" ), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR ) ) == -1 ) {
+ char pathMeta[strlen( path ) + 6];
+ char pathData[strlen( path ) + 6];
+ strcpy( pathMeta, path );
+ strcpy( pathData, path );
+ strcat( pathMeta, ".meta" );
+ strcat( pathData, ".data" );
+ if ( ( cow.fhm = open( pathMeta, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR ) ) == -1 ) {
logadd( LOG_ERROR, "Could not open cow meta file. Bye.\n" );
return false;
}
- if ( ( cow.fhd = open( strcat( path, ".data" ), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR ) ) == -1 ) {
+ if ( ( cow.fhd = open( pathData, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR ) ) == -1 ) {
logadd( LOG_ERROR, "Could not open cow data file. Bye.\n" );
return false;
}
- size_t metaDataSizeHeader;
- ssize_t bytesRead = read( cow.fhm, &metaDataSizeHeader, sizeof( size_t ) );
- if ( bytesRead < (ssize_t)sizeof( size_t ) ) {
- if ( bytesRead < 0 ) {
- logadd( LOG_ERROR, "Error while reading metaDataSizeHeader: " );
- } else {
- logadd( LOG_ERROR, "metaDataSizeHeader smaller than expected. Bye.\n" );
+
+ cowfile_metadata_header_t header;
+ {
+ size_t sizeToRead = sizeof( cowfile_metadata_header_t );
+ size_t readBytes = 0;
+ while ( readBytes < sizeToRead ) {
+ ssize_t bytes = pread( cow.fhm, ( ( &header ) + readBytes ), sizeToRead, 0 );
+ if ( bytes <= 0 ) {
+ logadd( LOG_ERROR, "Error while reading meta file header. Bye.\n" );
+ return false;
+ }
+ readBytes += bytes;
+ }
+
+
+ if ( header.magicValue != COW_FILE_META_MAGIC_VALUE ) {
+ if ( __builtin_bswap64( header.magicValue ) == COW_FILE_META_MAGIC_VALUE ) {
+ logadd( LOG_ERROR, "cow meta file of wrong endianess. Bye.\n" );
+ return false;
+ }
+ logadd( LOG_ERROR, "cow meta file of unkown format. Bye.\n" );
+ return false;
+ }
+ struct stat st;
+ stat( pathMeta, &st );
+ if ( (long)st.st_size < (long)header.metaDataStart + (long)header.nextL2 * (long)sizeof( l2 ) ) {
+ logadd( LOG_ERROR, "cow meta file to small. Bye.\n" );
+ return false;
}
- return false;
}
- cowfile_metadata_header_t *metadata = malloc( metaDataSizeHeader );
- bytesRead = read( cow.fhm, metadata, metaDataSizeHeader );
- if ( bytesRead < (ssize_t)sizeof( size_t ) ) {
- if ( bytesRead < 0 ) {
- logadd( LOG_ERROR, "Error while reading metadata. Bye.\n" );
- } else {
- logadd( LOG_ERROR, "metadata smaller than expected. Bye.\n" );
+ {
+ uint64_t magicValueDataFile;
+ pread( cow.fhd, &magicValueDataFile, sizeof( uint64_t ), 0 );
+
+ if ( magicValueDataFile != COW_FILE_DATA_MAGIC_VALUE ) {
+ if ( __builtin_bswap64( magicValueDataFile ) == COW_FILE_DATA_MAGIC_VALUE ) {
+ logadd( LOG_ERROR, "cow data file of wrong endianess. Bye.\n" );
+ return false;
+ }
+ logadd( LOG_ERROR, "cow data file of unkown format. Bye.\n" );
+ return false;
}
+ struct stat st;
+ stat( pathData, &st );
+ if ( (long)header.dataFileSize < st.st_size ) {
+ logadd( LOG_ERROR, "cow data file to small. Bye.\n" );
+ return false;
+ }
+ }
+
+ cow.metadata_mmap = mmap( NULL, header.metadataFileSize, PROT_READ | PROT_WRITE, MAP_SHARED, cow.fhm, 0 );
+
+ if ( cow.metadata_mmap == MAP_FAILED ) {
+ logadd( LOG_ERROR, "Error while mapping mmap:\n%s \n Bye.\n", strerror( errno ) );
+ return false;
+ }
+ if ( header.version != cowFileVersion ) {
+ logadd( LOG_ERROR, "Error wrong file version got: %i expected: 1. Bye.\n", metadata->version );
return false;
}
- logadd( LOG_DEBUG1, "===Image Name===: %s\n", metadata->imageName );
+
+
+ metadata = (cowfile_metadata_header_t *)( cow.metadata_mmap );
+
+ *imageSizePtr = &metadata->imageSize;
+ cow.l1 = (l1 *)( cow.metadata_mmap + metadata->metaDataStart );
+ cow.maxImageSize = metadata->maxImageSize;
+ cow.l1Size = ( ( cow.maxImageSize + COW_L2_STORAGE_CAPACITY - 1LL ) / COW_L2_STORAGE_CAPACITY );
+
+ cow.firstL2 = (l2 *)( ( (char *)cow.l1 ) + cow.l1Size );
+ pthread_mutex_init( &cow.l2CreateLock, NULL );
return true;
}
-static void writeData( const char *buffer, size_t size, size_t netSize, cow_request_t *cowRequest, cow_block_metadata_t *block,
- off_t inBlockOffset )
+/**
+ * @brief writes the given data in the .data file
+ *
+ * @param buffer containing the data
+ * @param size of the buffer
+ * @param netSize which actually contributes to the fuse write request (can be different from size if partial full blocks are written)
+ * @param cowRequest
+ * @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 )
{
- ssize_t bytesWritten = pwrite( cow.fhd, buffer, size, block->offset + inBlockOffset );
-
- if ( bytesWritten == -1 ) {
- cowRequest->errorCode = errno;
- } else if ( (size_t)bytesWritten < size ) {
- cowRequest->errorCode = EIO;
+ 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;
+ break;
+ } else if ( bytesWritten == 0 ) {
+ cowRequest->errorCode = EIO;
+ break;
+ }
+ totalBytesWritten += bytesWritten;
}
atomic_fetch_add( &cowRequest->bytesWorkedOn, netSize );
- setBitsInBitfield(
- block->bitfield, (int)( inBlockOffset / DNBD3_BLOCK_SIZE ), (int)( ( inBlockOffset + size ) / DNBD3_BLOCK_SIZE ) );
- block->timeChanged = (atomic_uint_fast32_t)time( NULL );
+ setBitsInBitfield( block->bitfield, (int)( inBlockOffset / DNBD3_BLOCK_SIZE ),
+ (int)( ( inBlockOffset + totalBytesWritten - 1 ) / DNBD3_BLOCK_SIZE ) );
+
+ block->timeChanged = (atomic_uint_fast32_t)( time( NULL ) - metadata->creationTime );
+}
+
+/**
+ * @brief
+ *
+ * @param block
+ * @return true
+ * @return false
+ */
+static bool allocateMetaBlockData( cow_block_metadata_t *block )
+{
+ block->offset = (atomic_long)atomic_fetch_add( &metadata->dataFileSize, COW_METADAT_STORAGE_CAPACITY );
+ return true;
}
+/**
+ * @brief Get the cow_block_metadata_t from l1Offset and l2Offset
+ *
+ * @param l1Offset
+ * @param l2Offset
+ * @return cow_block_metadata_t*
+ */
+static cow_block_metadata_t *getBlock( int l1Offset, int l2Offset )
+{
+ cow_block_metadata_t *block = ( cow.firstL2[cow.l1[l1Offset]] + l2Offset );
+ if ( block->offset == -1 ) {
+ allocateMetaBlockData( block );
+ }
+ return block;
+}
+/**
+ * @brief creates an new L2 Block and initializes the containing cow_block_metadata_t blocks
+ *
+ * @param l1Offset
+ */
static bool createL2Block( int l1Offset )
{
pthread_mutex_lock( &cow.l2CreateLock );
- if ( cow.l1[l1Offset] == NULL ) {
- for ( int i = 0; i < cow.l2Size; i++ ) {
- cow.nextL2[i].offset = -1;
- cow.nextL2[i].timeChanged = 0;
- cow.nextL2[i].timeUploaded = 0;
- for (int j = 0; j < COW_BITFIELD_SIZE; j++){
- cow.nextL2[i].bitfield[j] = ATOMIC_VAR_INIT( 0 );
+ if ( cow.l1[l1Offset] == -1 ) {
+ for ( int i = 0; i < COW_L2_SIZE; i++ ) {
+ cow.firstL2[metadata->nextL2][i].offset = -1;
+ cow.firstL2[metadata->nextL2][i].timeChanged = 0;
+ cow.firstL2[metadata->nextL2][i].timeUploaded = 0;
+ for ( int j = 0; j < COW_BITFIELD_SIZE; j++ ) {
+ cow.firstL2[metadata->nextL2][i].bitfield[j] = ATOMIC_VAR_INIT( 0 );
}
}
- cow.l1[l1Offset] = cow.nextL2;
- cow.nextL2 += cow.l2Size;
+ cow.l1[l1Offset] = metadata->nextL2;
+ metadata->nextL2 += 1;
}
pthread_mutex_unlock( &cow.l2CreateLock );
return true;
}
-static bool allocateMetaBlockData( cow_block_metadata_t *block )
+static void finishWriteRequest( fuse_req_t req, cow_request_t *cowRequest )
{
- block->offset = (atomic_long)atomic_fetch_add( &cow.dataFileSize, cow.metadataStorageCapacity );
- return true;
+ if ( cowRequest->errorCode != 0 ) {
+ fuse_reply_err( req, cowRequest->errorCode );
+
+ } else {
+ metadata->imageSize = MAX( metadata->imageSize, cowRequest->bytesWorkedOn + cowRequest->fuseRequestOffset );
+ if ( cowRequest->replyAttr ) {
+ //TODO HANDLE ERROR
+ image_ll_getattr( req, cowRequest->ino, cowRequest->fi );
+
+ } else {
+ fuse_reply_write( req, cowRequest->bytesWorkedOn );
+ }
+ }
+ if ( cowRequest->replyAttr ) {
+ free( (char *)cowRequest->writeBuffer );
+ }
+ free( cowRequest );
}
@@ -245,15 +394,16 @@ static bool allocateMetaBlockData( cow_block_metadata_t *block )
* @brief
*
*/
-static void padBlockFromRemote( fuse_req_t req, off_t offset, cow_request_t *cowRequest, cow_write_request_t *cowWriteRequest )
+static void padBlockFromRemote(
+ fuse_req_t req, off_t offset, cow_request_t *cowRequest, cow_write_request_t *cowWriteRequest )
{
if ( offset > (off_t)metadata->originalImageSize ) {
//pad 0 and done
char buffer[DNBD3_BLOCK_SIZE] = { 0 };
memcpy( buffer, cowWriteRequest->buffer, cowWriteRequest->size );
- writeData(
- buffer, DNBD3_BLOCK_SIZE, cowWriteRequest->size, cowRequest, cowWriteRequest->block, cowWriteRequest->inBlockOffset );
+ writeData( buffer, DNBD3_BLOCK_SIZE, (ssize_t)cowWriteRequest->size, cowRequest, cowWriteRequest->block,
+ cowWriteRequest->inBlockOffset );
free( cowWriteRequest );
return;
}
@@ -281,46 +431,14 @@ static void padBlockFromRemote( fuse_req_t req, off_t offset, cow_request_t *cow
}
}
-void cowFile_readRemoteData( dnbd3_async_t *request )
-{
- atomic_fetch_add( &request->cow->bytesWorkedOn, request->length );
- if ( atomic_fetch_sub( &request->cow->workCounter, 1 ) == 1 ) {
- fuse_reply_buf( request->fuse_req, request->cow->readBuffer, request->cow->bytesWorkedOn );
- free( request->cow->readBuffer );
- free( request->cow );
- }
- free( request );
-}
-
-static void finishWriteRequest( fuse_req_t req, cow_request_t *cowRequest )
-{
- if ( cowRequest->errorCode != 0 ) {
- fuse_reply_err( req, cowRequest->errorCode );
-
- } else {
- metadata->imageSize = MAX( metadata->imageSize, cowRequest->bytesWorkedOn + cowRequest->fuseRequestOffset );
- if ( cowRequest->replyAttr ) {
- //TODO HANDLE ERROR
- image_ll_getattr( req, cowRequest->ino, cowRequest->fi );
-
- } else {
- fuse_reply_write( req, cowRequest->bytesWorkedOn );
- }
- }
- if ( cowRequest->replyAttr ) {
- free( (char *)cowRequest->writeBuffer );
- }
- free( cowRequest );
-}
-
-
void cowfile_writePaddedBlock( dnbd3_async_t *request )
{
//copy write Data
- memcpy( request->buffer + ( request->cow_write->inBlockOffset % DNBD3_BLOCK_SIZE ), request->cow_write->buffer,
+ memcpy( ( request->buffer + ( request->cow_write->inBlockOffset % DNBD3_BLOCK_SIZE ) ), request->cow_write->buffer,
request->cow_write->size );
- writeData( request->buffer, DNBD3_BLOCK_SIZE, request->cow_write->size, request->cow, request->cow_write->block,
- request->cow_write->inBlockOffset );
+ writeData( request->buffer, DNBD3_BLOCK_SIZE, (ssize_t)request->cow_write->size, request->cow,
+ request->cow_write->block,
+ ( request->cow_write->inBlockOffset - ( request->cow_write->inBlockOffset % DNBD3_BLOCK_SIZE ) ) );
free( request->cow_write );
if ( atomic_fetch_sub( &request->cow->workCounter, 1 ) == 1 ) {
@@ -330,11 +448,23 @@ void cowfile_writePaddedBlock( dnbd3_async_t *request )
free( request );
}
+void cowFile_readRemoteData( dnbd3_async_t *request )
+{
+ atomic_fetch_add( &request->cow->bytesWorkedOn, request->length );
+ if ( atomic_fetch_sub( &request->cow->workCounter, 1 ) == 1 ) {
+ fuse_reply_buf( request->fuse_req, request->cow->readBuffer, request->cow->bytesWorkedOn );
+ free( request->cow->readBuffer );
+ free( request->cow );
+ }
+ free( request );
+}
+
+
/// TODO move block padding in write
void cowfile_write( fuse_req_t req, cow_request_t *cowRequest, off_t offset, size_t size )
{
if ( cowRequest->replyAttr ) {
- cowRequest->writeBuffer = calloc( sizeof( char ), MIN( size, cow.metadataStorageCapacity ) );
+ cowRequest->writeBuffer = calloc( sizeof( char ), MIN( size, COW_METADAT_STORAGE_CAPACITY ) );
}
// if beyond end of file, pad with 0
if ( offset > (off_t)metadata->imageSize ) {
@@ -346,88 +476,75 @@ void cowfile_write( fuse_req_t req, cow_request_t *cowRequest, off_t offset, siz
cowfile_write( req, cowRequest, metadata->imageSize, pSize );
}
- // TODO PREVENT RACE CONDITION on not full block writes
off_t currentOffset = offset;
off_t endOffset = offset + size;
- // get start & end block if needed( not on border and not already there)
- if ( offset % DNBD3_BLOCK_SIZE != 0 ) {
- int l1Offset = getL1Offset( offset );
- int l2Offset = getL2Offset( offset );
- if ( cow.l1[l1Offset] == NULL ) {
- createL2Block( l1Offset );
- }
- cow_block_metadata_t *metaBlock = &( cow.l1[l1Offset] )[l2Offset];
- size_t metaBlockStartOffset = l1Offset * cow.l2StorageCapacity + l2Offset * cow.metadataStorageCapacity;
- size_t inBlockOffset = offset - metaBlockStartOffset;
-
-
- if ( !checkBit( metaBlock->bitfield, (int)( inBlockOffset / DNBD3_BLOCK_SIZE ) ) ) {
- size_t padSize = MIN( size, DNBD3_BLOCK_SIZE - ( (size_t)offset % DNBD3_BLOCK_SIZE ) );
- cow_write_request_t *cowWriteRequest = malloc( sizeof( cow_write_request_t ) );
- cowWriteRequest->inBlockOffset = (off_t)inBlockOffset;
- cowWriteRequest->block = metaBlock;
- cowWriteRequest->size = padSize;
- cowWriteRequest->buffer = cowRequest->writeBuffer;
- padBlockFromRemote( req, offset, cowRequest, cowWriteRequest );
- currentOffset += padSize;
- }
- }
- // also make sure endblock != start block
- if ( offset + size % DNBD3_BLOCK_SIZE != 0 && ( ( offset + (off_t)size ) / DNBD3_BLOCK_SIZE ) != ( offset / DNBD3_BLOCK_SIZE ) ) {
- int l1Offset = getL1Offset( offset + size );
- int l2Offset = getL2Offset( offset + size );
- if ( cow.l1[l1Offset] == NULL ) {
- createL2Block( l1Offset );
- }
- cow_block_metadata_t *metaBlock = &( cow.l1[l1Offset] )[l2Offset];
- if ( metaBlock->offset == -1 ) {
- allocateMetaBlockData( metaBlock );
- }
- size_t metaBlockStartOffset = l1Offset * cow.l2StorageCapacity + l2Offset * cow.metadataStorageCapacity;
- size_t padOffset = endOffset - ( endOffset % DNBD3_BLOCK_SIZE );
- size_t inBlockOffset = padOffset - metaBlockStartOffset;
-
-
- if ( !checkBit( metaBlock->bitfield, (int)( inBlockOffset / DNBD3_BLOCK_SIZE ) ) ) {
- cow_write_request_t *cowWriteRequest = malloc( sizeof( cow_write_request_t ) );
- cowWriteRequest->inBlockOffset = (off_t)inBlockOffset;
- cowWriteRequest->block = metaBlock;
- cowWriteRequest->size = endOffset - padOffset;
- cowWriteRequest->buffer = cowRequest->writeBuffer + ( padOffset - offset );
- padBlockFromRemote( req, padOffset, cowRequest, cowWriteRequest );
-
- endOffset = padOffset; //TODO written size
- }
- }
-
- // lock for have block probably needed
// write data
int l1Offset = getL1Offset( currentOffset );
int l2Offset = getL2Offset( currentOffset );
while ( currentOffset < endOffset ) {
- if ( cow.l1[l1Offset] == NULL ) {
+ if ( cow.l1[l1Offset] == -1 ) {
createL2Block( l1Offset );
}
//loop over L2 array (metadata)
- while ( currentOffset < (off_t)endOffset && l2Offset < cow.l2Size ) {
- cow_block_metadata_t *metaBlock = &( cow.l1[l1Offset] )[l2Offset];
- if ( metaBlock->offset == -1 ) {
- allocateMetaBlockData( metaBlock );
- }
- size_t metaBlockStartOffset = l1Offset * cow.l2StorageCapacity + l2Offset * cow.metadataStorageCapacity;
+ while ( currentOffset < (off_t)endOffset && l2Offset < COW_L2_SIZE ) {
+ cow_block_metadata_t *metaBlock = getBlock( l1Offset, l2Offset );
+
+
+ size_t metaBlockStartOffset = l1Offset * COW_L2_STORAGE_CAPACITY + l2Offset * COW_METADAT_STORAGE_CAPACITY;
size_t inBlockOffset = currentOffset - metaBlockStartOffset;
size_t sizeToWriteToBlock =
- MIN( (size_t)( endOffset - currentOffset ), cow.metadataStorageCapacity - inBlockOffset );
+ MIN( (size_t)( endOffset - currentOffset ), COW_METADAT_STORAGE_CAPACITY - inBlockOffset );
+
+
+ /////////////////////////
+ // lock for the half block probably needed
+ if ( currentOffset % DNBD3_BLOCK_SIZE != 0
+ && !checkBit( metaBlock->bitfield, (int)( inBlockOffset / DNBD3_BLOCK_SIZE ) ) ) {
+ // write remote
+ size_t padSize = MIN( sizeToWriteToBlock, DNBD3_BLOCK_SIZE - ( (size_t)currentOffset % DNBD3_BLOCK_SIZE ) );
+ cow_write_request_t *cowWriteRequest = malloc( sizeof( cow_write_request_t ) );
+ cowWriteRequest->inBlockOffset = (off_t)inBlockOffset;
+ cowWriteRequest->block = metaBlock;
+ cowWriteRequest->size = padSize;
+ cowWriteRequest->buffer = cowRequest->writeBuffer + ( ( currentOffset - offset ) * !cowRequest->replyAttr );
+ padBlockFromRemote( req, offset, cowRequest, cowWriteRequest );
+ currentOffset += padSize;
+ continue;
+ }
+
+ size_t endPaddedSize = 0;
+ if ( ( currentOffset + sizeToWriteToBlock ) % DNBD3_BLOCK_SIZE != 0 ) {
+ off_t currentEndOffset = currentOffset + sizeToWriteToBlock;
+ off_t padStartOffset = currentEndOffset - ( currentEndOffset % 4096 );
+ off_t inBlockPadStartOffset = padStartOffset - metaBlockStartOffset;
+ if ( !checkBit( metaBlock->bitfield, (int)( inBlockPadStartOffset / DNBD3_BLOCK_SIZE ) ) ) {
+ cow_write_request_t *cowWriteRequest = malloc( sizeof( cow_write_request_t ) );
+ cowWriteRequest->inBlockOffset = inBlockPadStartOffset;
+ cowWriteRequest->block = metaBlock;
+ cowWriteRequest->size = (currentEndOffset)-padStartOffset;
+ cowWriteRequest->buffer =
+ cowRequest->writeBuffer + ( ( padStartOffset - offset ) * !cowRequest->replyAttr );
+ padBlockFromRemote( req, padStartOffset, cowRequest, cowWriteRequest );
+
+
+ sizeToWriteToBlock -= (currentEndOffset)-padStartOffset;
+ endPaddedSize = (currentEndOffset)-padStartOffset;
+ }
+ }
- writeData( cowRequest->writeBuffer + ( ( currentOffset - offset ) * !cowRequest->replyAttr ),
- sizeToWriteToBlock, sizeToWriteToBlock, cowRequest, metaBlock, inBlockOffset );
+ writeData( cowRequest->writeBuffer + ( ( currentOffset - offset ) * !cowRequest->replyAttr ),
+ (ssize_t)sizeToWriteToBlock, sizeToWriteToBlock, cowRequest, metaBlock, inBlockOffset );
+ cow_block_metadata_t *b = getBlock( l1Offset, l2Offset );
currentOffset += sizeToWriteToBlock;
+ currentOffset += endPaddedSize;
+
+
l2Offset++;
}
l1Offset++;
@@ -440,6 +557,7 @@ void cowfile_write( fuse_req_t req, cow_request_t *cowRequest, off_t offset, siz
}
}
+
/**
* @brief Request data, that is not available locally, via the network.
*
@@ -449,7 +567,7 @@ void cowfile_write( fuse_req_t req, cow_request_t *cowRequest, off_t offset, siz
* @param buffer into which the data is to be written
* @param workCounter workCounter is increased by one and later reduced by one again when the request is completed.
*/
-static void readRemote( fuse_req_t req, off_t offset, size_t size, char *buffer, cow_request_t *cowRequest )
+static void readRemote( fuse_req_t req, off_t offset, ssize_t size, char *buffer, cow_request_t *cowRequest )
{
dnbd3_async_t *request = malloc( sizeof( dnbd3_async_t ) );
request->buffer = buffer;
@@ -468,6 +586,15 @@ static void readRemote( fuse_req_t req, off_t offset, size_t size, char *buffer,
}
}
+void byte_to_binary( atomic_char *a )
+{
+ for ( int i = 0; i < 8; i++ ) {
+ char tmp = *a;
+ printf( "%d", !!( ( tmp << i ) & 0x80 ) );
+ }
+ printf( "\n" );
+}
+
/*
Maybe optimize that remote reads are done first
*/
@@ -491,14 +618,15 @@ void cowfile_read( fuse_req_t req, size_t size, off_t offset )
off_t lastReadOffset = offset;
off_t endOffset = offset + size;
off_t searchOffset = offset;
+ off_t inBlockOffset;
int l1Offset = getL1Offset( offset );
int l2Offset = getL2Offset( offset );
int bitfieldOffset = getBitfieldOffset( offset );
bool isLocal;
cow_block_metadata_t *block = NULL;
- ;
- if ( cow.l1[l1Offset] != NULL ) {
- block = &( cow.l1[l1Offset] )[l2Offset];
+
+ if ( cow.l1[l1Offset] != -1 ) {
+ block = getBlock( l1Offset, l2Offset );
}
bool doRead = false;
@@ -509,39 +637,51 @@ void cowfile_read( fuse_req_t req, size_t size, off_t offset )
firstLoop = false;
lastReadOffset = searchOffset;
isLocal = block != NULL && checkBit( block->bitfield, bitfieldOffset );
- } else if ( ( block != NULL && checkBit( block->bitfield, bitfieldOffset ) ) != isLocal ) {
+ } else if ( ( block != NULL && checkBit( block->bitfield, bitfieldOffset ) != isLocal ) ) {
doRead = true;
+ } else {
+ bitfieldOffset++;
}
- bitfieldOffset++;
if ( bitfieldOffset >= COW_BITFIELD_SIZE ) {
bitfieldOffset = 0;
l2Offset++;
- if ( l2Offset >= cow.l2Size ) {
+ if ( l2Offset >= COW_L2_SIZE ) {
l2Offset = 0;
l1Offset++;
}
updateBlock = true;
- doRead = true;
+ if ( isLocal ) {
+ doRead = true;
+ }
}
-
- searchOffset =
- DNBD3_BLOCK_SIZE * ( bitfieldOffset ) + l2Offset * cow.metadataStorageCapacity + l1Offset * cow.l2StorageCapacity;
+ // compute the original file offset from bitfieldOffset, l2Offset and l1Offset
+ searchOffset = DNBD3_BLOCK_SIZE * ( bitfieldOffset ) + l2Offset * COW_METADAT_STORAGE_CAPACITY
+ + l1Offset * COW_L2_STORAGE_CAPACITY;
if ( doRead || searchOffset >= endOffset ) {
- size_t sizeToRead = MIN( searchOffset, endOffset ) - lastReadOffset;
+ ssize_t sizeToRead = MIN( searchOffset, endOffset ) - lastReadOffset;
if ( !isLocal ) {
readRemote(
req, lastReadOffset, sizeToRead, cowRequest->readBuffer + ( lastReadOffset - offset ), cowRequest );
} else {
- off_t localRead = block->offset + DNBD3_BLOCK_SIZE * bitfieldOffset + lastReadOffset % DNBD3_BLOCK_SIZE;
- ssize_t bytesRead =
- pread( cow.fhd, cowRequest->readBuffer + ( lastReadOffset - offset ), sizeToRead, localRead );
- if ( bytesRead == -1 ) {
- cowRequest->errorCode = errno;
- } else if ( bytesRead < (ssize_t)sizeToRead ) {
- cowRequest->errorCode = EIO;
+ // Compute the offset in the .data file where the read starts
+ off_t localRead =
+ block->offset + ( ( lastReadOffset % COW_L2_STORAGE_CAPACITY ) % COW_METADAT_STORAGE_CAPACITY );
+ ssize_t totalBytesRead = 0;
+ while ( totalBytesRead < sizeToRead ) {
+ ssize_t bytesRead =
+ pread( cow.fhd, cowRequest->readBuffer + ( lastReadOffset - offset ), sizeToRead, localRead );
+ if ( bytesRead == -1 ) {
+ cowRequest->errorCode = errno;
+ goto fail;
+ } else if ( bytesRead <= 0 ) {
+ cowRequest->errorCode = EIO;
+ goto fail;
+ }
+ totalBytesRead += bytesRead;
}
- atomic_fetch_add( &cowRequest->bytesWorkedOn, bytesRead );
+
+ atomic_fetch_add( &cowRequest->bytesWorkedOn, totalBytesRead );
}
lastReadOffset = searchOffset;
doRead = false;
@@ -549,15 +689,15 @@ void cowfile_read( fuse_req_t req, size_t size, off_t offset )
}
if ( updateBlock ) {
- if ( cow.l1[l1Offset] != NULL ) {
- block = &( cow.l1[l1Offset] )[l2Offset];
+ if ( cow.l1[l1Offset] != -1 ) {
+ block = getBlock( l1Offset, l2Offset );
} else {
block = NULL;
}
updateBlock = false;
}
}
-
+fail:;
if ( atomic_fetch_sub( &cowRequest->workCounter, 1 ) == 1 ) {
if ( cowRequest->errorCode != 0 ) {
fuse_reply_err( req, cowRequest->errorCode );
diff --git a/src/fuse/cowfile.h b/src/fuse/cowfile.h
index 2f1f3ce..43101e2 100644
--- a/src/fuse/cowfile.h
+++ b/src/fuse/cowfile.h
@@ -11,20 +11,30 @@
#include <errno.h>
#include "main.h"
+#define COW_METADAT_STORAGE_CAPACITY ( COW_BITFIELD_SIZE * DNBD3_BLOCK_SIZE )
+#define COW_L2_SIZE 1024
+#define COW_L2_STORAGE_CAPACITY ( COW_L2_SIZE * COW_METADAT_STORAGE_CAPACITY )
-#define COW_METADATA_HEADER_SIZE 244
-typedef struct __attribute__((packed)) cowfile_metadata_header
+
+#define COW_METADATA_HEADER_SIZE 280
+typedef struct __attribute__( ( packed ) ) cowfile_metadata_header
{
- uint64_t imageSize; // 8byte
- int32_t version; // 4byte
- int32_t blocksize; // 4byte
- uint64_t originalImageSize; // 8byte
- uint64_t metaDataStart; // 8byte
- int32_t bitfieldSize; // 4byte
- uint64_t maxImageSize; // 8byte
- char imageName[200]; // 200byte
-} cowfile_metadata_header_t; // 244byte
-_Static_assert( sizeof(cowfile_metadata_header_t) == COW_METADATA_HEADER_SIZE, "cowfile_metadata_header is messed up" );
+ uint64_t magicValue; // 8byte
+ uint64_t imageSize; // 8byte
+ int32_t version; // 4byte
+ int32_t blocksize; // 4byte
+ uint64_t originalImageSize; // 8byte
+ uint64_t metaDataStart; // 8byte
+ int32_t bitfieldSize; // 4byte
+ int32_t nextL2; // 4byte
+ atomic_size_t metadataFileSize; // 8byte
+ atomic_size_t dataFileSize; // 8byte
+ uint64_t maxImageSize; // 8byte
+ uint64_t creationTime; // 8byte
+ char imageName[200]; // 200byte
+} cowfile_metadata_header_t;
+_Static_assert(
+ sizeof( cowfile_metadata_header_t ) == COW_METADATA_HEADER_SIZE, "cowfile_metadata_header is messed up" );
typedef struct cow_block_metadata
{
@@ -39,8 +49,8 @@ typedef struct cow_request
{
size_t fuseRequestSize;
off_t fuseRequestOffset;
- char* readBuffer;
- const char* writeBuffer;
+ char *readBuffer;
+ const char *writeBuffer;
atomic_size_t bytesWorkedOn;
atomic_int workCounter;
atomic_int errorCode;
@@ -51,21 +61,21 @@ typedef struct cow_request
typedef struct cow_write_request
{
- const char* buffer;
+ const char *buffer;
size_t size;
off_t inBlockOffset;
- cow_block_metadata_t * block;
+ cow_block_metadata_t *block;
} cow_write_request_t;
-typedef cow_block_metadata_t** l1;
-typedef cow_block_metadata_t* l2;
+typedef int32_t l1;
+typedef cow_block_metadata_t l2[COW_L2_SIZE];
-bool cowfile_init( char *path, const char *image_Name, size_t ** imageSizePtr );
-bool cowfile_load( char *path );
-void cowfile_read(fuse_req_t req, size_t size, off_t offset);
-void cowfile_write( fuse_req_t req, cow_request_t* cowRequest, off_t offset, size_t size);
+bool cowfile_init( char *path, const char *image_Name, size_t **imageSizePtr );
+bool cowfile_load( char *path, size_t **imageSizePtr );
+void cowfile_read( fuse_req_t req, size_t size, off_t offset );
+void cowfile_write( fuse_req_t req, cow_request_t *cowRequest, off_t offset, size_t size );
size_t cowfile_append( char *buffer, uint64_t offset, uint64_t size );
diff --git a/src/fuse/main.c b/src/fuse/main.c
index c260946..b7a4a9b 100644
--- a/src/fuse/main.c
+++ b/src/fuse/main.c
@@ -488,10 +488,10 @@ int main( int argc, char *argv[] )
}
}
if ( loadCow ) {
- if ( !cowfile_load( cow_file_path ) ) {
+ if ( !cowfile_load( cow_file_path, &imageSizePtr ) ) {
return EXIT_FAILURE;
}
- }
+ }
// Prepare our handler
struct sigaction newHandler;
memset( &newHandler, 0, sizeof( newHandler ) );