summaryrefslogtreecommitdiffstats
path: root/src/fuse/cowfile.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/fuse/cowfile.h')
-rw-r--r--src/fuse/cowfile.h146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/fuse/cowfile.h b/src/fuse/cowfile.h
new file mode 100644
index 0000000..3b1711c
--- /dev/null
+++ b/src/fuse/cowfile.h
@@ -0,0 +1,146 @@
+#ifndef _COWFILE_H_
+#define _COWFILE_H_
+
+#include "connection.h"
+
+#include <dnbd3/config/cow.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdatomic.h>
+#include <stdlib.h>
+
+// Net storage capacity of a single cluster in the data file
+#define COW_DATA_CLUSTER_SIZE ( COW_BITFIELD_SIZE * 8 * DNBD3_BLOCK_SIZE )
+// Number of entries per L2 table
+#define COW_L2_TABLE_SIZE 1024
+// Net storage capacity in data file represented by a full L2 table
+#define COW_FULL_L2_TABLE_DATA_SIZE ( COW_L2_TABLE_SIZE * COW_DATA_CLUSTER_SIZE )
+
+_Static_assert( ATOMIC_INT_LOCK_FREE == 2, "ATOMIC INT not lock free" );
+_Static_assert( ATOMIC_LONG_LOCK_FREE == 2, "ATOMIC LONG not lock free" );
+_Static_assert( ATOMIC_LLONG_LOCK_FREE == 2, "ATOMIC LLONG not lock free" );
+_Static_assert( sizeof( atomic_uint_least64_t ) == 8, "atomic_uint_least64_t not 8 byte" );
+_Static_assert( sizeof( _Atomic(uint32_t) ) == 4, "_Atomic(uint32_t) not 4 byte" );
+_Static_assert( sizeof( atomic_int_least64_t ) == 8, "atomic_int_least64_t not 8 byte" );
+
+enum dataSource
+{
+ ds_invalid,
+ ds_local,
+ ds_remote,
+ ds_zero
+};
+
+#define COW_METADATA_HEADER_SIZE 320
+typedef struct cowfile_metadata_header
+{
+ uint64_t magicValue; // 8byte
+ atomic_uint_least64_t imageSize; // 8byte
+ int32_t version; // 4byte
+ int32_t blocksize; // 4byte
+ uint64_t validRemoteSize; // 8byte
+ uint32_t startL1; // 4byte
+ uint32_t startL2; // 4byte
+ int32_t bitfieldSize; // 4byte
+ int32_t nextL2; // 4byte
+ atomic_int_least64_t metaSize; // 8byte
+ atomic_int_least64_t nextClusterOffset; // 8byte
+ uint64_t maxImageSize; // 8byte
+ uint64_t creationTime; // 8byte
+ char uuid[40]; // 40byte
+ 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" );
+
+#define COW_L2_ENTRY_SIZE 64
+typedef struct cow_l2_entry
+{
+ atomic_int_least64_t offset;
+ atomic_int_least64_t timeChanged;
+ _Atomic(uint32_t) uploads;
+ _Atomic(uint32_t) fails;
+ atomic_uchar bitfield[COW_BITFIELD_SIZE];
+} cow_l2_entry_t;
+_Static_assert( sizeof( cow_l2_entry_t ) == COW_L2_ENTRY_SIZE, "cow_l2_entry_t is messed up" );
+
+/**
+ * Open request for reading/writing the virtual image we expose.
+ */
+typedef struct cow_request
+{
+ size_t fuseRequestSize; // Number of bytes to be read/written
+ off_t fuseRequestOffset; // Absolute offset into the image, as seen by user space
+ char *readBuffer; // Used only in read case
+ const char *writeBuffer; // Used only in write case
+ atomic_size_t bytesWorkedOn; // Used for tracking how many bytes we have touched (exluding padding etc)
+ atomic_int workCounter; // How many pending sub requests (see below)
+ atomic_int errorCode; // For reporting back to fuse
+ fuse_ino_t ino; // Inode of file, used for ??? (For reporting back to fuse, dont know if needed?)
+ struct fuse_file_info *fi; // Used for ??? (For reporting back to fuse, dont know if needed?)
+ //fuse_req_t req; // Fuse request
+} cow_request_t;
+
+typedef struct cow_sub_request cow_sub_request_t;
+typedef void ( *cow_callback )( cow_sub_request_t *sRequest );
+
+/**
+ * A sub-request for above, which needs to be completed successfully
+ * before the parent cow_request can be completed.
+ * TODO Please verify field comments
+ */
+typedef struct cow_sub_request
+{
+ size_t size; // size of this sub-request
+ off_t inClusterOffset; // offset relative to the beginning of the cluster
+ const char *writeSrc; // pointer to the data of a write request which needs padding
+ char *buffer; // The pointer points to the original read buffer to the place where the sub read request should be copied to.
+ cow_l2_entry_t *cluster; // the cluster inClusterOffset refers to
+ cow_callback callback; // Callback when we're done handling this
+ cow_request_t *cowRequest; // parent request
+ dnbd3_async_t dRequest; // Probably request to dnbd3-server for non-aligned writes (wrt 4k dnbd3 block)
+ char writeBuffer[]; // buffer for a padding write request, gets filled from a remote read, then the writeSrc data gets copied into it.
+} cow_sub_request_t;
+
+typedef struct cow_curl_read_upload
+{
+ atomic_uint_least64_t time;
+ cow_l2_entry_t *cluster;
+ size_t position;
+ uint64_t clusterNumber;
+ int64_t ulLast;
+ int retryTime;
+ atomic_uchar bitfield[COW_BITFIELD_SIZE];
+ char replyBuffer[500];
+} cow_curl_read_upload_t;
+
+
+typedef struct cow_cluster_statistics
+{
+ uint64_t clusterNumber;
+ uint64_t uploads;
+} cow_cluster_statistics_t;
+
+typedef int32_t l1;
+typedef cow_l2_entry_t l2[COW_L2_TABLE_SIZE];
+
+bool cowfile_init( char *path, const char *image_Name, uint16_t imageVersion, atomic_uint_fast64_t **imageSizePtr,
+ char *serverAddress, bool sStdout, bool sFile, const char *cowUuid );
+
+bool cowfile_load( char *path, atomic_uint_fast64_t **imageSizePtr, char *serverAddress, bool sStdout, bool sFile, const char *cowUuid );
+bool cowfile_startBackgroundThreads();
+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_setSize( fuse_req_t req, size_t size, fuse_ino_t ino, struct fuse_file_info *fi );
+
+void readRemoteData( cow_sub_request_t *sRequest );
+
+int cow_printStats( char *buffer, const size_t len );
+
+void cowfile_close();
+
+#endif /* COWFILE_H_ */