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