]> git.sesse.net Git - bcachefs-tools-debian/blob - cmd_debug.c
Update bcachefs sources to aa540d47ab bcachefs: Option improvements
[bcachefs-tools-debian] / cmd_debug.c
1 #include <fcntl.h>
2 #include <string.h>
3 #include <sys/stat.h>
4 #include <sys/types.h>
5
6 #include "cmds.h"
7 #include "libbcachefs.h"
8 #include "qcow2.h"
9 #include "tools-util.h"
10
11 #include "libbcachefs/bcachefs.h"
12 #include "libbcachefs/bset.h"
13 #include "libbcachefs/btree_cache.h"
14 #include "libbcachefs/btree_io.h"
15 #include "libbcachefs/btree_iter.h"
16 #include "libbcachefs/buckets.h"
17 #include "libbcachefs/checksum.h"
18 #include "libbcachefs/error.h"
19 #include "libbcachefs/journal.h"
20 #include "libbcachefs/journal_io.h"
21 #include "libbcachefs/super.h"
22
23 static void dump_usage(void)
24 {
25         puts("bcachefs dump - dump filesystem metadata\n"
26              "Usage: bcachefs dump [OPTION]... <devices>\n"
27              "\n"
28              "Options:\n"
29              "  -o output     Output qcow2 image(s)\n"
30              "  -f            Force; overwrite when needed\n"
31              "  -h            Display this help and exit\n"
32              "Report bugs to <linux-bcache@vger.kernel.org>");
33 }
34
35 static void dump_one_device(struct bch_fs *c, struct bch_dev *ca, int fd)
36 {
37         struct bch_sb *sb = ca->disk_sb.sb;
38         ranges data;
39         unsigned i;
40         int ret;
41
42         darray_init(data);
43
44         /* Superblock: */
45         range_add(&data, BCH_SB_LAYOUT_SECTOR << 9,
46                   sizeof(struct bch_sb_layout));
47
48         for (i = 0; i < sb->layout.nr_superblocks; i++)
49                 range_add(&data,
50                           le64_to_cpu(sb->layout.sb_offset[i]) << 9,
51                           vstruct_bytes(sb));
52
53         /* Journal: */
54         for (i = 0; i < ca->journal.nr; i++)
55                 if (ca->journal.bucket_seq[i] >= c->journal.last_seq_ondisk) {
56                         u64 bucket = ca->journal.buckets[i];
57
58                         range_add(&data,
59                                   bucket_bytes(ca) * bucket,
60                                   bucket_bytes(ca));
61                 }
62
63         /* Btree: */
64         for (i = 0; i < BTREE_ID_NR; i++) {
65                 const struct bch_extent_ptr *ptr;
66                 struct bkey_ptrs_c ptrs;
67                 struct btree_trans trans;
68                 struct btree_iter iter;
69                 struct btree *b;
70
71                 bch2_trans_init(&trans, c, 0, 0);
72
73                 __for_each_btree_node(&trans, iter, i, POS_MIN, 0, 1, 0, b, ret) {
74                         struct btree_node_iter iter;
75                         struct bkey u;
76                         struct bkey_s_c k;
77
78                         for_each_btree_node_key_unpack(b, k, &iter, &u) {
79                                 ptrs = bch2_bkey_ptrs_c(k);
80
81                                 bkey_for_each_ptr(ptrs, ptr)
82                                         if (ptr->dev == ca->dev_idx)
83                                                 range_add(&data,
84                                                           ptr->offset << 9,
85                                                           btree_bytes(c));
86                         }
87                 }
88
89                 if (ret)
90                         die("error %s walking btree nodes", strerror(-ret));
91
92                 b = c->btree_roots[i].b;
93                 if (!btree_node_fake(b)) {
94                         ptrs = bch2_bkey_ptrs_c(bkey_i_to_s_c(&b->key));
95
96                         bkey_for_each_ptr(ptrs, ptr)
97                                 if (ptr->dev == ca->dev_idx)
98                                         range_add(&data,
99                                                   ptr->offset << 9,
100                                                   btree_bytes(c));
101                 }
102
103                 bch2_trans_iter_exit(&trans, &iter);
104                 bch2_trans_exit(&trans);
105         }
106
107         qcow2_write_image(ca->disk_sb.bdev->bd_fd, fd, &data,
108                           max_t(unsigned, btree_bytes(c) / 8, block_bytes(c)));
109         darray_free(data);
110 }
111
112 int cmd_dump(int argc, char *argv[])
113 {
114         struct bch_opts opts = bch2_opts_empty();
115         struct bch_dev *ca;
116         char *out = NULL;
117         unsigned i, nr_devices = 0;
118         bool force = false;
119         int fd, opt;
120
121         opt_set(opts, nochanges,        true);
122         opt_set(opts, norecovery,       true);
123         opt_set(opts, degraded,         true);
124         opt_set(opts, errors,           BCH_ON_ERROR_continue);
125         opt_set(opts, fix_errors,       FSCK_OPT_NO);
126
127         while ((opt = getopt(argc, argv, "o:fvh")) != -1)
128                 switch (opt) {
129                 case 'o':
130                         out = optarg;
131                         break;
132                 case 'f':
133                         force = true;
134                         break;
135                 case 'v':
136                         opt_set(opts, verbose, true);
137                         break;
138                 case 'h':
139                         dump_usage();
140                         exit(EXIT_SUCCESS);
141                 }
142         args_shift(optind);
143
144         if (!out)
145                 die("Please supply output filename");
146
147         if (!argc)
148                 die("Please supply device(s) to check");
149
150         struct bch_fs *c = bch2_fs_open(argv, argc, opts);
151         if (IS_ERR(c))
152                 die("error opening %s: %s", argv[0], strerror(-PTR_ERR(c)));
153
154         down_read(&c->gc_lock);
155
156         for_each_online_member(ca, c, i)
157                 nr_devices++;
158
159         BUG_ON(!nr_devices);
160
161         for_each_online_member(ca, c, i) {
162                 int flags = O_WRONLY|O_CREAT|O_TRUNC;
163
164                 if (!force)
165                         flags |= O_EXCL;
166
167                 if (!c->devs[i])
168                         continue;
169
170                 char *path = nr_devices > 1
171                         ? mprintf("%s.%u", out, i)
172                         : strdup(out);
173                 fd = xopen(path, flags, 0600);
174                 free(path);
175
176                 dump_one_device(c, ca, fd);
177                 close(fd);
178         }
179
180         up_read(&c->gc_lock);
181
182         bch2_fs_stop(c);
183         return 0;
184 }
185
186 static void list_keys(struct bch_fs *c, enum btree_id btree_id,
187                       struct bpos start, struct bpos end)
188 {
189         struct btree_trans trans;
190         struct btree_iter iter;
191         struct bkey_s_c k;
192         char buf[512];
193         int ret;
194
195         bch2_trans_init(&trans, c, 0, 0);
196
197         for_each_btree_key(&trans, iter, btree_id, start,
198                            BTREE_ITER_ALL_SNAPSHOTS|
199                            BTREE_ITER_PREFETCH, k, ret) {
200                 if (bkey_cmp(k.k->p, end) > 0)
201                         break;
202
203                 bch2_bkey_val_to_text(&PBUF(buf), c, k);
204                 puts(buf);
205         }
206         bch2_trans_iter_exit(&trans, &iter);
207
208         bch2_trans_exit(&trans);
209 }
210
211 static void list_btree_formats(struct bch_fs *c, enum btree_id btree_id, unsigned level,
212                                struct bpos start, struct bpos end)
213 {
214         struct btree_trans trans;
215         struct btree_iter iter;
216         struct btree *b;
217         char buf[4096];
218         int ret;
219
220         bch2_trans_init(&trans, c, 0, 0);
221
222         __for_each_btree_node(&trans, iter, btree_id, start, 0, level, 0, b, ret) {
223                 if (bkey_cmp(b->key.k.p, end) > 0)
224                         break;
225
226                 bch2_btree_node_to_text(&PBUF(buf), c, b);
227                 puts(buf);
228         }
229         bch2_trans_iter_exit(&trans, &iter);
230
231         if (ret)
232                 die("error %s walking btree nodes", strerror(-ret));
233
234         bch2_trans_exit(&trans);
235 }
236
237 static void list_nodes(struct bch_fs *c, enum btree_id btree_id, unsigned level,
238                        struct bpos start, struct bpos end)
239 {
240         struct btree_trans trans;
241         struct btree_iter iter;
242         struct btree *b;
243         char buf[4096];
244         int ret;
245
246         bch2_trans_init(&trans, c, 0, 0);
247
248         __for_each_btree_node(&trans, iter, btree_id, start, 0, level, 0, b, ret) {
249                 if (bkey_cmp(b->key.k.p, end) > 0)
250                         break;
251
252                 bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(&b->key));
253                 fputs(buf, stdout);
254                 putchar('\n');
255         }
256         bch2_trans_iter_exit(&trans, &iter);
257
258         if (ret)
259                 die("error %s walking btree nodes", strerror(-ret));
260
261         bch2_trans_exit(&trans);
262 }
263
264 static void print_node_ondisk(struct bch_fs *c, struct btree *b)
265 {
266         struct btree_node *n_ondisk;
267         struct extent_ptr_decoded pick;
268         struct bch_dev *ca;
269         struct bio *bio;
270         unsigned offset = 0;
271
272         if (bch2_bkey_pick_read_device(c, bkey_i_to_s_c(&b->key), NULL, &pick) <= 0) {
273                 printf("error getting device to read from\n");
274                 return;
275         }
276
277         ca = bch_dev_bkey_exists(c, pick.ptr.dev);
278         if (!bch2_dev_get_ioref(ca, READ)) {
279                 printf("error getting device to read from\n");
280                 return;
281         }
282
283         n_ondisk = malloc(btree_bytes(c));
284
285         bio = bio_alloc_bioset(GFP_NOIO,
286                         buf_pages(n_ondisk, btree_bytes(c)),
287                         &c->btree_bio);
288         bio_set_dev(bio, ca->disk_sb.bdev);
289         bio->bi_opf             = REQ_OP_READ|REQ_META;
290         bio->bi_iter.bi_sector  = pick.ptr.offset;
291         bch2_bio_map(bio, n_ondisk, btree_bytes(c));
292
293         submit_bio_wait(bio);
294
295         bio_put(bio);
296         percpu_ref_put(&ca->io_ref);
297
298         while (offset < btree_sectors(c)) {
299                 struct bset *i;
300                 struct nonce nonce;
301                 struct bch_csum csum;
302                 struct bkey_packed *k;
303                 unsigned sectors;
304
305                 if (!offset) {
306                         i = &n_ondisk->keys;
307
308                         if (!bch2_checksum_type_valid(c, BSET_CSUM_TYPE(i)))
309                                 die("unknown checksum type");
310
311                         nonce = btree_nonce(i, offset << 9);
312                         csum = csum_vstruct(c, BSET_CSUM_TYPE(i), nonce, n_ondisk);
313
314                         if (bch2_crc_cmp(csum, n_ondisk->csum))
315                                 die("invalid checksum\n");
316
317                         bset_encrypt(c, i, offset << 9);
318
319                         sectors = vstruct_sectors(n_ondisk, c->block_bits);
320                 } else {
321                         struct btree_node_entry *bne = (void *) n_ondisk + (offset << 9);
322
323                         i = &bne->keys;
324
325                         if (i->seq != n_ondisk->keys.seq)
326                                 break;
327
328                         if (!bch2_checksum_type_valid(c, BSET_CSUM_TYPE(i)))
329                                 die("unknown checksum type");
330
331                         nonce = btree_nonce(i, offset << 9);
332                         csum = csum_vstruct(c, BSET_CSUM_TYPE(i), nonce, bne);
333
334                         if (bch2_crc_cmp(csum, bne->csum))
335                                 die("invalid checksum");
336
337                         bset_encrypt(c, i, offset << 9);
338
339                         sectors = vstruct_sectors(bne, c->block_bits);
340                 }
341
342                 fprintf(stdout, "  offset %u version %u, journal seq %llu\n",
343                         offset,
344                         le16_to_cpu(i->version),
345                         le64_to_cpu(i->journal_seq));
346                 offset += sectors;
347
348                 for (k = i->start; k != vstruct_last(i); k = bkey_next(k)) {
349                         struct bkey u;
350                         char buf[4096];
351
352                         bch2_bkey_val_to_text(&PBUF(buf), c, bkey_disassemble(b, k, &u));
353                         fprintf(stdout, "    %s\n", buf);
354                 }
355         }
356
357         free(n_ondisk);
358 }
359
360 static void list_nodes_ondisk(struct bch_fs *c, enum btree_id btree_id, unsigned level,
361                               struct bpos start, struct bpos end)
362 {
363         struct btree_trans trans;
364         struct btree_iter iter;
365         struct btree *b;
366         char buf[4096];
367         int ret;
368
369         bch2_trans_init(&trans, c, 0, 0);
370
371         __for_each_btree_node(&trans, iter, btree_id, start, 0, level, 0, b, ret) {
372                 if (bkey_cmp(b->key.k.p, end) > 0)
373                         break;
374
375                 bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(&b->key));
376                 fputs(buf, stdout);
377                 putchar('\n');
378
379                 print_node_ondisk(c, b);
380         }
381         bch2_trans_iter_exit(&trans, &iter);
382
383         if (ret)
384                 die("error %s walking btree nodes", strerror(-ret));
385
386         bch2_trans_exit(&trans);
387 }
388
389 static void list_nodes_keys(struct bch_fs *c, enum btree_id btree_id, unsigned level,
390                             struct bpos start, struct bpos end)
391 {
392         struct btree_trans trans;
393         struct btree_iter iter;
394         struct btree_node_iter node_iter;
395         struct bkey unpacked;
396         struct bkey_s_c k;
397         struct btree *b;
398         char buf[4096];
399         int ret;
400
401         bch2_trans_init(&trans, c, 0, 0);
402
403         __for_each_btree_node(&trans, iter, btree_id, start, 0, level, 0, b, ret) {
404                 if (bkey_cmp(b->key.k.p, end) > 0)
405                         break;
406
407                 bch2_btree_node_to_text(&PBUF(buf), c, b);
408                 fputs(buf, stdout);
409
410                 for_each_btree_node_key_unpack(b, k, &node_iter, &unpacked) {
411                         bch2_bkey_val_to_text(&PBUF(buf), c, k);
412                         putchar('\t');
413                         puts(buf);
414                 }
415         }
416         bch2_trans_iter_exit(&trans, &iter);
417
418         if (ret)
419                 die("error %s walking btree nodes", strerror(-ret));
420
421         bch2_trans_exit(&trans);
422 }
423
424 static void list_keys_usage(void)
425 {
426         puts("bcachefs list - list filesystem metadata to stdout\n"
427              "Usage: bcachefs list [OPTION]... <devices>\n"
428              "\n"
429              "Options:\n"
430              "  -b (extents|inodes|dirents|xattrs)    Btree to list from\n"
431              "  -l level                              Btree depth to descend to (0 == leaves)\n"
432              "  -s inode:offset                       Start position to list from\n"
433              "  -e inode:offset                       End position\n"
434              "  -i inode                              List keys for a given inode number\n"
435              "  -m (keys|formats|nodes|nodes_ondisk|nodes_keys)\n"
436              "                                        List mode\n"
437              "  -f                                    Check (fsck) the filesystem first\n"
438              "  -v                                    Verbose mode\n"
439              "  -h                                    Display this help and exit\n"
440              "Report bugs to <linux-bcache@vger.kernel.org>");
441 }
442
443 #define LIST_MODES()            \
444         x(keys)                 \
445         x(formats)              \
446         x(nodes)                \
447         x(nodes_ondisk)         \
448         x(nodes_keys)
449
450 enum list_modes {
451 #define x(n)    LIST_MODE_##n,
452         LIST_MODES()
453 #undef x
454 };
455
456 static const char * const list_modes[] = {
457 #define x(n)    #n,
458         LIST_MODES()
459 #undef x
460         NULL
461 };
462
463 int cmd_list(int argc, char *argv[])
464 {
465         struct bch_opts opts = bch2_opts_empty();
466         enum btree_id btree_id_start    = 0;
467         enum btree_id btree_id_end      = BTREE_ID_NR;
468         enum btree_id btree_id;
469         unsigned level = 0;
470         struct bpos start = POS_MIN, end = POS_MAX;
471         u64 inum = 0;
472         int mode = 0, opt;
473
474         opt_set(opts, nochanges,        true);
475         opt_set(opts, norecovery,       true);
476         opt_set(opts, degraded,         true);
477         opt_set(opts, errors,           BCH_ON_ERROR_continue);
478
479         while ((opt = getopt(argc, argv, "b:l:s:e:i:m:fvh")) != -1)
480                 switch (opt) {
481                 case 'b':
482                         btree_id_start = read_string_list_or_die(optarg,
483                                                 bch2_btree_ids, "btree id");
484                         btree_id_end = btree_id_start + 1;
485                         break;
486                 case 'l':
487                         if (kstrtouint(optarg, 10, &level) || level >= BTREE_MAX_DEPTH)
488                                 die("invalid level");
489                         break;
490                 case 's':
491                         start   = bpos_parse(optarg);
492                         break;
493                 case 'e':
494                         end     = bpos_parse(optarg);
495                         break;
496                 case 'i':
497                         if (kstrtoull(optarg, 10, &inum))
498                                 die("invalid inode %s", optarg);
499                         start   = POS(inum, 0);
500                         end     = POS(inum + 1, 0);
501                         break;
502                 case 'm':
503                         mode = read_string_list_or_die(optarg,
504                                                 list_modes, "list mode");
505                         break;
506                 case 'f':
507                         opt_set(opts, fix_errors, FSCK_OPT_YES);
508                         opt_set(opts, norecovery, false);
509                         break;
510                 case 'v':
511                         opt_set(opts, verbose, true);
512                         break;
513                 case 'h':
514                         list_keys_usage();
515                         exit(EXIT_SUCCESS);
516                 }
517         args_shift(optind);
518
519         if (!argc)
520                 die("Please supply device(s)");
521
522         struct bch_fs *c = bch2_fs_open(argv, argc, opts);
523         if (IS_ERR(c))
524                 die("error opening %s: %s", argv[0], strerror(-PTR_ERR(c)));
525
526
527         for (btree_id = btree_id_start;
528              btree_id < btree_id_end;
529              btree_id++) {
530                 switch (mode) {
531                 case LIST_MODE_keys:
532                         list_keys(c, btree_id, start, end);
533                         break;
534                 case LIST_MODE_formats:
535                         list_btree_formats(c, btree_id, level, start, end);
536                         break;
537                 case LIST_MODE_nodes:
538                         list_nodes(c, btree_id, level, start, end);
539                         break;
540                 case LIST_MODE_nodes_ondisk:
541                         list_nodes_ondisk(c, btree_id, level, start, end);
542                         break;
543                 case LIST_MODE_nodes_keys:
544                         list_nodes_keys(c, btree_id, level, start, end);
545                         break;
546                 default:
547                         die("Invalid mode");
548                 }
549         }
550
551         bch2_fs_stop(c);
552         return 0;
553 }
554
555 static void list_journal_usage(void)
556 {
557         puts("bcachefs list_journal - print contents of journal\n"
558              "Usage: bcachefs list_journal [OPTION]... <devices>\n"
559              "\n"
560              "Options:\n"
561              "  -a            Read entire journal, not just dirty entries\n"
562              "  -h            Display this help and exit\n"
563              "Report bugs to <linux-bcache@vger.kernel.org>");
564 }
565
566 int cmd_list_journal(int argc, char *argv[])
567 {
568         struct bch_opts opts = bch2_opts_empty();
569         int opt;
570
571         opt_set(opts, nochanges,        true);
572         opt_set(opts, norecovery,       true);
573         opt_set(opts, degraded,         true);
574         opt_set(opts, errors,           BCH_ON_ERROR_continue);
575         opt_set(opts, fix_errors,       FSCK_OPT_YES);
576         opt_set(opts, keep_journal,     true);
577
578         while ((opt = getopt(argc, argv, "ah")) != -1)
579                 switch (opt) {
580                 case 'a':
581                         opt_set(opts, read_entire_journal, true);
582                         break;
583                 case 'h':
584                         list_journal_usage();
585                         exit(EXIT_SUCCESS);
586                 }
587         args_shift(optind);
588
589         if (!argc)
590                 die("Please supply device(s) to open");
591
592         struct bch_fs *c = bch2_fs_open(argv, argc, opts);
593         if (IS_ERR(c))
594                 die("error opening %s: %s", argv[0], strerror(-PTR_ERR(c)));
595
596         struct journal_replay *p;
597         struct jset_entry *entry;
598         struct bkey_i *k, *_n;
599
600         /* This could be greatly expanded: */
601
602         list_for_each_entry(p, &c->journal_entries, list) {
603                 printf("journal entry   %8llu\n"
604                        "    version     %8u\n"
605                        "    last seq    %8llu\n"
606                        ,
607                        le64_to_cpu(p->j.seq),
608                        le32_to_cpu(p->j.version),
609                        le64_to_cpu(p->j.last_seq));
610
611                 for_each_jset_key(k, _n, entry, &p->j) {
612                         char buf[200];
613
614                         bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(k));
615                         printf("btree %s l %u: %s\n",
616                                bch2_btree_ids[entry->btree_id],
617                                entry->level,
618                                buf);
619                 }
620         }
621
622         bch2_fs_stop(c);
623         return 0;
624 }