summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Scherle2022-05-11 17:39:36 +0200
committerMichael Scherle2022-05-11 17:39:36 +0200
commit87649d872e7b0b237749846a21755389c0921ac6 (patch)
tree76e6826e063abad29c228bb43c1562cbaf7c490c
parentchanged to use container_of and callbacks (diff)
downloaddnbd3-87649d872e7b0b237749846a21755389c0921ac6.tar.gz
dnbd3-87649d872e7b0b237749846a21755389c0921ac6.tar.xz
dnbd3-87649d872e7b0b237749846a21755389c0921ac6.zip
implemented block upload via rest
-rw-r--r--inc/dnbd3/config.h7
-rw-r--r--src/cowtest/main.c6
-rw-r--r--src/fuse/CMakeLists.txt9
-rw-r--r--src/fuse/connection.c11
-rw-r--r--src/fuse/connection.h4
-rw-r--r--src/fuse/cowfile.c356
-rw-r--r--src/fuse/cowfile.h31
-rw-r--r--src/fuse/main.c18
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 );