1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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_ */
|