diff options
author | Michael Scherle | 2022-05-11 17:39:36 +0200 |
---|---|---|
committer | Michael Scherle | 2022-05-11 17:39:36 +0200 |
commit | 87649d872e7b0b237749846a21755389c0921ac6 (patch) | |
tree | 76e6826e063abad29c228bb43c1562cbaf7c490c | |
parent | changed to use container_of and callbacks (diff) | |
download | dnbd3-87649d872e7b0b237749846a21755389c0921ac6.tar.gz dnbd3-87649d872e7b0b237749846a21755389c0921ac6.tar.xz dnbd3-87649d872e7b0b237749846a21755389c0921ac6.zip |
implemented block upload via rest
-rw-r--r-- | inc/dnbd3/config.h | 7 | ||||
-rw-r--r-- | src/cowtest/main.c | 6 | ||||
-rw-r--r-- | src/fuse/CMakeLists.txt | 9 | ||||
-rw-r--r-- | src/fuse/connection.c | 11 | ||||
-rw-r--r-- | src/fuse/connection.h | 4 | ||||
-rw-r--r-- | src/fuse/cowfile.c | 356 | ||||
-rw-r--r-- | src/fuse/cowfile.h | 31 | ||||
-rw-r--r-- | src/fuse/main.c | 18 |
8 files changed, 408 insertions, 34 deletions
diff --git a/inc/dnbd3/config.h b/inc/dnbd3/config.h index 323a670..b4afcf1 100644 --- a/inc/dnbd3/config.h +++ b/inc/dnbd3/config.h @@ -44,4 +44,11 @@ #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 +#define COW_MIN_UPLOAD_DELAY 60 //in Seconds + +// +++++ COW API Endpoints +++++ +#define COW_API_CREATE "%s/api/File/Create" +#define COW_API_UPDATE "%s/api/File/Update?guid=%s&BlockNumber=%u" +#define COW_API_START_MERGE "%s/api/File/StartMerge?guid=%s&fileSize=%lld" + #endif /* CONFIG_H_ */ diff --git a/src/cowtest/main.c b/src/cowtest/main.c index 71efe4c..e369f2d 100644 --- a/src/cowtest/main.c +++ b/src/cowtest/main.c @@ -64,6 +64,7 @@ void printUsage() printf( "Press the follwing for: \n" ); printf( " c <path> Creates test file at the path. \n" ); printf( " t <path> Runs the standart test procedure. \n" ); + printf( " v <path> verifies a file. \n" ); } void printCharInHexadecimal( const char *str, int len ) @@ -453,10 +454,7 @@ void verifyFinalFile( char *path ) verifyTests( tests ); int currentTest = 0; - //verifyWriteOverTwoBlocks(); - //verifyWriteNotOnBlockBorder(); - //verifyInterleavedTest(); - //verifyWriteOverL2(); + while ( offset < fileSize ) { diff --git a/src/fuse/CMakeLists.txt b/src/fuse/CMakeLists.txt index 605ef87..489f43e 100644 --- a/src/fuse/CMakeLists.txt +++ b/src/fuse/CMakeLists.txt @@ -10,6 +10,11 @@ find_package(Fuse REQUIRED) find_package(Stdatomic REQUIRED) find_package(Libatomic REQUIRED) +# find curl for cow +find_package(CURL REQUIRED) + +pkg_search_module(UUID REQUIRED uuid) + # add compile option to enable enhanced POSIX pthread features add_definitions(-D_GNU_SOURCE) @@ -23,8 +28,8 @@ set(DNBD3_FUSE_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/cowfile.h ${CMAKE_CURRENT_SOURCE_DIR}/main.h) add_executable(dnbd3-fuse ${DNBD3_FUSE_SOURCE_FILES}) -target_include_directories(dnbd3-fuse PRIVATE ${FUSE_INCLUDE_DIRS}) -target_link_libraries(dnbd3-fuse dnbd3-build dnbd3-version dnbd3-shared ${FUSE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +target_include_directories(dnbd3-fuse PRIVATE ${FUSE_INCLUDE_DIRS} ${CURL_INCLUDE_DIR} ${UUID_INCLUDE_DIRS}) +target_link_libraries(dnbd3-fuse dnbd3-build dnbd3-version dnbd3-shared ${FUSE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${CURL_LIBRARIES} ${UUID_LIBRARIES}) install(TARGETS dnbd3-fuse RUNTIME DESTINATION bin COMPONENT fuse) diff --git a/src/fuse/connection.c b/src/fuse/connection.c index 20c57ae..5a3c93b 100644 --- a/src/fuse/connection.c +++ b/src/fuse/connection.c @@ -244,6 +244,17 @@ bool connection_initThreads() return success; } +char * connection_getImageName() +{ + return image.name; +} + +uint16_t connection_getImageRID() +{ + return image.rid; +} + + uint64_t connection_getImageSize() { return image.size; diff --git a/src/fuse/connection.h b/src/fuse/connection.h index e5fe89b..9f6447b 100644 --- a/src/fuse/connection.h +++ b/src/fuse/connection.h @@ -32,6 +32,10 @@ bool connection_initThreads(); uint64_t connection_getImageSize(); +char * connection_getImageName(); + +uint16_t connection_getImageRID(); + bool connection_read( dnbd3_async_t *request ); void connection_close(); diff --git a/src/fuse/cowfile.c b/src/fuse/cowfile.c index ae6f095..4e8b67f 100644 --- a/src/fuse/cowfile.c +++ b/src/fuse/cowfile.c @@ -1,9 +1,13 @@ #include "cowfile.h" - +#include "math.h" extern void image_ll_getattr( fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi ); -int cowFileVersion = 1; -cowfile_metadata_header_t *metadata = NULL; +static int cowFileVersion = 1; +static pthread_t tidCowUploader; +static char *cowServerAddress; +static CURL *curl; +static cowfile_metadata_header_t *metadata = NULL; +atomic_bool uploadLoop = true; static struct cow { @@ -37,7 +41,7 @@ static int getL1Offset( size_t offset ) */ static int getL2Offset( size_t offset ) { - return (int)( ( offset % COW_L2_STORAGE_CAPACITY ) / COW_METADAT_STORAGE_CAPACITY ); + return (int)( ( offset % COW_L2_STORAGE_CAPACITY ) / COW_METADATA_STORAGE_CAPACITY ); } /** @@ -94,6 +98,302 @@ static bool checkBit( atomic_char *bitfield, int n ) return ( atomic_load( ( bitfield + ( n / 8 ) ) ) >> ( n % 8 ) ) & 1; } + +size_t curlCallbackCreateSession( char *buffer, size_t itemSize, size_t nitems, void *response ) +{ + size_t bytes = itemSize * nitems; + if ( strlen( response ) + bytes != 36 ) { + logadd( LOG_INFO, "strlen(response): %i bytes: %i \n", strlen( response ), bytes ); + return bytes; + } + + strcat( response, buffer ); + return bytes; +} + +/** + * @brief Create a Session with the cow server and gets the session guid + * + * @param imageName + * @param version of the original Image + */ +bool createSession( char *imageName, uint16_t version ) +{ + CURLcode res; + char url[300]; + sprintf( url, COW_API_CREATE, cowServerAddress ); + logadd( LOG_INFO, "COW_API_CREATE URL: %s", url ); + curl_easy_setopt( curl, CURLOPT_CUSTOMREQUEST, "POST" ); + curl_easy_setopt( curl, CURLOPT_URL, url ); + + curl_mime *mime; + curl_mimepart *part; + mime = curl_mime_init( curl ); + part = curl_mime_addpart( mime ); + curl_mime_name( part, "imageName" ); + curl_mime_data( part, imageName, CURL_ZERO_TERMINATED ); + part = curl_mime_addpart( mime ); + curl_mime_name( part, "version" ); + char buf[sizeof( int ) * 3 + 2]; + snprintf( buf, sizeof buf, "%d", version ); + curl_mime_data( part, buf, CURL_ZERO_TERMINATED ); + + part = curl_mime_addpart( mime ); + curl_mime_name( part, "bitfieldSize" ); + snprintf( buf, sizeof buf, "%d", metadata->bitfieldSize ); + curl_mime_data( part, buf, CURL_ZERO_TERMINATED ); + + curl_easy_setopt( curl, CURLOPT_MIMEPOST, mime ); + + char response[37]; + response[0] = '\0'; + curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, curlCallbackCreateSession ); + curl_easy_setopt( curl, CURLOPT_WRITEDATA, &response ); + + res = curl_easy_perform( curl ); + curl_mime_free( mime ); + + /* Check for errors */ + if ( res != CURLE_OK ) { + logadd( LOG_ERROR, "COW_API_CREATE failed: %s\n", curl_easy_strerror( res ) ); + return false; + } + + long http_code = 0; + curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &http_code ); + if ( http_code != 200 ) { + logadd( LOG_ERROR, "COW_API_CREATE failed http: %ld\n", http_code ); + return false; + } + curl_easy_reset( curl ); + response[36] = '\0'; + logadd( LOG_DEBUG1, "Cow session started, guid: %s\n", response ); + if ( uuid_parse( response, metadata->uuid ) != 0 ) { + logadd( LOG_ERROR, "uuid_parse failed\n" ); + return false; + } + return true; +} + + +void print_bin( char a ) +{ + for ( int i = 0; i < 8; i++ ) { + printf( "%d", !!( ( a << i ) & 0x80 ) ); + } +} + +void print_bin_arr( char *ptr, int size ) +{ + for ( int i = 0; i < size; i++ ) { + print_bin( ptr[i] ); + printf( " " ); + } + printf( "\n" ); +} + +/** + * @brief Implementation of CURLOPT_READFUNCTION, this function will first send the bitfield and + * then the block data in one bitstream. this function is usually called multible times per block, + * since the buffer is usually not large for one block and its bitfield. + * for more details see: https://curl.se/libcurl/c/CURLOPT_READFUNCTION.html + * + * @param ptr to the buffer + * @param size size of one element in buffer + * @param nmemb number of elements in buffer + * @param userdata from CURLOPT_READFUNCTION + * @return size_t size written in buffer + */ +size_t curlReadCallbackUploadBlock( char *ptr, size_t size, size_t nmemb, void *userdata ) +{ + cow_curl_read_upload_t *uploadBlock = (cow_curl_read_upload_t *)userdata; + size_t len = 0; + if ( uploadBlock->position < (size_t)metadata->bitfieldSize / 8 ) { + size_t lenCpy = MIN( metadata->bitfieldSize / 8 - uploadBlock->position, size * nmemb ); + memcpy( ptr, uploadBlock->block->bitfield + uploadBlock->position, lenCpy ); + uploadBlock->position += lenCpy; + len += lenCpy; + } + if ( uploadBlock->position >= (size_t)metadata->bitfieldSize / 8 ) { + size_t lenRead = MIN( COW_METADATA_STORAGE_CAPACITY - ( uploadBlock->position - ( metadata->bitfieldSize / 8 ) ), + ( size * nmemb ) - len ); + off_t inBlockOffset = uploadBlock->position - metadata->bitfieldSize / 8; + size_t lengthRead = pread( cow.fhd, ( ptr + len ), lenRead, uploadBlock->block->offset + inBlockOffset ); + uploadBlock->position += lengthRead; + len += lengthRead; + } + return len; +} + +/** + * @brief uploads the given block to the cow server. + * + * @param block pointer to the cow_block_metadata_t + * @param blocknumber is the abosulte block number from the beginning. + * @param time relative Time since the creation of the cow file. will be used to + * set the block->timeUploaded. + */ +bool uploadBlock( cow_block_metadata_t *block, uint32_t blocknumber, uint32_t time ) +{ + CURLcode res; + cow_curl_read_upload_t curlUploadBlock; + + char url[400]; + char uuid[37]; + uuid_unparse( metadata->uuid, uuid ); + sprintf( url, COW_API_UPDATE, cowServerAddress, uuid, blocknumber ); + curlUploadBlock.block = block; + curlUploadBlock.position = 0; + + curl_easy_setopt( curl, CURLOPT_URL, url ); + curl_easy_setopt( curl, CURLOPT_POST, 1L ); + curl_easy_setopt( curl, CURLOPT_READFUNCTION, curlReadCallbackUploadBlock ); + curl_easy_setopt( curl, CURLOPT_READDATA, (void *)&curlUploadBlock ); + + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt( + curl, CURLOPT_POSTFIELDSIZE_LARGE, (long)( metadata->bitfieldSize / 8 + COW_METADATA_STORAGE_CAPACITY ) ); + + struct curl_slist *headers = NULL; + headers = curl_slist_append( headers, "Content-Type: application/octet-stream" ); + curl_easy_setopt( curl, CURLOPT_HTTPHEADER, headers ); + + + res = curl_easy_perform( curl ); + + + /* Check for errors */ + if ( res != CURLE_OK ) { + logadd( LOG_ERROR, "COW_API_UPDATE failed: %s\n", curl_easy_strerror( res ) ); + curl_easy_reset( curl ); + return false; + } + long http_code = 0; + curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &http_code ); + if ( http_code != 200 ) { + logadd( LOG_ERROR, "COW_API_UPDATE failed http: %ld\n", http_code ); + curl_easy_reset( curl ); + return false; + } + + // everything went ok, update timeUploaded + block->timeUploaded = (atomic_uint_fast32_t)time; + curl_easy_reset( curl ); + return true; +} + + +/** + * @brief requests the merging of the image on the cow server + + */ +bool mergeRequest() +{ + CURLcode res; + curl_easy_setopt( curl, CURLOPT_CUSTOMREQUEST, "GET" ); + + char url[400]; + char uuid[37]; + uuid_unparse( metadata->uuid, uuid ); + sprintf( url, COW_API_START_MERGE, cowServerAddress, uuid, metadata->imageSize ); + curl_easy_setopt( curl, CURLOPT_URL, url ); + + res = curl_easy_perform( curl ); + if ( res != CURLE_OK ) { + logadd( LOG_WARNING, "COW_API_START_MERGE failed: %s\n", curl_easy_strerror( res ) ); + curl_easy_reset( curl ); + return false; + } + long http_code = 0; + curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &http_code ); + if ( http_code != 200 ) { + logadd( LOG_WARNING, "COW_API_START_MERGE failed http: %ld\n", http_code ); + curl_easy_reset( curl ); + return false; + } + curl_easy_reset( curl ); + return true; +} + +/** + * @brief wrapper for mergeRequest so if its fails it will be tried again. + * + */ +void startMerge() +{ + int fails = 0; + bool success = false; + success = mergeRequest(); + while ( fails <= 5 && !success ) { + fails++; + logadd( LOG_WARNING, "Trying again. %i/5", fails ); + mergeRequest(); + } +} + +/** + * @brief loops through all blocks and uploads them. + * + * @param lastLoop if set to true, all blocks which are not uploaded will be uploaded, ignoring their timeChanged + */ +bool uploaderLoop( bool lastLoop ) +{ + bool success = true; + int l1MaxOffset = ceil( metadata->imageSize / COW_L2_STORAGE_CAPACITY ); + for ( int l1Offset = 0; l1Offset < l1MaxOffset; l1Offset++ ) { + if ( cow.l1[l1Offset] == -1 ) { + continue; + } + for ( int l2Offset = 0; l2Offset < COW_L2_SIZE; l2Offset++ ) { + cow_block_metadata_t *block = ( cow.firstL2[cow.l1[l1Offset]] + l2Offset ); + if ( block->offset == -1 ) { + continue; + } + if ( block->timeUploaded < block->timeChanged ) { + uint32_t relativeTime = (uint32_t)( time( NULL ) - metadata->creationTime ); + if ( ( ( ( relativeTime - block->timeChanged ) > COW_MIN_UPLOAD_DELAY ) || lastLoop ) + && block->timeUploaded < block->timeChanged ) { + if ( !uploadBlock( block, l1Offset * COW_L2_SIZE + l2Offset, relativeTime ) ) { + int fails = 1; + while ( fails <= 5 ) { + if ( uploadBlock( block, l1Offset * COW_L2_SIZE + l2Offset, relativeTime ) ) { + break; + } + logadd( LOG_WARNING, "Trying again. %i/5", fails ); + fails++; + } + if ( fails > 5 ) { + logadd( LOG_ERROR, "Block upload failed" ); + success = false; + } + } + } + } + } + } + return success; +} + +/** + * @brief main loop for blockupload in the background + */ +void cowfile_uploader( void *something ) +{ + while ( uploadLoop ) { + uploaderLoop( false ); + sleep( 2 ); + } + logadd( LOG_DEBUG1, "start uploading the remaining blocks." ); + + // force the upload of all remaining blocks since the user dismounted the image + if ( !uploaderLoop( true ) ) { + logadd( LOG_ERROR, "Can't merge, since one or more blocks failed to upload" ); + return; + } + logadd( LOG_DEBUG1, "Requesting merge." ); + startMerge(); +} + /** * @brief initializes the cow functionality, creates the .data & .meta file. * @@ -101,7 +401,8 @@ static bool checkBit( atomic_char *bitfield, int n ) * @param image_Name name of the original file/image * @param imageSizePtr */ -bool cowfile_init( char *path, const char *image_Name, size_t **imageSizePtr ) +bool cowfile_init( + char *path, const char *image_Name, uint16_t imageVersion, size_t **imageSizePtr, char *serverAddress ) { char pathMeta[strlen( path ) + 6]; char pathData[strlen( path ) + 6]; @@ -178,10 +479,24 @@ bool cowfile_init( char *path, const char *image_Name, size_t **imageSizePtr ) return false; } // move the dataFileSize to make room for the header - atomic_store( &metadata->dataFileSize, COW_METADAT_STORAGE_CAPACITY ); + atomic_store( &metadata->dataFileSize, COW_METADATA_STORAGE_CAPACITY ); pthread_mutex_init( &cow.l2CreateLock, NULL ); - return 1; + + + cowServerAddress = serverAddress; + curl_global_init( CURL_GLOBAL_ALL ); + curl = curl_easy_init(); + if ( !curl ) { + logadd( LOG_ERROR, "Error on curl init. Bye.\n" ); + return false; + } + if ( !createSession( image_Name, imageVersion ) ) { + return false; + } + + pthread_create( &tidCowUploader, NULL, &cowfile_uploader, NULL ); + return true; } /** * @brief loads an existing cow state from the .meta & .data files @@ -190,8 +505,9 @@ bool cowfile_init( char *path, const char *image_Name, size_t **imageSizePtr ) * @param imageSizePtr */ -bool cowfile_load( char *path, size_t **imageSizePtr ) +bool cowfile_load( char *path, size_t **imageSizePtr, char *serverAddress ) { + cowServerAddress = serverAddress; char pathMeta[strlen( path ) + 6]; char pathData[strlen( path ) + 6]; strcpy( pathMeta, path ); @@ -323,7 +639,7 @@ static void writeData( const char *buffer, ssize_t size, size_t netSize, cow_req */ static bool allocateMetaBlockData( cow_block_metadata_t *block ) { - block->offset = (atomic_long)atomic_fetch_add( &metadata->dataFileSize, COW_METADAT_STORAGE_CAPACITY ); + block->offset = (atomic_long)atomic_fetch_add( &metadata->dataFileSize, COW_METADATA_STORAGE_CAPACITY ); return true; } @@ -448,12 +764,12 @@ static void padBlockFromRemote( fuse_req_t req, off_t offset, cow_request_t *cow } } - void cowFile_handleCallback( dnbd3_async_t *request ) { cow_sub_request_t *sRequest = container_of( request, cow_sub_request_t, dRequest ); sRequest->callback( sRequest ); } + static void readRemoteData( cow_sub_request_t *sRequest ) { memcpy( sRequest->cowRequest->readBuffer + ( sRequest->dRequest.offset - sRequest->cowRequest->fuseRequestOffset ), @@ -476,7 +792,7 @@ static void readRemoteData( cow_sub_request_t *sRequest ) 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_METADAT_STORAGE_CAPACITY ) ); + cowRequest->writeBuffer = calloc( sizeof( char ), MIN( size, COW_METADATA_STORAGE_CAPACITY ) ); } // if beyond end of file, pad with 0 if ( offset > (off_t)metadata->imageSize ) { @@ -505,11 +821,11 @@ void cowfile_write( fuse_req_t req, cow_request_t *cowRequest, off_t offset, siz cow_block_metadata_t *metaBlock = getBlock( l1Offset, l2Offset ); - size_t metaBlockStartOffset = l1Offset * COW_L2_STORAGE_CAPACITY + l2Offset * COW_METADAT_STORAGE_CAPACITY; + size_t metaBlockStartOffset = l1Offset * COW_L2_STORAGE_CAPACITY + l2Offset * COW_METADATA_STORAGE_CAPACITY; size_t inBlockOffset = currentOffset - metaBlockStartOffset; size_t sizeToWriteToBlock = - MIN( (size_t)( endOffset - currentOffset ), COW_METADAT_STORAGE_CAPACITY - inBlockOffset ); + MIN( (size_t)( endOffset - currentOffset ), COW_METADATA_STORAGE_CAPACITY - inBlockOffset ); ///////////////////////// @@ -661,7 +977,7 @@ void cowfile_read( fuse_req_t req, size_t size, off_t offset ) } } // compute the original file offset from bitfieldOffset, l2Offset and l1Offset - searchOffset = DNBD3_BLOCK_SIZE * ( bitfieldOffset ) + l2Offset * COW_METADAT_STORAGE_CAPACITY + searchOffset = DNBD3_BLOCK_SIZE * ( bitfieldOffset ) + l2Offset * COW_METADATA_STORAGE_CAPACITY + l1Offset * COW_L2_STORAGE_CAPACITY; if ( doRead || searchOffset >= endOffset ) { ssize_t sizeToRead = MIN( searchOffset, endOffset ) - lastReadOffset; @@ -670,7 +986,7 @@ void cowfile_read( fuse_req_t req, size_t size, off_t offset ) } else { // 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 ); + block->offset + ( ( lastReadOffset % COW_L2_STORAGE_CAPACITY ) % COW_METADATA_STORAGE_CAPACITY ); ssize_t totalBytesRead = 0; while ( totalBytesRead < sizeToRead ) { ssize_t bytesRead = @@ -713,3 +1029,13 @@ fail:; free( cowRequest ); } } + +void cowfile_close() +{ + uploadLoop = false; + pthread_join( tidCowUploader, NULL ); + if ( curl ) { + curl_global_cleanup(); + curl_easy_cleanup( curl ); + } +} diff --git a/src/fuse/cowfile.h b/src/fuse/cowfile.h index d28158c..8ee7c54 100644 --- a/src/fuse/cowfile.h +++ b/src/fuse/cowfile.h @@ -1,7 +1,6 @@ #ifndef _COWFILE_H_ #define _COWFILE_H_ - #include "connection.h" #include "main.h" #include <stdint.h> @@ -12,18 +11,21 @@ #include <string.h> #include <pthread.h> #include <errno.h> +#include <uuid/uuid.h> +#include <curl/curl.h> -#define COW_METADAT_STORAGE_CAPACITY ( COW_BITFIELD_SIZE * DNBD3_BLOCK_SIZE ) +#define COW_METADATA_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_L2_STORAGE_CAPACITY ( COW_L2_SIZE * COW_METADATA_STORAGE_CAPACITY ) #define container_of( ptr, type, member ) ( (type *)( (char *)( ptr ) - (char *)&( ( (type *)NULL )->member ) ) ) -#define COW_METADATA_HEADER_SIZE 280 + +#define COW_METADATA_HEADER_SIZE 296 typedef struct __attribute__( ( packed ) ) cowfile_metadata_header { uint64_t magicValue; // 8byte - uint64_t imageSize; // 8byte + atomic_uint_fast64_t imageSize; // 8byte int32_t version; // 4byte int32_t blocksize; // 4byte uint64_t originalImageSize; // 8byte @@ -34,6 +36,7 @@ typedef struct __attribute__( ( packed ) ) cowfile_metadata_header atomic_size_t dataFileSize; // 8byte uint64_t maxImageSize; // 8byte uint64_t creationTime; // 8byte + uuid_t uuid; // 16byte char imageName[200]; // 200byte } cowfile_metadata_header_t; _Static_assert( @@ -47,7 +50,6 @@ typedef struct cow_block_metadata atomic_char bitfield[40]; } cow_block_metadata_t; - typedef struct cow_request { size_t fuseRequestSize; @@ -65,7 +67,6 @@ typedef struct cow_request typedef struct cow_sub_request cow_sub_request_t; typedef void ( *cow_callback )( cow_sub_request_t *sRequest ); - typedef struct cow_sub_request { size_t size; @@ -78,16 +79,26 @@ typedef struct cow_sub_request } cow_sub_request_t; +typedef struct cow_curl_read_upload +{ + cow_block_metadata_t *block; + size_t position; +} cow_curl_read_upload_t; 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, size_t **imageSizePtr ); +bool cowfile_init( + char *path, const char *image_Name, uint16_t imageVersion, size_t **imageSizePtr, char *serverAdress ); + +bool cowfile_load( char *path, size_t **imageSizePtr, char *serverAdress ); + 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 ); -void cowFile_handleCallback( dnbd3_async_t *request ); +void cowfile_handleCallback( dnbd3_async_t *request ); +void cowfile_close(); #endif /* COWFILE_H_ */
\ No newline at end of file diff --git a/src/fuse/main.c b/src/fuse/main.c index 5d37813..3089a3a 100644 --- a/src/fuse/main.c +++ b/src/fuse/main.c @@ -357,10 +357,11 @@ static void printUsage( char *argv0, int exitCode ) printf( " -s Single threaded mode\n" ); printf( " -c <path> Enables cow, creates the cow files at given path\n" ); printf( " -L <path> Loads the cow files from a given path\n" ); + printf( " -C --host Host address of the cow server\n" ); exit( exitCode ); } -static const char *optString = "dfHh:i:l:o:r:SsVvc:L:"; +static const char *optString = "dfHh:i:l:o:r:SsVvc:L:C:"; static const struct option longOpts[] = { { "debug", no_argument, NULL, 'd' }, { "help", no_argument, NULL, 'H' }, @@ -373,12 +374,14 @@ static const struct option longOpts[] = { { "version", no_argument, NULL, 'v' }, { "cow", required_argument, NULL, 'c' }, { "loadcow", required_argument, NULL, 'L' }, + { "cowServer", required_argument, NULL, 'C' }, { 0, 0, 0, 0 } }; int main( int argc, char *argv[] ) { char *server_address = NULL; + char *cow_server_address = NULL; char *image_Name = NULL; char *log_file = NULL; uint16_t rid = 0; @@ -461,6 +464,9 @@ int main( int argc, char *argv[] ) cow_file_path = optarg; useCow = true; break; + case 'C': + cow_server_address = optarg; + break; case 'L': cow_file_path = optarg; useCow = true; @@ -484,8 +490,11 @@ int main( int argc, char *argv[] ) logadd( LOG_WARNING, "Could not open log file at '%s'", log_file ); } } + if( useCow && cow_server_address == NULL ) { + printUsage( argv[0], EXIT_FAILURE ); + } if ( loadCow ) { - if ( !cowfile_load( cow_file_path, &imageSizePtr ) ) { + if ( !cowfile_load( cow_file_path, &imageSizePtr, cow_server_address ) ) { return EXIT_FAILURE; } } @@ -534,7 +543,7 @@ int main( int argc, char *argv[] ) owner = getuid(); if ( useCow & !loadCow) { - if( !cowfile_init( cow_file_path, IMAGE_NAME, &imageSizePtr) ) { + if( !cowfile_init( cow_file_path, connection_getImageName(), connection_getImageRID(), &imageSizePtr, cow_server_address ) ) { return EXIT_FAILURE; } } @@ -572,6 +581,9 @@ int main( int argc, char *argv[] ) _fuseSession = NULL; } fuse_unmount( mountpoint, ch ); + if( useCow ) { + cowfile_close(); + } } fuse_opt_free_args( &args ); free( newArgv ); |