]> git.sesse.net Git - bcachefs-tools-debian/blob - bcacheadm-format.c
Major refactoring, add new settings to bcacheadm format
[bcachefs-tools-debian] / bcacheadm-format.c
1 /*
2  * Authors: Kent Overstreet <kmo@daterainc.com>
3  *          Gabriel de Perthuis <g2p.code@gmail.com>
4  *          Jacob Malevich <jam@datera.io>
5  *
6  * GPLv2
7  */
8
9 #if 0
10 #include <nih/main.h>
11 #include <nih/logging.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <inttypes.h>
15 #include <limits.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18 #include <blkid.h>
19 #include <sys/ioctl.h>
20 #include <sys/stat.h>
21 #include <dirent.h>
22 #endif
23
24 #include <errno.h>
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31
32 #include <uuid/uuid.h>
33
34 #include <nih/command.h>
35 #include <nih/option.h>
36
37 #include "bcache.h"
38 #include "bcacheadm.h"
39
40 static struct cache_opts {
41         int             fd;
42         const char      *dev;
43         unsigned        bucket_size;
44         unsigned        tier;
45         unsigned        replacement_policy;
46         unsigned        replication_set;
47         uint64_t        filesystem_size;
48 } cache_devices[MAX_DEVS];
49
50 static struct backingdev_opts {
51         int             fd;
52         const char      *dev;
53         const char      *label;
54 } backing_devices[MAX_DEVS];
55
56 static size_t nr_backing_devices = 0, nr_cache_devices = 0;
57
58 static char *label = NULL;
59
60 /* All in units of 512 byte sectors */
61 static unsigned block_size;
62 static unsigned bucket_size = 2048;
63 static unsigned btree_node_size;
64 static uint64_t filesystem_size;
65 static unsigned tier, replacement_policy;
66
67 static uuid_t cache_set_uuid;
68 static unsigned csum_type = BCH_CSUM_CRC32C;
69 static unsigned replication_set, meta_replicas = 1, data_replicas = 1;
70 static unsigned on_error_action;
71 static int discard;
72
73 static uint64_t data_offset = BDEV_DATA_START_DEFAULT;
74 static unsigned cache_mode = CACHE_MODE_WRITEBACK;
75
76 static int set_cache(NihOption *option, const char *arg)
77 {
78         cache_devices[nr_cache_devices++] = (struct cache_opts) {
79                 .dev                    = strdup(arg),
80                 .bucket_size            = bucket_size,
81                 .tier                   = tier,
82                 .replacement_policy     = replacement_policy,
83                 .replication_set        = replication_set,
84                 .filesystem_size        = filesystem_size,
85         };
86         return 0;
87 }
88
89 static int set_bdev(NihOption *option, const char *arg)
90 {
91         backing_devices[nr_backing_devices++] = (struct backingdev_opts) {
92                 .dev                    = strdup(arg),
93                 .label                  = strdup(label),
94         };
95         return 0;
96 }
97
98 static int set_cache_set_uuid(NihOption *option, const char *arg)
99 {
100         if (uuid_parse(arg, cache_set_uuid))
101                 die("Bad uuid");
102         return 0;
103 }
104
105 static int set_block_size(NihOption *option, const char *arg)
106 {
107         block_size = hatoi_validate(arg, "block size");
108         return 0;
109 }
110
111 static int set_bucket_sizes(NihOption *option, const char *arg)
112 {
113         bucket_size = hatoi_validate(arg, "bucket size");
114         return 0;
115 }
116
117 static int set_btree_node_size(NihOption *option, const char *arg)
118 {
119         btree_node_size = hatoi_validate(arg, "btree node size");
120         return 0;
121 }
122
123 static int set_filesystem_size(NihOption *option, const char *arg)
124 {
125         filesystem_size = hatoi(arg) >> 9;
126         return 0;
127 }
128
129 static int set_replacement_policy(NihOption *option, const char *arg)
130 {
131         replacement_policy = read_string_list_or_die(arg, replacement_policies,
132                                                      "replacement policy");
133         return 0;
134 }
135
136 static int set_csum_type(NihOption *option, const char *arg)
137 {
138         csum_type = read_string_list_or_die(arg, csum_types, "checksum type");
139         return 0;
140 }
141
142 static int set_on_error_action(NihOption *option, const char *arg)
143 {
144         on_error_action = read_string_list_or_die(arg, error_actions,
145                                                   "error action");
146         return 0;
147 }
148
149 static int set_tier(NihOption *option, const char *arg)
150 {
151         tier = strtoul_or_die(arg, CACHE_TIERS, "tier");
152         return 0;
153 }
154
155 static int set_replication_set(NihOption *option, const char *arg)
156 {
157         replication_set = strtoul_or_die(arg, CACHE_REPLICATION_SET_MAX,
158                                          "replication set");
159         return 0;
160 }
161
162 static int set_meta_replicas(NihOption *option, const char *arg)
163 {
164         meta_replicas = strtoul_or_die(arg, CACHE_SET_META_REPLICAS_WANT_MAX,
165                                        "meta_replicas");
166         return 0;
167 }
168
169 static int set_data_replicas(NihOption *option, const char *arg)
170 {
171         data_replicas = strtoul_or_die(arg, CACHE_SET_DATA_REPLICAS_WANT_MAX,
172                                        "data_replicas");
173         return 0;
174 }
175
176 static int set_cache_mode(NihOption *option, const char *arg)
177 {
178         cache_mode = read_string_list_or_die(arg, bdev_cache_mode,
179                                              "cache mode");
180         return 0;
181 }
182
183 NihOption bcacheadm_format_options[] = {
184 //      { int shortoption, char *longoption, char *help, NihOptionGroup, char *argname, void *value, NihOptionSetter}
185
186         { 'C',  "cache",                N_("Format a cache device"),
187                 NULL, "dev",    NULL,   set_cache },
188         { 'B',  "bdev",                 N_("Format a backing device"),
189                 NULL, "dev",    NULL,   set_bdev },
190
191         { 'l',  "label",                N_("label"),
192                 NULL, "label",  &label, NULL},
193         { 0,    "cset_uuid",            N_("UUID for the cache set"),
194                 NULL, "uuid",   NULL,   set_cache_set_uuid },
195
196         { 'w',  "block",                N_("block size (hard sector size of SSD, often 2k"),
197                 NULL, "size",   NULL,   set_block_size },
198         { 'b',  "bucket",               N_("bucket size"),
199                 NULL, "size",   NULL,   set_bucket_sizes },
200         { 'n',  "btree-node",           N_("Btree node size, default 256k"),
201                 NULL, "size",   NULL,   set_btree_node_size },
202         { 0,    "fs-size",              N_("Size of filesystem on device" ),
203                 NULL, "size",   NULL,   set_filesystem_size },
204
205         { 'p',  "cache_replacement_policy", NULL,
206                 NULL, "(lru|fifo|random)", NULL, set_replacement_policy },
207
208         { 0,    "csum-type",            N_("Checksum type"),
209                 NULL, "(none|crc32c|crc64)", NULL, set_csum_type },
210
211         { 0,    "on-error",             N_("Action to take on filesystem error"),
212                 NULL, "(continue|readonly|panic)", NULL, set_on_error_action },
213
214         { 0,    "discard",              N_("Enable discards"),
215                 NULL, NULL,     &discard,               NULL },
216
217         { 't',  "tier",                 N_("tier of subsequent devices"),
218                 NULL, "#",      NULL,   set_tier },
219
220         { 0,    "replication_set",      N_("replication set of subsequent devices"),
221                 NULL, "#",      NULL,   set_replication_set },
222
223         { 0,    "meta-replicas",        N_("number of metadata replicas"),
224                 NULL, "#",      NULL,   set_meta_replicas },
225
226         { 0,    "data-replicas",        N_("number of data replicas"),
227                 NULL, "#",      NULL,   set_data_replicas },
228
229         { 0,    "cache_mode",           N_("Cache mode (for backing devices)"),
230                 NULL, "(writethrough|writeback|writearound", NULL, set_cache_mode },
231
232         { 'o',  "data_offset",          N_("data offset in sectors"),
233                 NULL, "offset", &data_offset, NULL},
234
235         NIH_OPTION_LAST
236 };
237
238 int bcacheadm_format(NihCommand *command, char *const *args)
239 {
240         struct cache_sb *cache_set_sb;
241
242         if (!nr_cache_devices && !nr_backing_devices)
243                 die("Please supply a device");
244
245         for (struct cache_opts *i = cache_devices;
246              i < cache_devices + nr_cache_devices;
247              i++)
248                 i->fd = dev_open(i->dev);
249
250         for (struct backingdev_opts *i = backing_devices;
251              i < backing_devices + nr_backing_devices;
252              i++)
253                 i->fd = dev_open(i->dev);
254
255         if (!block_size) {
256                 for (struct cache_opts *i = cache_devices;
257                      i < cache_devices + nr_cache_devices;
258                      i++)
259                         block_size = max(block_size, get_blocksize(i->dev, i->fd));
260
261                 for (struct backingdev_opts *i = backing_devices;
262                      i < backing_devices + nr_backing_devices;
263                      i++)
264                         block_size = max(block_size, get_blocksize(i->dev, i->fd));
265         }
266
267         if (!btree_node_size) {
268                 btree_node_size = 512;
269
270                 for (struct cache_opts *i = cache_devices;
271                      i < cache_devices + nr_cache_devices;
272                      i++)
273                         btree_node_size = min(btree_node_size, i->bucket_size);
274         }
275
276         cache_set_sb = calloc(1, sizeof(*cache_set_sb) +
277                               sizeof(struct cache_member) * nr_cache_devices);
278
279         cache_set_sb->offset            = SB_SECTOR;
280         cache_set_sb->version           = BCACHE_SB_VERSION_CDEV_V3;
281         cache_set_sb->magic             = BCACHE_MAGIC;
282         cache_set_sb->block_size        = block_size;
283         uuid_generate(cache_set_sb->set_uuid.b);
284
285         if (uuid_is_null(cache_set_uuid))
286                 uuid_generate(cache_set_sb->user_uuid.b);
287         else
288                 memcpy(cache_set_sb->user_uuid.b, cache_set_uuid,
289                        sizeof(cache_set_sb->user_uuid));
290
291         if (label)
292                 memcpy(cache_set_sb->label, label, sizeof(cache_set_sb->label));
293
294         /*
295          * don't have a userspace crc32c implementation handy, just always use
296          * crc64
297          */
298         SET_CACHE_SB_CSUM_TYPE(cache_set_sb,            BCH_CSUM_CRC64);
299         SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb,     csum_type);
300
301         SET_CACHE_BTREE_NODE_SIZE(cache_set_sb,         btree_node_size);
302         SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb,  meta_replicas);
303         SET_CACHE_SET_META_REPLICAS_HAVE(cache_set_sb,  meta_replicas);
304         SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb,  data_replicas);
305         SET_CACHE_SET_DATA_REPLICAS_HAVE(cache_set_sb,  data_replicas);
306         SET_CACHE_ERROR_ACTION(cache_set_sb,            on_error_action);
307
308         for (struct cache_opts *i = cache_devices;
309              i < cache_devices + nr_cache_devices;
310              i++) {
311                 if (i->bucket_size < block_size)
312                         die("Bucket size cannot be smaller than block size");
313
314                 struct cache_member *m = cache_set_sb->members + cache_set_sb->nr_in_set++;
315
316                 uuid_generate(m->uuid.b);
317                 m->nbuckets     = (i->filesystem_size ?:
318                                    getblocks(i->fd)) / i->bucket_size;
319                 m->first_bucket = (23 / i->bucket_size) + 3;
320                 m->bucket_size  = i->bucket_size;
321
322                 if (m->nbuckets < 1 << 7)
323                         die("Not enough buckets: %llu, need %u",
324                             m->nbuckets, 1 << 7);
325
326                 SET_CACHE_TIER(m,               i->tier);
327                 SET_CACHE_REPLICATION_SET(m,    i->replication_set);
328                 SET_CACHE_REPLACEMENT(m,        i->replacement_policy);
329                 SET_CACHE_DISCARD(m,            discard);
330         }
331
332         cache_set_sb->u64s = bch_journal_buckets_offset(cache_set_sb);
333
334         for (unsigned i = 0; i < cache_set_sb->nr_in_set; i++) {
335                 char uuid_str[40], set_uuid_str[40];
336                 struct cache_member *m = cache_set_sb->members + i;
337
338                 cache_set_sb->disk_uuid         = m->uuid;
339                 cache_set_sb->nr_this_dev       = i;
340                 cache_set_sb->csum              = csum_set(cache_set_sb,
341                                                 CACHE_SB_CSUM_TYPE(cache_set_sb));
342
343                 uuid_unparse(cache_set_sb->disk_uuid.b, uuid_str);
344                 uuid_unparse(cache_set_sb->user_uuid.b, set_uuid_str);
345                 printf("UUID:                   %s\n"
346                        "Set UUID:               %s\n"
347                        "version:                %u\n"
348                        "nbuckets:               %llu\n"
349                        "block_size:             %u\n"
350                        "bucket_size:            %u\n"
351                        "nr_in_set:              %u\n"
352                        "nr_this_dev:            %u\n"
353                        "first_bucket:           %u\n",
354                        uuid_str, set_uuid_str,
355                        (unsigned) cache_set_sb->version,
356                        m->nbuckets,
357                        cache_set_sb->block_size,
358                        m->bucket_size,
359                        cache_set_sb->nr_in_set,
360                        cache_set_sb->nr_this_dev,
361                        m->first_bucket);
362
363                 do_write_sb(cache_devices[i].fd, cache_set_sb);
364         }
365
366         for (struct backingdev_opts *i = backing_devices;
367              i < backing_devices + nr_backing_devices;
368              i++)
369                 write_backingdev_sb(i->fd, block_size, cache_mode,
370                                     data_offset, i->label,
371                                     cache_set_sb->user_uuid,
372                                     cache_set_sb->set_uuid);
373
374
375         return 0;
376 }