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