-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.cpp
154 lines (120 loc) · 3.78 KB
/
main.cpp
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
147
148
149
150
151
152
153
154
#include <argp.h>
#include <err.h>
#include <cstdint>
#include <string>
#include <iostream>
#include <cmath>
#include "buse/buse.h"
#include "Storage.hpp"
const int BASE_BLK_SIZE = 1024;
static uint64_t parseBytesStr(const char *str) {
return std::stoull(str); // TODO: suffix parse
}
struct Arguments {
const char *nbdDevice;
const char *storageDir;
const char *chunkPrefix;
uint32_t chunkSize;
uint64_t size;
bool verbose;
};
struct CallbackData {
Arguments *args;
Storage *storage;
};
int main(int argc, char **argv) {
argp_option options[] = {
{"chunk-prefix", 'p', "prefix", 0, "Set chunk file name prefix ('blk' by default)", 0},
{"chunk-size", 'c', "size", 0, "Set chunk file size ('1m' by default)", 0},
{"size", 's', "size", 0, "Available space for data store. If not multiplier of chunk-size or 1024 it will be shrinked ('10m' by default)", 0},
{"verbose", 'v', nullptr, 0, "Verbose output about all operations", 0},
{0},
};
argp argConfig = {
.options = options,
.args_doc = "nbd-device storagedir",
.doc = "Chunked virtual block device (requires nbd kernel module enabled).\n"
"Represents set of files in storagedir (ex. blk0, blk1, ...) as single block device.\n"
};
argConfig.parser = [] (int key, char *arg, struct argp_state *state) -> error_t {
auto args = (Arguments *) state->input;
switch (key) {
case 'p': args->chunkPrefix = arg; break;
case 'c': args->chunkSize = parseBytesStr(arg); break;
case 's': args->size = parseBytesStr(arg); break;
case 'v': args->verbose = true; break;
case ARGP_KEY_ARG:
switch (state->arg_num) {
case 0: args->nbdDevice = arg; break;
case 1: args->storageDir = arg; break;
default:
/* Too many arguments. */
return ARGP_ERR_UNKNOWN;
}
break;
case ARGP_KEY_END:
if (state->arg_num < 2) {
warnx("not enough arguments");
argp_usage(state);
}
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
};
Arguments args = {
.chunkPrefix = "blk",
.chunkSize = 1024 * 1024,
.size = 10 * 1024 * 1024,
.verbose = false,
};
argp_parse(&argConfig, argc, argv, 0, 0, &args);
uint32_t blocksCount = args.size / BASE_BLK_SIZE;
uint64_t chunksCount = blocksCount * BASE_BLK_SIZE / args.chunkSize;
Storage storage(args.storageDir, args.chunkPrefix, args.chunkSize, chunksCount);
buse_operations aop = {
.read = [] (void *buf, uint32_t len, uint64_t offset, void *userdata) {
auto &cbData = *(CallbackData *) userdata;
if (cbData.args->verbose) {
std::cout << "Read " << offset << ", len " << len;
}
uint64_t rlen = cbData.storage->read((char *) buf, offset, len);
if (cbData.args->verbose) {
std::cout << " => " << rlen << std::endl;
}
return rlen == len ? 0 : EINVAL;
},
.write = [] (const void *buf, uint32_t len, uint64_t offset, void *userdata) {
auto &cbData = *(CallbackData *) userdata;
if (cbData.args->verbose) {
std::cout << "Write " << offset << ", len " << len;
}
uint64_t wlen = cbData.storage->write((const char *) buf, offset, len);
if (cbData.args->verbose) {
std::cout << " => " << wlen << std::endl;
}
return wlen == len ? 0 : ENOSPC;
},
.disc = [] (void *userdata) {
auto &cbData = *(CallbackData *) userdata;
cbData.storage->flush();
},
.flush = [] (void *userdata) {
auto &cbData = *(CallbackData *) userdata;
int result = cbData.storage->flush();
return result == 0 ? 0 : EINVAL;
},
.size = 0,
.blksize = BASE_BLK_SIZE,
.size_blocks = blocksCount,
};
std::cout << "Initialize device " << args.nbdDevice << " with 1K-blocks count " << blocksCount << std::endl;
CallbackData cbData = {
.args = &args,
.storage = &storage,
};
int result = buse_main(args.nbdDevice, &aop, &cbData);
std::cout << "Clean up" << std::endl;
return result;
}