summaryrefslogtreecommitdiffstats
path: root/src/fuse/cowfile.h
blob: a07469de7882de382f250b5dd5f4bd77ed43990c (plain) (blame)
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
#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_int_least64_t ) == 8, "atomic_int_least64_t not 8 byte" );

enum dataSource
{
	local,
	remote,
	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 originalImageSize;             // 8byte - the name implies this is the size of the image on the server, but apparently it changes if we truncate the image etc. better name?
	uint64_t metaDataStart;                 // 8byte
	int32_t bitfieldSize;                   // 4byte
	int32_t nextL2;                         // 4byte
	atomic_uint_least64_t metadataFileSize; // 8byte
	atomic_uint_least64_t dataFileSize;     // 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_uint_least64_t timeChanged;
	atomic_uint_least64_t uploads;
	atomic_char 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.
 * TODO Please verify field comments
 */
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 ???
	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 ???
	struct fuse_file_info *fi; // Used for ???
} 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!? cow-block? DNBD3 block? cluster?
	const char *writeSrc; // ???
	char *buffer; // ???
	cow_l2_entry_t *block; // 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[]; // ???
} cow_sub_request_t;

typedef struct cow_curl_read_upload
{
	atomic_uint_least64_t time;
	cow_l2_entry_t *block;
	size_t position;
	long unsigned int blocknumber;
	int fails;
	int64_t ulLast;
} cow_curl_read_upload_t;


typedef struct cow_block_upload_statistics
{
	uint64_t blocknumber;
	uint64_t uploads;
} cow_block_upload_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 );

bool cowfile_load( char *path, atomic_uint_fast64_t **imageSizePtr, char *serverAddress, bool sStdout, bool sFile );
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_ */