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
|
#ifndef _IMAGE_H_
#define _IMAGE_H_
#include "globals.h"
struct json_t;
void image_serverStartup();
bool image_isComplete(dnbd3_image_t *image);
bool image_isHashBlockComplete(dnbd3_cache_map_t * const cache, const uint64_t block, const uint64_t fileSize);
void image_updateCachemap(dnbd3_image_t *image, uint64_t start, uint64_t end, const bool set);
void image_markComplete(dnbd3_image_t *image);
bool image_ensureOpen(dnbd3_image_t *image);
dnbd3_image_t* image_byId(int imgId);
dnbd3_image_t* image_get(const char *name, uint16_t revision, bool checkIfWorking);
bool image_reopenCacheFd(dnbd3_image_t *image, const bool force);
dnbd3_image_t* image_getOrLoad(char *name, uint16_t revision);
dnbd3_image_t* image_lock(dnbd3_image_t *image);
dnbd3_image_t* image_release(dnbd3_image_t *image);
bool image_checkBlocksCrc32(int fd, uint32_t *crc32list, const int *blocks, const uint64_t fileSize);
void image_killUplinks();
bool image_loadAll(char *path);
bool image_tryFreeAll();
bool image_create(char *image, int revision, uint64_t size);
bool image_generateCrcFile(char *image);
struct json_t* image_getListAsJson();
int image_getCompletenessEstimate(dnbd3_image_t * const image);
void image_closeUnusedFd();
bool image_ensureDiskSpaceLocked(uint64_t size, bool force);
bool image_saveCacheMap(dnbd3_image_t *image);
/**
* Check if given range is cached. Be careful when using this function because:
* 1) you need to hold a reference to the cache map
* 2) start and end are assumed to be 4k aligned
* 3) start and end are not checked to be in bounds (we don't know the image in this context)
*/
static inline bool image_isRangeCachedUnsafe(dnbd3_cache_map_t *cache, uint64_t start, uint64_t end)
{
const uint64_t firstByteInMap = start >> 15;
const uint64_t lastByteInMap = (end - 1) >> 15;
const uint8_t fb = (uint8_t)(0xff << ((start >> 12) & 7));
const uint8_t lb = (uint8_t)(~(0xff << ((((end - 1) >> 12) & 7) + 1)));
uint64_t pos;
uint8_t b;
bool isCached;
if ( firstByteInMap == lastByteInMap ) { // Single byte to check, much simpler
b = cache->map[firstByteInMap];
isCached = ( b & ( fb & lb ) ) == ( fb & lb );
} else {
isCached = true;
atomic_thread_fence( memory_order_acquire );
// First byte
if ( isCached ) {
b = atomic_load_explicit( &cache->map[firstByteInMap], memory_order_relaxed );
isCached = ( ( b & fb ) == fb );
}
// Last byte
if ( isCached ) {
b = atomic_load_explicit( &cache->map[lastByteInMap], memory_order_relaxed );
isCached = ( ( b & lb ) == lb );
}
// Middle, must be all bits set (0xff)
if ( isCached ) {
for ( pos = firstByteInMap + 1; pos < lastByteInMap; ++pos ) {
if ( atomic_load_explicit( &cache->map[pos], memory_order_relaxed ) != 0xff ) {
isCached = false;
break;
}
}
}
}
return isCached;
}
// one byte in the map covers 8 4kib blocks, so 32kib per byte
// "+ (1 << 15) - 1" is required to account for the last bit of
// the image that is smaller than 32kib
// this would be the case whenever the image file size is not a
// multiple of 32kib (= the number of blocks is not divisible by 8)
// ie: if the image is 49152 bytes and you do 49152 >> 15 you get 1,
// but you actually need 2 bytes to have a complete cache map
#define IMGSIZE_TO_MAPBYTES(bytes) ((int)(((bytes) + (1 << 15) - 1) >> 15))
// calculate number of hash blocks in file. One hash block is 16MiB
#define HASH_BLOCK_SIZE ((int64_t)(1 << 24))
#define IMGSIZE_TO_HASHBLOCKS(bytes) ((int)(((bytes) + HASH_BLOCK_SIZE - 1) / HASH_BLOCK_SIZE))
#endif
|