summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Scherle2022-06-28 13:25:24 +0200
committerMichael Scherle2022-06-28 13:25:24 +0200
commit1e7da6470a5b9a4d4671733075f145647d9e1cdc (patch)
tree87a001f69b0aa2b781282394a6172a6839c9cc3f
parentredme expanded (diff)
downloaddnbd3-1e7da6470a5b9a4d4671733075f145647d9e1cdc.tar.gz
dnbd3-1e7da6470a5b9a4d4671733075f145647d9e1cdc.tar.xz
dnbd3-1e7da6470a5b9a4d4671733075f145647d9e1cdc.zip
created sperate paramter for stats
-rw-r--r--src/fuse/cowDoc/readme.md51
-rw-r--r--src/fuse/cowfile.c60
-rw-r--r--src/fuse/cowfile.h4
-rw-r--r--src/fuse/main.c19
4 files changed, 79 insertions, 55 deletions
diff --git a/src/fuse/cowDoc/readme.md b/src/fuse/cowDoc/readme.md
index 7fb487c..fcf5b2d 100644
--- a/src/fuse/cowDoc/readme.md
+++ b/src/fuse/cowDoc/readme.md
@@ -17,11 +17,14 @@ This extension to the fuse dnbd3 client allows it to mount images writable. The
# Usage
### New Parameters
-- `-c <path>` Enables the cow functionality, the argument sets the path for the temporary `.meta` and `.data` file in which the writes are stored
+- `-c <path>` Enables the cow functionality, the argument sets the path for the temporary `meta` and `data` file in which the writes are stored
- `-C <address>` sets the address of the cow server. The cow server is responsible for merging the original image with the changes from the client.
- `-L <path>` Similar to `-c <path>` but instead of creating a new session, it loads an existing from the given path.
- `-m` if set, the client will request a merge after the image is unmounted and all change are uploaded.
+- `--cowStatStdout` creates a status file at the same location as the data and meta file. The file contains information about the current session, for more information see [here](#status).
+- `--cowStatFile` similar to `--cowStatStdout` but the information will be printed in the stdout.
+
Example parameters for creating a new cow session:
```
./dnbd3-fuse "/home/user/VMs/mount" -f -h localhost -i imagename -c "/home/user/temp" -C "192.168.178.20:5000"
@@ -40,14 +43,14 @@ Split into metadata and data
!-->
-The datastructe is split in to main parts. The actual data from the write on the image and its corresponding metadata. Its also important to distinguish between a dnbd3 block which is 4096byte and and cow block which groups 320 dnbd3 blocks together. An cow block has an `cow_block_metadata_t` struct which holds the corresponding meta data. The metadata is used to determine if and block has bin written on, where this block is stored in the data file, when it was last modified and when it was uploaded. But more later.
+The datastructe is split in two main parts. The actual data from the write on the image and its corresponding metadata. Its also important to distinguish between a dnbd3 block which is 4096byte and and cow block which groups 320 dnbd3 blocks together. An cow block has an `cow_block_metadata_t` struct which holds the corresponding meta data. The metadata is used to determine if and block has bin written on, where this block is stored in the data file, when it was last modified and when it was uploaded. But more later.
### Blockmetadata
![Datastructure](img/Bild1.jpg)
-The data structure for storing metadata about blocks contains a Layer 1(L1) and a Layer 2 (L2). L1 contains pointers to the L2's.
+The data structure for storing metadata about cow blocks contains a Layer 1(L1) and a Layer 2 (L2). L1 contains pointers to the L2's.
The whole L1 array is initialized at the beginning and cannot be resized, so the size of the L1 array limits the total size of the image.
The L2's are dynamically created once needed. So at the beginning, all L1 pointer will be null. The L2's are arrays which contains 1024
`cow_block_metadata_t` structs.
@@ -61,7 +64,7 @@ typedef struct cow_block_metadata
atomic_char bitfield[40];
} cow_block_metadata_t;
```
-Each `cow_block_metadata_t` contains a 40 byte so 320 bit bitfield. The bitfield indicates whether the corresponding data contains data or not. For e.g. if the bitfield starts with 01.., the first 4096 contains not data and the next 4096 contain data.
+Each `cow_block_metadata_t` contains a 40 byte so 320 bit bitfield. The bitfield indicates whether the corresponding dnbd3 block contains data or not. For e.g. if the bitfield starts with 01.., the first 4096 contains not data and the next 4096 contain data.
So each `cow_block_metadata_t` stores the metadata of up to 320*4096 byte if all bits are set to 1. The offset is the offset where in the data file is the corresponding data stored. The timeChanged property contains the unix when the block was last modified, and the timeUploaded property contains the unix time when the block was last uploaded. It's 0 if the block was never uploaded.
@@ -75,7 +78,7 @@ So for example, to get the `cow_block_metadata_t` for offset 4033085440 you woul
Then you would take the fifth `cow_block_metadata_t` in the L2 array because of
```
-(4033085440 mod COW_L2_STORAGE_CAPACITY) / COW_METADATA_STORAGE_CAPACITY
+(4033085440 mod COW_L2_STORAGE_CAPACITY) / COW_METADATA_STORAGE_CAPACITY = 5
```
Where:
```
@@ -98,9 +101,8 @@ The graph shown above is somewhat simplified for better visibility. The reads fr
the fuse buffer. Each request to the dnbd3 server will increase the `workCounter` variable by one and every time a request is done it will be decreased by one. Once `workCounter` is 0 again, fuse_request will be returned.
Also on the local side, it has to break the loop once the end of an `cow_block_metadata_t` is reached, since the next data offset of the next `cow_block_metadata_t` is very likely not directly after it in the data file.
-### Write Request
-
+### Write Request
For the write request, if the start or the end or the end does not align with a multiple of 4096, then the start and/or end block must be padded.
Because every 4096byte block needs complete data, since if the bit in the bitfield for that block is set, all the data will be read locally.
To pad the block, if its still in the range of the original image size, the missing bytes will be requested from the dnbd3 server. If its outside of the original image (because the image grown in size) then the missing bytes will be padded with 0.
@@ -112,32 +114,31 @@ The `workCounter` variable is used here again to make sure that if padding was n
## Files
If a new CoW session is started, a new `meta`, `data` and if set so in the Command line arguments a `status.txt` file is created.
-### status.txt
-While the cow session is active, the file contains:
-
-```
-uuid: <uuid>
-state: active
-```
-- The `uuid` is the session uuid, which the cow server uses to identify the session.
-
+### status
+The `status.txt` can be activated with the `--cowStatFile` command line parameter.
-Once the user unmounts the image, the file contains:
+The file will contain:
```
-uid: <uuid>
-state: uploading
-uploaded: <number>
-totalBlocks: <number>
+uuid=<uuid>
+state=backgroundUpload
+inQueue=0
+modifiedBlocks=0
+idleBlocks=0
+totalBlocksUploaded=0
+ulspeed=0.00
```
-- `uploaded` is the number of Blocks which are already uploaded.
-
-- `totalBlocks` is the total Number of Blocks which need to be uploaded.
+- The `uuid` is the session uuid, which the cow server uses to identify the session.
+- The `state`
+- `inQueue`
+- `modifiedBlocks`
+- `totalBlocksUploaded` the total amount of cowblocks uploaded since the image was mounted.
+- `ulspeed` the current upload speed in kb/s.
Once all blocks are uploaded, the state will be set to `done`.
-
+With the command line parameter `--cowStatStdout` the same output of the stats file will be printed in stdout.
### meta
The `meta` file contains the following header:
diff --git a/src/fuse/cowfile.c b/src/fuse/cowfile.c
index e48f770..d64d797 100644
--- a/src/fuse/cowfile.c
+++ b/src/fuse/cowfile.c
@@ -3,7 +3,8 @@
extern void image_ll_getattr( fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi );
static int cowFileVersion = 1;
-static int foreground;
+static bool statStdout;
+static bool statFile;
static pthread_t tidCowUploader;
static pthread_t tidStatUpdater;
static char *cowServerAddress;
@@ -348,17 +349,19 @@ void updateCowStatsFile( uint64_t inQueue, uint64_t modified, uint64_t idle, cha
"%s=%s",
state, inQueue, modified, idle, totalBlocksUploaded, COW_SHOW_UL_SPEED ? "ulspeed" : "", speedBuffer );
- if ( foreground ) {
+ if ( statStdout ) {
logadd( LOG_INFO, "%s", buffer );
- return;
- } else {
+ }
+
+ if ( statFile ) {
if ( pwrite( cow.fhs, buffer, len, 43 ) != len ) {
logadd( LOG_WARNING, "Could not update cow status file" );
}
+ if ( ftruncate( cow.fhs, 43 + len ) ) {
+ logadd( LOG_WARNING, "Could not truncate cow status file" );
+ }
}
- if ( ftruncate( cow.fhs, 43 + len ) ) {
- logadd( LOG_WARNING, "Could not truncate cow status file" );
- }
+
}
/**
@@ -634,19 +637,20 @@ bool createCowStatsFile( char *path )
snprintf( pathStatus, strlen( path ) + 12, "%s%s", path, "/status.txt" );
char buffer[100];
- int len = snprintf( buffer, 100, "uuid: %s\nstate: active\n", metadata->uuid );
- if ( foreground ) {
+ int len = snprintf( buffer, 100, "uuid=%s\nstate: active\n", metadata->uuid );
+ if ( statStdout ) {
logadd( LOG_INFO, "%s", buffer );
- return true;
- }
- if ( ( cow.fhs = open( pathStatus, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR ) ) == -1 ) {
- logadd( LOG_ERROR, "Could not create cow status file. Bye.\n" );
- return false;
}
+ if ( statFile ) {
+ if ( ( cow.fhs = open( pathStatus, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR ) ) == -1 ) {
+ logadd( LOG_ERROR, "Could not create cow status file. Bye.\n" );
+ return false;
+ }
- if ( pwrite( cow.fhs, buffer, len, 0 ) != len ) {
- logadd( LOG_ERROR, "Could not write to cow status file. Bye.\n" );
- return false;
+ if ( pwrite( cow.fhs, buffer, len, 0 ) != len ) {
+ logadd( LOG_ERROR, "Could not write to cow status file. Bye.\n" );
+ return false;
+ }
}
return true;
}
@@ -659,9 +663,10 @@ bool createCowStatsFile( char *path )
* @param imageSizePtr
*/
bool cowfile_init( char *path, const char *image_Name, uint16_t imageVersion, atomic_uint_fast64_t **imageSizePtr,
- char *serverAddress, int isForeground )
+ char *serverAddress, bool sStdout, bool sfile)
{
- foreground = isForeground;
+ statStdout = sStdout;
+ statFile = sfile;
char pathMeta[strlen( path ) + 6];
char pathData[strlen( path ) + 6];
@@ -755,7 +760,9 @@ bool cowfile_init( char *path, const char *image_Name, uint16_t imageVersion, at
createCowStatsFile( path );
pthread_create( &tidCowUploader, NULL, &cowfile_uploader, NULL );
- pthread_create( &tidStatUpdater, NULL, &cowfile_statUpdater, NULL );
+ if ( statFile || statStdout) {
+ pthread_create( &tidStatUpdater, NULL, &cowfile_statUpdater, NULL );
+ }
return true;
}
@@ -765,9 +772,10 @@ bool cowfile_init( char *path, const char *image_Name, uint16_t imageVersion, at
* @param path where the meta & data file is located
* @param imageSizePtr
*/
-bool cowfile_load( char *path, atomic_uint_fast64_t **imageSizePtr, char *serverAddress, int isForeground )
+bool cowfile_load( char *path, atomic_uint_fast64_t **imageSizePtr, char *serverAddress, bool sStdout, bool sFile )
{
- foreground = isForeground;
+ statStdout = sStdout;
+ statFile = sFile;
cowServerAddress = serverAddress;
curl_global_init( CURL_GLOBAL_ALL );
curl = curl_easy_init();
@@ -862,8 +870,10 @@ bool cowfile_load( char *path, atomic_uint_fast64_t **imageSizePtr, char *server
pthread_mutex_init( &cow.l2CreateLock, NULL );
createCowStatsFile( path );
pthread_create( &tidCowUploader, NULL, &cowfile_uploader, NULL );
- pthread_create( &tidStatUpdater, NULL, &cowfile_statUpdater, NULL );
+ if ( statFile || statStdout) {
+ pthread_create( &tidStatUpdater, NULL, &cowfile_statUpdater, NULL );
+ }
return true;
}
@@ -1326,7 +1336,9 @@ fail:;
void cowfile_close()
{
uploadLoop = false;
- pthread_join( tidStatUpdater, NULL );
+ if ( statFile || statStdout) {
+ pthread_join( tidStatUpdater, NULL );
+ }
pthread_join( tidCowUploader, NULL );
if ( curl ) {
diff --git a/src/fuse/cowfile.h b/src/fuse/cowfile.h
index abcc85f..a61beab 100644
--- a/src/fuse/cowfile.h
+++ b/src/fuse/cowfile.h
@@ -103,9 +103,9 @@ typedef int32_t l1;
typedef cow_block_metadata_t l2[COW_L2_SIZE];
bool cowfile_init( char *path, const char *image_Name, uint16_t imageVersion, atomic_uint_fast64_t **imageSizePtr,
- char *serverAddress, int isForeground );
+ char *serverAddress, bool sStdout, bool sFile );
-bool cowfile_load( char *path, atomic_uint_fast64_t **imageSizePtr, char *serverAddress, int isForeground );
+bool cowfile_load( char *path, atomic_uint_fast64_t **imageSizePtr, char *serverAddress, bool sStdout, bool sFile );
void cowfile_read( fuse_req_t req, size_t size, off_t offset );
diff --git a/src/fuse/main.c b/src/fuse/main.c
index 926fcab..571bbb4 100644
--- a/src/fuse/main.c
+++ b/src/fuse/main.c
@@ -359,11 +359,12 @@ static void printUsage( char *argv0, int exitCode )
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" );
- printf( " -m merge changes on the server after unmount (only works with -c)\n" );
+ printf( " --cowStatStdout prints the cow status in stdout" );
+ printf( " --cowStatFile creates and updates the cow status file" );
exit( exitCode );
}
-static const char *optString = "dfHh:i:l:o:r:SsVvc:L:C:m";
+static const char *optString = "dfHh:i:l:o:r:SsVvc:L:C:mxy";
static const struct option longOpts[] = {
{ "debug", no_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'H' },
@@ -378,6 +379,8 @@ static const struct option longOpts[] = {
{ "loadcow", required_argument, NULL, 'L' },
{ "cowServer", required_argument, NULL, 'C' },
{ "merge", no_argument, NULL, 'm' },
+ { "cowStatStdout", no_argument, NULL, 'x' },
+ { "cowStatFile", no_argument, NULL, 'y' },
{ 0, 0, 0, 0 }
};
@@ -399,6 +402,8 @@ int main( int argc, char *argv[] )
int foreground = 0;
char *cow_file_path = NULL;
bool loadCow = false;
+ bool sStdout = false;
+ bool sFile = false;
log_init();
@@ -479,6 +484,12 @@ int main( int argc, char *argv[] )
useCow = true;
loadCow = true;
break;
+ case 'x':
+ sStdout = true;
+ break;
+ case 'y':
+ sFile = true;
+ break;
default:
printUsage( argv[0], EXIT_FAILURE );
}
@@ -505,7 +516,7 @@ int main( int argc, char *argv[] )
printUsage( argv[0], EXIT_FAILURE );
}
if ( loadCow ) {
- if ( !cowfile_load( cow_file_path, &imageSizePtr, cow_server_address, foreground ) ) {
+ if ( !cowfile_load( cow_file_path, &imageSizePtr, cow_server_address, sStdout, sFile ) ) {
return EXIT_FAILURE;
}
}
@@ -554,7 +565,7 @@ int main( int argc, char *argv[] )
owner = getuid();
if ( useCow & !loadCow) {
- if( !cowfile_init( cow_file_path, connection_getImageName(), connection_getImageRID(), &imageSizePtr, cow_server_address, foreground ) ) {
+ if( !cowfile_init( cow_file_path, connection_getImageName(), connection_getImageRID(), &imageSizePtr, cow_server_address, sStdout, sFile ) ) {
return EXIT_FAILURE;
}
}