]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs.c
d4993a1505a1f5c1f2d32abc68a7d31416df7f29
[bcachefs-tools-debian] / libbcachefs.c
1 #include <ctype.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <stdbool.h>
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/stat.h>
10 #include <sys/sysmacros.h>
11 #include <sys/types.h>
12 #include <time.h>
13 #include <unistd.h>
14
15 #include <uuid/uuid.h>
16
17 #include "libbcachefs.h"
18 #include "crypto.h"
19 #include "libbcachefs/bcachefs_format.h"
20 #include "libbcachefs/btree_cache.h"
21 #include "libbcachefs/checksum.h"
22 #include "libbcachefs/disk_groups.h"
23 #include "libbcachefs/opts.h"
24 #include "libbcachefs/replicas.h"
25 #include "libbcachefs/super-io.h"
26
27 #define NSEC_PER_SEC    1000000000L
28
29 /* minimum size filesystem we can create, given a bucket size: */
30 static u64 min_size(unsigned bucket_size)
31 {
32         return BCH_MIN_NR_NBUCKETS * bucket_size;
33 }
34
35 static void init_layout(struct bch_sb_layout *l, unsigned block_size,
36                         u64 start, u64 end)
37 {
38         unsigned sb_size;
39         u64 backup; /* offset of 2nd sb */
40
41         memset(l, 0, sizeof(*l));
42
43         if (start != BCH_SB_SECTOR)
44                 start = round_up(start, block_size);
45         end = round_down(end, block_size);
46
47         if (start >= end)
48                 die("insufficient space for superblocks");
49
50         /*
51          * Create two superblocks in the allowed range: reserve a maximum of 64k
52          */
53         sb_size = min_t(u64, 128, end - start / 2);
54
55         backup = start + sb_size;
56         backup = round_up(backup, block_size);
57
58         backup = min(backup, end);
59
60         sb_size = min(end - backup, backup- start);
61         sb_size = rounddown_pow_of_two(sb_size);
62
63         if (sb_size < 8)
64                 die("insufficient space for superblocks");
65
66         l->magic                = BCACHE_MAGIC;
67         l->layout_type          = 0;
68         l->nr_superblocks       = 2;
69         l->sb_max_size_bits     = ilog2(sb_size);
70         l->sb_offset[0]         = cpu_to_le64(start);
71         l->sb_offset[1]         = cpu_to_le64(backup);
72 }
73
74 void bch2_pick_bucket_size(struct format_opts opts, struct dev_opts *dev)
75 {
76         if (!dev->sb_offset) {
77                 dev->sb_offset  = BCH_SB_SECTOR;
78                 dev->sb_end     = BCH_SB_SECTOR + 256;
79         }
80
81         if (!dev->size)
82                 dev->size = get_size(dev->path, dev->fd) >> 9;
83
84         if (!dev->bucket_size) {
85                 if (dev->size < min_size(opts.block_size))
86                         die("cannot format %s, too small (%llu sectors, min %llu)",
87                             dev->path, dev->size, min_size(opts.block_size));
88
89                 /* Bucket size must be >= block size: */
90                 dev->bucket_size = opts.block_size;
91
92                 /* Bucket size must be >= btree node size: */
93                 dev->bucket_size = max(dev->bucket_size, opts.btree_node_size);
94
95                 /* Want a bucket size of at least 128k, if possible: */
96                 dev->bucket_size = max(dev->bucket_size, 256U);
97
98                 if (dev->size >= min_size(dev->bucket_size)) {
99                         unsigned scale = max(1,
100                                              ilog2(dev->size / min_size(dev->bucket_size)) / 4);
101
102                         scale = rounddown_pow_of_two(scale);
103
104                         /* max bucket size 1 mb */
105                         dev->bucket_size = min(dev->bucket_size * scale, 1U << 11);
106                 } else {
107                         do {
108                                 dev->bucket_size /= 2;
109                         } while (dev->size < min_size(dev->bucket_size));
110                 }
111         }
112
113         dev->nbuckets   = dev->size / dev->bucket_size;
114
115         if (dev->bucket_size < opts.block_size)
116                 die("Bucket size cannot be smaller than block size");
117
118         if (dev->bucket_size < opts.btree_node_size)
119                 die("Bucket size cannot be smaller than btree node size");
120
121         if (dev->nbuckets < BCH_MIN_NR_NBUCKETS)
122                 die("Not enough buckets: %llu, need %u (bucket size %u)",
123                     dev->nbuckets, BCH_MIN_NR_NBUCKETS, dev->bucket_size);
124
125 }
126
127 static unsigned parse_target(struct bch_sb_handle *sb,
128                              struct dev_opts *devs, size_t nr_devs,
129                              const char *s)
130 {
131         struct dev_opts *i;
132         int idx;
133
134         if (!s)
135                 return 0;
136
137         for (i = devs; i < devs + nr_devs; i++)
138                 if (!strcmp(s, i->path))
139                         return dev_to_target(i - devs);
140
141         idx = bch2_disk_path_find(sb, s);
142         if (idx >= 0)
143                 return group_to_target(idx);
144
145         die("Invalid target %s", s);
146         return 0;
147 }
148
149 struct bch_sb *bch2_format(struct format_opts opts,
150                            struct dev_opts *devs, size_t nr_devs)
151 {
152         struct bch_sb_handle sb = { NULL };
153         struct dev_opts *i;
154         struct bch_sb_field_members *mi;
155
156         /* calculate block size: */
157         if (!opts.block_size)
158                 for (i = devs; i < devs + nr_devs; i++)
159                         opts.block_size = max(opts.block_size,
160                                               get_blocksize(i->path, i->fd));
161
162         /* calculate bucket sizes: */
163         for (i = devs; i < devs + nr_devs; i++)
164                 bch2_pick_bucket_size(opts, i);
165
166         /* calculate btree node size: */
167         if (!opts.btree_node_size) {
168                 /* 256k default btree node size */
169                 opts.btree_node_size = 512;
170
171                 for (i = devs; i < devs + nr_devs; i++)
172                         opts.btree_node_size =
173                                 min(opts.btree_node_size, i->bucket_size);
174         }
175
176         if (!is_power_of_2(opts.block_size))
177                 die("block size must be power of 2");
178
179         if (!is_power_of_2(opts.btree_node_size))
180                 die("btree node size must be power of 2");
181
182         if (uuid_is_null(opts.uuid.b))
183                 uuid_generate(opts.uuid.b);
184
185         if (bch2_sb_realloc(&sb, 0))
186                 die("insufficient memory");
187
188         sb.sb->version          = cpu_to_le64(BCH_SB_VERSION_MAX);
189         sb.sb->magic            = BCACHE_MAGIC;
190         sb.sb->block_size       = cpu_to_le16(opts.block_size);
191         sb.sb->user_uuid        = opts.uuid;
192         sb.sb->nr_devices       = nr_devs;
193
194         uuid_generate(sb.sb->uuid.b);
195
196         if (opts.label)
197                 memcpy(sb.sb->label,
198                        opts.label,
199                        min(strlen(opts.label), sizeof(sb.sb->label)));
200
201         SET_BCH_SB_CSUM_TYPE(sb.sb,             opts.meta_csum_type);
202         SET_BCH_SB_META_CSUM_TYPE(sb.sb,        opts.meta_csum_type);
203         SET_BCH_SB_DATA_CSUM_TYPE(sb.sb,        opts.data_csum_type);
204         SET_BCH_SB_COMPRESSION_TYPE(sb.sb,      opts.compression_type);
205         SET_BCH_SB_BACKGROUND_COMPRESSION_TYPE(sb.sb,
206                                                 opts.background_compression_type);
207
208         SET_BCH_SB_BTREE_NODE_SIZE(sb.sb,       opts.btree_node_size);
209         SET_BCH_SB_GC_RESERVE(sb.sb,            8);
210         SET_BCH_SB_META_REPLICAS_WANT(sb.sb,    opts.meta_replicas);
211         SET_BCH_SB_META_REPLICAS_REQ(sb.sb,     opts.meta_replicas_required);
212         SET_BCH_SB_DATA_REPLICAS_WANT(sb.sb,    opts.data_replicas);
213         SET_BCH_SB_DATA_REPLICAS_REQ(sb.sb,     opts.data_replicas_required);
214         SET_BCH_SB_ERROR_ACTION(sb.sb,          opts.on_error_action);
215         SET_BCH_SB_STR_HASH_TYPE(sb.sb,         BCH_STR_HASH_SIPHASH);
216         SET_BCH_SB_ENCODED_EXTENT_MAX_BITS(sb.sb,ilog2(opts.encoded_extent_max));
217
218         SET_BCH_SB_POSIX_ACL(sb.sb,             1);
219
220         struct timespec now;
221         if (clock_gettime(CLOCK_REALTIME, &now))
222                 die("error getting current time: %m");
223
224         sb.sb->time_base_lo     = cpu_to_le64(now.tv_sec * NSEC_PER_SEC + now.tv_nsec);
225         sb.sb->time_precision   = cpu_to_le32(1);
226
227         /* Member info: */
228         mi = bch2_sb_resize_members(&sb,
229                         (sizeof(*mi) + sizeof(struct bch_member) *
230                          nr_devs) / sizeof(u64));
231
232         for (i = devs; i < devs + nr_devs; i++) {
233                 struct bch_member *m = mi->members + (i - devs);
234
235                 uuid_generate(m->uuid.b);
236                 m->nbuckets     = cpu_to_le64(i->nbuckets);
237                 m->first_bucket = 0;
238                 m->bucket_size  = cpu_to_le16(i->bucket_size);
239
240                 SET_BCH_MEMBER_REPLACEMENT(m,   CACHE_REPLACEMENT_LRU);
241                 SET_BCH_MEMBER_DISCARD(m,       i->discard);
242                 SET_BCH_MEMBER_DATA_ALLOWED(m,  i->data_allowed);
243                 SET_BCH_MEMBER_DURABILITY(m,    i->durability + 1);
244         }
245
246         /* Disk groups */
247         for (i = devs; i < devs + nr_devs; i++) {
248                 struct bch_member *m = mi->members + (i - devs);
249                 int idx;
250
251                 if (!i->group)
252                         continue;
253
254                 idx = bch2_disk_path_find_or_create(&sb, i->group);
255                 if (idx < 0)
256                         die("error creating disk path: %s", idx);
257
258                 SET_BCH_MEMBER_GROUP(m, idx + 1);
259         }
260
261         SET_BCH_SB_FOREGROUND_TARGET(sb.sb,
262                 parse_target(&sb, devs, nr_devs, opts.foreground_target));
263         SET_BCH_SB_BACKGROUND_TARGET(sb.sb,
264                 parse_target(&sb, devs, nr_devs, opts.background_target));
265         SET_BCH_SB_PROMOTE_TARGET(sb.sb,
266                 parse_target(&sb, devs, nr_devs, opts.promote_target));
267
268         /* Crypt: */
269         if (opts.encrypted) {
270                 struct bch_sb_field_crypt *crypt =
271                         bch2_sb_resize_crypt(&sb, sizeof(*crypt) / sizeof(u64));
272
273                 bch_sb_crypt_init(sb.sb, crypt, opts.passphrase);
274                 SET_BCH_SB_ENCRYPTION_TYPE(sb.sb, 1);
275         }
276
277         for (i = devs; i < devs + nr_devs; i++) {
278                 sb.sb->dev_idx = i - devs;
279
280                 init_layout(&sb.sb->layout, opts.block_size,
281                             i->sb_offset, i->sb_end);
282
283                 if (i->sb_offset == BCH_SB_SECTOR) {
284                         /* Zero start of disk */
285                         static const char zeroes[BCH_SB_SECTOR << 9];
286
287                         xpwrite(i->fd, zeroes, BCH_SB_SECTOR << 9, 0);
288                 }
289
290                 bch2_super_write(i->fd, sb.sb);
291                 close(i->fd);
292         }
293
294         return sb.sb;
295 }
296
297 void bch2_super_write(int fd, struct bch_sb *sb)
298 {
299         struct nonce nonce = { 0 };
300
301         unsigned i;
302         for (i = 0; i < sb->layout.nr_superblocks; i++) {
303                 sb->offset = sb->layout.sb_offset[i];
304
305                 if (sb->offset == BCH_SB_SECTOR) {
306                         /* Write backup layout */
307                         xpwrite(fd, &sb->layout, sizeof(sb->layout),
308                                 BCH_SB_LAYOUT_SECTOR << 9);
309                 }
310
311                 sb->csum = csum_vstruct(NULL, BCH_SB_CSUM_TYPE(sb), nonce, sb);
312                 xpwrite(fd, sb, vstruct_bytes(sb),
313                         le64_to_cpu(sb->offset) << 9);
314         }
315
316         fsync(fd);
317 }
318
319 struct bch_sb *__bch2_super_read(int fd, u64 sector)
320 {
321         struct bch_sb sb, *ret;
322
323         xpread(fd, &sb, sizeof(sb), sector << 9);
324
325         if (memcmp(&sb.magic, &BCACHE_MAGIC, sizeof(sb.magic)))
326                 die("not a bcachefs superblock");
327
328         size_t bytes = vstruct_bytes(&sb);
329
330         ret = malloc(bytes);
331
332         xpread(fd, ret, bytes, sector << 9);
333
334         return ret;
335 }
336
337 static unsigned get_dev_has_data(struct bch_sb *sb, unsigned dev)
338 {
339         struct bch_sb_field_replicas *replicas;
340         struct bch_replicas_entry *r;
341         unsigned i, data_has = 0;
342
343         replicas = bch2_sb_get_replicas(sb);
344
345         if (replicas)
346                 for_each_replicas_entry(replicas, r)
347                         for (i = 0; i < r->nr_devs; i++)
348                                 if (r->devs[i] == dev)
349                                         data_has |= 1 << r->data_type;
350
351         return data_has;
352 }
353
354 /* superblock printing: */
355
356 static void bch2_sb_print_layout(struct bch_sb *sb, enum units units)
357 {
358         struct bch_sb_layout *l = &sb->layout;
359         unsigned i;
360
361         printf("  type:                         %u\n"
362                "  superblock max size:          %s\n"
363                "  nr superblocks:               %u\n"
364                "  Offsets:                      ",
365                l->layout_type,
366                pr_units(1 << l->sb_max_size_bits, units),
367                l->nr_superblocks);
368
369         for (i = 0; i < l->nr_superblocks; i++) {
370                 if (i)
371                         printf(", ");
372                 printf("%llu", le64_to_cpu(l->sb_offset[i]));
373         }
374         putchar('\n');
375 }
376
377 static void bch2_sb_print_journal(struct bch_sb *sb, struct bch_sb_field *f,
378                                   enum units units)
379 {
380         struct bch_sb_field_journal *journal = field_to_type(f, journal);
381         unsigned i, nr = bch2_nr_journal_buckets(journal);
382
383         printf("  Buckets:                      ");
384         for (i = 0; i < nr; i++) {
385                 if (i)
386                         putchar(' ');
387                 printf("%llu", le64_to_cpu(journal->buckets[i]));
388         }
389         putchar('\n');
390 }
391
392 static void bch2_sb_print_members(struct bch_sb *sb, struct bch_sb_field *f,
393                                   enum units units)
394 {
395         struct bch_sb_field_members *mi = field_to_type(f, members);
396         struct bch_sb_field_disk_groups *gi = bch2_sb_get_disk_groups(sb);
397         unsigned i;
398
399         for (i = 0; i < sb->nr_devices; i++) {
400                 struct bch_member *m = mi->members + i;
401                 time_t last_mount = le64_to_cpu(m->last_mount);
402                 char member_uuid_str[40];
403                 char data_allowed_str[100];
404                 char data_has_str[100];
405                 char group[64];
406                 char time_str[64];
407
408                 if (!bch2_member_exists(m))
409                         continue;
410
411                 uuid_unparse(m->uuid.b, member_uuid_str);
412
413                 if (BCH_MEMBER_GROUP(m)) {
414                         unsigned idx = BCH_MEMBER_GROUP(m) - 1;
415
416                         if (idx < disk_groups_nr(gi)) {
417                                 memcpy(group, gi->entries[idx].label,
418                                        BCH_SB_LABEL_SIZE);
419                                 group[BCH_SB_LABEL_SIZE] = '\0';
420                         } else {
421                                 strcpy(group, "(bad disk groups section");
422                         }
423                 }
424
425                 bch2_scnprint_flag_list(data_allowed_str,
426                                         sizeof(data_allowed_str),
427                                         bch2_data_types,
428                                         BCH_MEMBER_DATA_ALLOWED(m));
429                 if (!data_allowed_str[0])
430                         strcpy(data_allowed_str, "(none)");
431
432                 bch2_scnprint_flag_list(data_has_str,
433                                         sizeof(data_has_str),
434                                         bch2_data_types,
435                                         get_dev_has_data(sb, i));
436                 if (!data_has_str[0])
437                         strcpy(data_has_str, "(none)");
438
439                 if (last_mount) {
440                         struct tm *tm = localtime(&last_mount);
441                         size_t err = strftime(time_str, sizeof(time_str), "%c", tm);
442                         if (!err)
443                                 strcpy(time_str, "(formatting error)");
444                 } else {
445                         strcpy(time_str, "(never)");
446                 }
447
448                 printf("  Device %u:\n"
449                        "    UUID:                       %s\n"
450                        "    Size:                       %s\n"
451                        "    Bucket size:                %s\n"
452                        "    First bucket:               %u\n"
453                        "    Buckets:                    %llu\n"
454                        "    Last mount:                 %s\n"
455                        "    State:                      %s\n"
456                        "    Group:                      %s\n"
457                        "    Data allowed:               %s\n"
458
459                        "    Has data:                   %s\n"
460
461                        "    Replacement policy:         %s\n"
462                        "    Discard:                    %llu\n",
463                        i, member_uuid_str,
464                        pr_units(le16_to_cpu(m->bucket_size) *
465                                 le64_to_cpu(m->nbuckets), units),
466                        pr_units(le16_to_cpu(m->bucket_size), units),
467                        le16_to_cpu(m->first_bucket),
468                        le64_to_cpu(m->nbuckets),
469                        time_str,
470
471                        BCH_MEMBER_STATE(m) < BCH_MEMBER_STATE_NR
472                        ? bch2_dev_state[BCH_MEMBER_STATE(m)]
473                        : "unknown",
474
475                        group,
476                        data_allowed_str,
477                        data_has_str,
478
479                        BCH_MEMBER_REPLACEMENT(m) < CACHE_REPLACEMENT_NR
480                        ? bch2_cache_replacement_policies[BCH_MEMBER_REPLACEMENT(m)]
481                        : "unknown",
482
483                        BCH_MEMBER_DISCARD(m));
484         }
485 }
486
487 static void bch2_sb_print_crypt(struct bch_sb *sb, struct bch_sb_field *f,
488                                 enum units units)
489 {
490         struct bch_sb_field_crypt *crypt = field_to_type(f, crypt);
491
492         printf("  KFD:                  %llu\n"
493                "  scrypt n:             %llu\n"
494                "  scrypt r:             %llu\n"
495                "  scrypt p:             %llu\n",
496                BCH_CRYPT_KDF_TYPE(crypt),
497                BCH_KDF_SCRYPT_N(crypt),
498                BCH_KDF_SCRYPT_R(crypt),
499                BCH_KDF_SCRYPT_P(crypt));
500 }
501
502 static void bch2_sb_print_replicas(struct bch_sb *sb, struct bch_sb_field *f,
503                                    enum units units)
504 {
505         struct bch_sb_field_replicas *replicas = field_to_type(f, replicas);
506         struct bch_replicas_entry *e;
507         unsigned i;
508
509         for_each_replicas_entry(replicas, e) {
510                 printf_pad(32, "  %s:", bch2_data_types[e->data_type]);
511
512                 putchar('[');
513                 for (i = 0; i < e->nr_devs; i++) {
514                         if (i)
515                                 putchar(' ');
516                         printf("%u", e->devs[i]);
517                 }
518                 printf("]\n");
519         }
520 }
521
522 static void bch2_sb_print_quota(struct bch_sb *sb, struct bch_sb_field *f,
523                                 enum units units)
524 {
525 }
526
527 static void bch2_sb_print_disk_groups(struct bch_sb *sb, struct bch_sb_field *f,
528                                       enum units units)
529 {
530 }
531
532 static void bch2_sb_print_clean(struct bch_sb *sb, struct bch_sb_field *f,
533                                 enum units units)
534 {
535 }
536
537 typedef void (*sb_field_print_fn)(struct bch_sb *, struct bch_sb_field *, enum units);
538
539 struct bch_sb_field_toolops {
540         sb_field_print_fn       print;
541 };
542
543 static const struct bch_sb_field_toolops bch2_sb_field_ops[] = {
544 #define x(f, nr)                                        \
545         [BCH_SB_FIELD_##f] = {                          \
546                 .print  = bch2_sb_print_##f,            \
547         },
548         BCH_SB_FIELDS()
549 #undef x
550 };
551
552 static inline void bch2_sb_field_print(struct bch_sb *sb,
553                                        struct bch_sb_field *f,
554                                        enum units units)
555 {
556         unsigned type = le32_to_cpu(f->type);
557
558         if (type < BCH_SB_FIELD_NR)
559                 bch2_sb_field_ops[type].print(sb, f, units);
560         else
561                 printf("(unknown field %u)\n", type);
562 }
563
564 void bch2_sb_print(struct bch_sb *sb, bool print_layout,
565                    unsigned fields, enum units units)
566 {
567         struct bch_sb_field_members *mi;
568         char user_uuid_str[40], internal_uuid_str[40];
569         char fields_have_str[200];
570         char label[BCH_SB_LABEL_SIZE + 1];
571         char time_str[64];
572         struct bch_sb_field *f;
573         u64 fields_have = 0;
574         unsigned nr_devices = 0;
575         time_t time_base = le64_to_cpu(sb->time_base_lo) / NSEC_PER_SEC;
576
577         memset(label, 0, sizeof(label));
578         memcpy(label, sb->label, sizeof(sb->label));
579         uuid_unparse(sb->user_uuid.b, user_uuid_str);
580         uuid_unparse(sb->uuid.b, internal_uuid_str);
581
582         if (time_base) {
583                 struct tm *tm = localtime(&time_base);
584                 size_t err = strftime(time_str, sizeof(time_str), "%c", tm);
585                 if (!err)
586                         strcpy(time_str, "(formatting error)");
587         } else {
588                 strcpy(time_str, "(not set)");
589         }
590
591         mi = bch2_sb_get_members(sb);
592         if (mi) {
593                 struct bch_member *m;
594
595                 for (m = mi->members;
596                      m < mi->members + sb->nr_devices;
597                      m++)
598                         nr_devices += bch2_member_exists(m);
599         }
600
601         vstruct_for_each(sb, f)
602                 fields_have |= 1 << le32_to_cpu(f->type);
603         bch2_scnprint_flag_list(fields_have_str, sizeof(fields_have_str),
604                                 bch2_sb_fields, fields_have);
605
606         printf("External UUID:                  %s\n"
607                "Internal UUID:                  %s\n"
608                "Label:                          %s\n"
609                "Version:                        %llu\n"
610                "Created:                        %s\n"
611                "Block_size:                     %s\n"
612                "Btree node size:                %s\n"
613                "Error action:                   %s\n"
614                "Clean:                          %llu\n"
615
616                "Metadata replicas:              %llu\n"
617                "Data replicas:                  %llu\n"
618
619                "Metadata checksum type:         %s (%llu)\n"
620                "Data checksum type:             %s (%llu)\n"
621                "Compression type:               %s (%llu)\n"
622
623                "Foreground write target:        %llu\n"
624                "Background write target:        %llu\n"
625                "Promote target:                 %llu\n"
626
627                "String hash type:               %s (%llu)\n"
628                "32 bit inodes:                  %llu\n"
629                "GC reserve percentage:          %llu%%\n"
630                "Root reserve percentage:        %llu%%\n"
631
632                "Devices:                        %u live, %u total\n"
633                "Sections:                       %s\n"
634                "Superblock size:                %llu\n",
635                user_uuid_str,
636                internal_uuid_str,
637                label,
638                le64_to_cpu(sb->version),
639                time_str,
640                pr_units(le16_to_cpu(sb->block_size), units),
641                pr_units(BCH_SB_BTREE_NODE_SIZE(sb), units),
642
643                BCH_SB_ERROR_ACTION(sb) < BCH_NR_ERROR_ACTIONS
644                ? bch2_error_actions[BCH_SB_ERROR_ACTION(sb)]
645                : "unknown",
646
647                BCH_SB_CLEAN(sb),
648
649                BCH_SB_META_REPLICAS_WANT(sb),
650                BCH_SB_DATA_REPLICAS_WANT(sb),
651
652                BCH_SB_META_CSUM_TYPE(sb) < BCH_CSUM_OPT_NR
653                ? bch2_csum_types[BCH_SB_META_CSUM_TYPE(sb)]
654                : "unknown",
655                BCH_SB_META_CSUM_TYPE(sb),
656
657                BCH_SB_DATA_CSUM_TYPE(sb) < BCH_CSUM_OPT_NR
658                ? bch2_csum_types[BCH_SB_DATA_CSUM_TYPE(sb)]
659                : "unknown",
660                BCH_SB_DATA_CSUM_TYPE(sb),
661
662                BCH_SB_COMPRESSION_TYPE(sb) < BCH_COMPRESSION_OPT_NR
663                ? bch2_compression_types[BCH_SB_COMPRESSION_TYPE(sb)]
664                : "unknown",
665                BCH_SB_COMPRESSION_TYPE(sb),
666
667                BCH_SB_FOREGROUND_TARGET(sb),
668                BCH_SB_BACKGROUND_TARGET(sb),
669                BCH_SB_PROMOTE_TARGET(sb),
670
671                BCH_SB_STR_HASH_TYPE(sb) < BCH_STR_HASH_NR
672                ? bch2_str_hash_types[BCH_SB_STR_HASH_TYPE(sb)]
673                : "unknown",
674                BCH_SB_STR_HASH_TYPE(sb),
675
676                BCH_SB_INODE_32BIT(sb),
677                BCH_SB_GC_RESERVE(sb),
678                BCH_SB_ROOT_RESERVE(sb),
679
680                nr_devices, sb->nr_devices,
681                fields_have_str,
682                vstruct_bytes(sb));
683
684         if (print_layout) {
685                 printf("\n"
686                        "Layout:\n");
687                 bch2_sb_print_layout(sb, units);
688         }
689
690         vstruct_for_each(sb, f) {
691                 unsigned type = le32_to_cpu(f->type);
692                 char name[60];
693
694                 if (!(fields & (1 << type)))
695                         continue;
696
697                 if (type < BCH_SB_FIELD_NR) {
698                         scnprintf(name, sizeof(name), "%s", bch2_sb_fields[type]);
699                         name[0] = toupper(name[0]);
700                 } else {
701                         scnprintf(name, sizeof(name), "(unknown field %u)", type);
702                 }
703
704                 printf("\n%s (size %llu):\n", name, vstruct_bytes(f));
705                 if (type < BCH_SB_FIELD_NR)
706                         bch2_sb_field_print(sb, f, units);
707         }
708 }
709
710 /* ioctl interface: */
711
712 /* Global control device: */
713 int bcachectl_open(void)
714 {
715         return xopen("/dev/bcachefs-ctl", O_RDWR);
716 }
717
718 /* Filesystem handles (ioctl, sysfs dir): */
719
720 #define SYSFS_BASE "/sys/fs/bcachefs/"
721
722 void bcache_fs_close(struct bchfs_handle fs)
723 {
724         close(fs.ioctl_fd);
725         close(fs.sysfs_fd);
726 }
727
728 struct bchfs_handle bcache_fs_open(const char *path)
729 {
730         struct bchfs_handle ret;
731
732         if (!uuid_parse(path, ret.uuid.b)) {
733                 /* It's a UUID, look it up in sysfs: */
734                 char *sysfs = mprintf(SYSFS_BASE "%s", path);
735                 ret.sysfs_fd = xopen(sysfs, O_RDONLY);
736
737                 char *minor = read_file_str(ret.sysfs_fd, "minor");
738                 char *ctl = mprintf("/dev/bcachefs%s-ctl", minor);
739                 ret.ioctl_fd = xopen(ctl, O_RDWR);
740
741                 free(sysfs);
742                 free(minor);
743                 free(ctl);
744         } else {
745                 /* It's a path: */
746                 ret.ioctl_fd = xopen(path, O_RDONLY);
747
748                 struct bch_ioctl_query_uuid uuid;
749                 if (ioctl(ret.ioctl_fd, BCH_IOCTL_QUERY_UUID, &uuid) < 0)
750                         die("error opening %s: not a bcachefs filesystem", path);
751
752                 ret.uuid = uuid.uuid;
753
754                 char uuid_str[40];
755                 uuid_unparse(uuid.uuid.b, uuid_str);
756
757                 char *sysfs = mprintf(SYSFS_BASE "%s", uuid_str);
758                 ret.sysfs_fd = xopen(sysfs, O_RDONLY);
759                 free(sysfs);
760         }
761
762         return ret;
763 }
764
765 /*
766  * Given a path to a block device, open the filesystem it belongs to; also
767  * return the device's idx:
768  */
769 struct bchfs_handle bchu_fs_open_by_dev(const char *path, unsigned *idx)
770 {
771         char buf[1024], *uuid_str;
772
773         struct stat stat = xstat(path);
774
775         if (!S_ISBLK(stat.st_mode))
776                 die("%s is not a block device", path);
777
778         char *sysfs = mprintf("/sys/dev/block/%u:%u/bcachefs",
779                               major(stat.st_dev),
780                               minor(stat.st_dev));
781         ssize_t len = readlink(sysfs, buf, sizeof(buf));
782         free(sysfs);
783
784         if (len > 0) {
785                 char *p = strrchr(buf, '/');
786                 if (!p || sscanf(p + 1, "dev-%u", idx) != 1)
787                         die("error parsing sysfs");
788
789                 *p = '\0';
790                 p = strrchr(buf, '/');
791                 uuid_str = p + 1;
792         } else {
793                 struct bch_opts opts = bch2_opts_empty();
794
795                 opt_set(opts, noexcl,   true);
796                 opt_set(opts, nochanges, true);
797
798                 struct bch_sb_handle sb;
799                 int ret = bch2_read_super(path, &opts, &sb);
800                 if (ret)
801                         die("Error opening %s: %s", path, strerror(-ret));
802
803                 *idx = sb.sb->dev_idx;
804                 uuid_str = buf;
805                 uuid_unparse(sb.sb->user_uuid.b, uuid_str);
806
807                 bch2_free_super(&sb);
808         }
809
810         return bcache_fs_open(uuid_str);
811 }
812
813 int bchu_data(struct bchfs_handle fs, struct bch_ioctl_data cmd)
814 {
815         int progress_fd = xioctl(fs.ioctl_fd, BCH_IOCTL_DATA, &cmd);
816
817         while (1) {
818                 struct bch_ioctl_data_event e;
819
820                 if (read(progress_fd, &e, sizeof(e)) != sizeof(e))
821                         die("error reading from progress fd %m");
822
823                 if (e.type)
824                         continue;
825
826                 if (e.p.data_type == U8_MAX)
827                         break;
828
829                 printf("\33[2K\r");
830
831                 printf("%llu%% complete: current position %s",
832                        e.p.sectors_done * 100 / e.p.sectors_total,
833                        bch2_data_types[e.p.data_type]);
834
835                 switch (e.p.data_type) {
836                 case BCH_DATA_BTREE:
837                 case BCH_DATA_USER:
838                         printf(" %s:%llu:%llu",
839                                bch2_btree_ids[e.p.btree_id],
840                                e.p.pos.inode,
841                                e.p.pos.offset);
842                 }
843
844                 sleep(1);
845         }
846         printf("\nDone\n");
847
848         close(progress_fd);
849         return 0;
850 }