]> git.sesse.net Git - bcachefs-tools-debian/blob - cmd_format.c
update bcache code, fsck improvements
[bcachefs-tools-debian] / cmd_format.c
1 /*
2  * Authors: Kent Overstreet <kent.overstreet@gmail.com>
3  *          Gabriel de Perthuis <g2p.code@gmail.com>
4  *          Jacob Malevich <jam@datera.io>
5  *
6  * GPLv2
7  */
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <getopt.h>
11 #include <stdbool.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19
20 #include <blkid.h>
21 #include <uuid/uuid.h>
22
23 #include "ccan/darray/darray.h"
24
25 #include "cmds.h"
26 #include "libbcache.h"
27 #include "opts.h"
28 #include "util.h"
29
30 /* Open a block device, do magic blkid stuff: */
31 static int open_for_format(const char *dev, bool force)
32 {
33         blkid_probe pr;
34         const char *fs_type = NULL, *fs_label = NULL;
35         size_t fs_type_len, fs_label_len;
36         int fd;
37
38         if ((fd = open(dev, O_RDWR|O_EXCL)) == -1)
39                 die("Can't open dev %s: %s\n", dev, strerror(errno));
40
41         if (force)
42                 return fd;
43
44         if (!(pr = blkid_new_probe()))
45                 die("blkid error 1");
46         if (blkid_probe_set_device(pr, fd, 0, 0))
47                 die("blkid error 2");
48         if (blkid_probe_enable_partitions(pr, true))
49                 die("blkid error 3");
50         if (blkid_do_fullprobe(pr) < 0)
51                 die("blkid error 4");
52
53         blkid_probe_lookup_value(pr, "TYPE", &fs_type, &fs_type_len);
54         blkid_probe_lookup_value(pr, "LABEL", &fs_label, &fs_label_len);
55
56         if (fs_type) {
57                 if (fs_label)
58                         printf("%s contains a %s filesystem labelled '%s'\n",
59                                dev, fs_type, fs_label);
60                 else
61                         printf("%s contains a %s filesystem\n",
62                                dev, fs_type);
63                 fputs("Proceed anyway?", stdout);
64                 if (!ask_yn())
65                         exit(EXIT_FAILURE);
66         }
67
68         blkid_free_probe(pr);
69         return fd;
70 }
71
72 static void usage(void)
73 {
74         puts("bcache format - create a new bcache filesystem on one or more devices\n"
75              "Usage: bcache format [OPTION]... <devices>\n"
76              "\n"
77              "Options:\n"
78              "  -b, --block=size\n"
79              "      --btree_node=size       Btree node size, default 256k\n"
80              "      --metadata_checksum_type=(none|crc32c|crc64)\n"
81              "      --data_checksum_type=(none|crc32c|crc64)\n"
82              "      --compression_type=(none|lz4|gzip)\n"
83              "      --error_action=(continue|readonly|panic)\n"
84              "                              Action to take on filesystem error\n"
85              "      --max_journal_entry_size=size\n"
86              "  -l, --label=label\n"
87              "      --uuid=uuid\n"
88              "  -f, --force\n"
89              "\n"
90              "Device specific options:\n"
91              "      --fs_size=size          Size of filesystem on device\n"
92              "      --bucket=size           bucket size\n"
93              "      --discard               Enable discards\n"
94              "  -t, --tier=#                tier of subsequent devices\n"
95              "\n"
96              "  -h, --help                  display this help and exit\n"
97              "\n"
98              "Device specific options must come before corresponding devices, e.g.\n"
99              "  bcache format --tier 0 /dev/sdb --tier 1 /dev/sdc\n"
100              "\n"
101              "Report bugs to <linux-bcache@vger.kernel.org>");
102 }
103
104 #define OPTS                                                            \
105         OPT('b',        block_size,             required_argument)      \
106         OPT(0,          btree_node_size,        required_argument)      \
107         OPT(0,          metadata_checksum_type, required_argument)      \
108         OPT(0,          data_checksum_type,     required_argument)      \
109         OPT(0,          compression_type,       required_argument)      \
110         OPT('e',        error_action,           required_argument)      \
111         OPT(0,          max_journal_entry_size, required_argument)      \
112         OPT('L',        label,                  required_argument)      \
113         OPT('U',        uuid,                   required_argument)      \
114         OPT('f',        force,                  no_argument)            \
115         OPT(0,          fs_size,                required_argument)      \
116         OPT(0,          bucket_size,            required_argument)      \
117         OPT('t',        tier,                   required_argument)      \
118         OPT(0,          discard,                no_argument)            \
119         OPT('h',        help,                   no_argument)
120
121 enum {
122         Opt_no_opt = 1,
123 #define OPT(shortopt, longopt, has_arg) Opt_##longopt,
124         OPTS
125 #undef OPT
126 };
127
128 static const struct option format_opts[] = {
129 #define OPT(shortopt, longopt, has_arg) {                               \
130                 #longopt,  has_arg, NULL, Opt_##longopt                 \
131         },
132         OPTS
133 #undef OPT
134         { NULL }
135 };
136
137 static unsigned hatoi_validate(const char *s, const char *msg)
138 {
139         u64 v;
140
141         if (bch_strtoull_h(s, &v))
142                 die("bad %s %s", msg, s);
143
144         if (v & (v - 1))
145                 die("%s must be a power of two", msg);
146
147         v /= 512;
148
149         if (v > USHRT_MAX)
150                 die("%s too large\n", msg);
151
152         if (!v)
153                 die("%s too small\n", msg);
154
155         return v;
156 }
157
158 int cmd_format(int argc, char *argv[])
159 {
160         darray(struct dev_opts) devices;
161         struct dev_opts *dev;
162         unsigned block_size = 0;
163         unsigned btree_node_size = 0;
164         unsigned meta_csum_type = BCH_CSUM_CRC32C;
165         unsigned data_csum_type = BCH_CSUM_CRC32C;
166         unsigned compression_type = BCH_COMPRESSION_NONE;
167         unsigned on_error_action = BCH_ON_ERROR_RO;
168         char *label = NULL;
169         uuid_le uuid;
170         bool force = false;
171
172         /* Device specific options: */
173         u64 filesystem_size = 0;
174         unsigned bucket_size = 0;
175         unsigned tier = 0;
176         bool discard = false;
177         unsigned max_journal_entry_size = 0;
178         char *passphrase = NULL;
179         int opt;
180
181         darray_init(devices);
182         uuid_clear(uuid.b);
183
184         while ((opt = getopt_long(argc, argv,
185                                   "-b:e:L:U:ft:h",
186                                   format_opts,
187                                   NULL)) != -1)
188                 switch (opt) {
189                 case Opt_block_size:
190                 case 'b':
191                         block_size = hatoi_validate(optarg,
192                                                 "block size");
193                         break;
194                 case Opt_btree_node_size:
195                         btree_node_size = hatoi_validate(optarg,
196                                                 "btree node size");
197                         break;
198                 case Opt_metadata_checksum_type:
199                         meta_csum_type = read_string_list_or_die(optarg,
200                                                 bch_csum_types, "checksum type");
201                         break;
202                 case Opt_data_checksum_type:
203                         data_csum_type = read_string_list_or_die(optarg,
204                                                 bch_csum_types, "checksum type");
205                         break;
206                 case Opt_compression_type:
207                         compression_type = read_string_list_or_die(optarg,
208                                                 bch_compression_types,
209                                                 "compression type");
210                         break;
211                 case Opt_error_action:
212                 case 'e':
213                         on_error_action = read_string_list_or_die(optarg,
214                                                 bch_error_actions, "error action");
215                         break;
216                 case Opt_max_journal_entry_size:
217                         max_journal_entry_size = hatoi_validate(optarg,
218                                                 "journal entry size");
219                         break;
220                 case Opt_label:
221                 case 'L':
222                         label = strdup(optarg);
223                         break;
224                 case Opt_uuid:
225                 case 'U':
226                         if (uuid_parse(optarg, uuid.b))
227                                 die("Bad uuid");
228                         break;
229                 case Opt_force:
230                 case 'f':
231                         force = true;
232                         break;
233                 case Opt_fs_size:
234                         if (bch_strtoull_h(optarg, &filesystem_size))
235                                 die("invalid filesystem size");
236
237                         filesystem_size >>= 9;
238                         break;
239                 case Opt_bucket_size:
240                         bucket_size = hatoi_validate(optarg, "bucket size");
241                         break;
242                 case Opt_tier:
243                 case 't':
244                         if (kstrtouint(optarg, 10, &tier) ||
245                             tier >= CACHE_TIERS)
246                                 die("invalid tier");
247                         break;
248                 case Opt_discard:
249                         discard = true;
250                         break;
251                 case Opt_no_opt:
252                         darray_append(devices, (struct dev_opts) {
253                                 .path                   = strdup(optarg),
254                                 .size                   = filesystem_size,
255                                 .bucket_size            = bucket_size,
256                                 .tier                   = tier,
257                                 .discard                = discard,
258                         });
259                         break;
260                 case Opt_help:
261                 case 'h':
262                         usage();
263                         exit(EXIT_SUCCESS);
264                         break;
265                 }
266
267         if (!darray_size(devices))
268                 die("Please supply a device");
269
270         if (uuid_is_null(uuid.b))
271                 uuid_generate(uuid.b);
272
273         darray_foreach(dev, devices)
274                 dev->fd = open_for_format(dev->path, force);
275
276         bcache_format(devices.item, darray_size(devices),
277                       block_size,
278                       btree_node_size,
279                       meta_csum_type,
280                       data_csum_type,
281                       compression_type,
282                       1,
283                       1,
284                       on_error_action,
285                       max_journal_entry_size,
286                       label,
287                       uuid);
288
289         if (passphrase) {
290                 memzero_explicit(passphrase, strlen(passphrase));
291                 free(passphrase);
292         }
293
294         return 0;
295 }