diff options
author | Michael Scherle | 2022-03-31 20:26:55 +0200 |
---|---|---|
committer | Michael Scherle | 2022-03-31 20:26:55 +0200 |
commit | 0ab8f979fd25c66c73ac90839ff29a6a2ac884e7 (patch) | |
tree | f9fc1682a0e7b051c0a4391efd511277220a0a33 | |
parent | first round of fixes: static, setBits, MagicValues (diff) | |
download | dnbd3-0ab8f979fd25c66c73ac90839ff29a6a2ac884e7.tar.gz dnbd3-0ab8f979fd25c66c73ac90839ff29a6a2ac884e7.tar.xz dnbd3-0ab8f979fd25c66c73ac90839ff29a6a2ac884e7.zip |
multible bugfixes, test can verify existing file
-rw-r--r-- | inc/dnbd3/config.h | 3 | ||||
-rw-r--r-- | src/cowtest/main.c | 317 | ||||
-rw-r--r-- | src/fuse/cowfile.c | 560 | ||||
-rw-r--r-- | src/fuse/cowfile.h | 54 | ||||
-rw-r--r-- | src/fuse/main.c | 4 |
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 ) ); |