btrfs-progs: Allow inspect dump-tree to show specified tree block even some tree...
[platform/upstream/btrfs-progs.git] / cmds-inspect-dump-tree.c
1 /*
2  * Copyright (C) 2007 Oracle.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License v2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 021110-1307, USA.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <uuid/uuid.h>
23 #include <getopt.h>
24
25 #include "kerncompat.h"
26 #include "radix-tree.h"
27 #include "ctree.h"
28 #include "disk-io.h"
29 #include "print-tree.h"
30 #include "transaction.h"
31 #include "volumes.h"
32 #include "commands.h"
33 #include "utils.h"
34 #include "cmds-inspect-dump-tree.h"
35 #include "help.h"
36
37 static void print_extents(struct btrfs_root *root, struct extent_buffer *eb)
38 {
39         struct extent_buffer *next;
40         int i;
41         u32 nr;
42         u32 size;
43
44         if (!eb)
45                 return;
46
47         if (btrfs_is_leaf(eb)) {
48                 btrfs_print_leaf(root, eb);
49                 return;
50         }
51
52         size = root->fs_info->nodesize;
53         nr = btrfs_header_nritems(eb);
54         for (i = 0; i < nr; i++) {
55                 next = read_tree_block(root->fs_info,
56                                 btrfs_node_blockptr(eb, i),
57                                 size, btrfs_node_ptr_generation(eb, i));
58                 if (!extent_buffer_uptodate(next))
59                         continue;
60                 if (btrfs_is_leaf(next) && btrfs_header_level(eb) != 1) {
61                         warning(
62         "eb corrupted: item %d eb level %d next level %d, skipping the rest",
63                                 i, btrfs_header_level(next),
64                                 btrfs_header_level(eb));
65                         goto out;
66                 }
67                 if (btrfs_header_level(next) != btrfs_header_level(eb) - 1) {
68                         warning(
69         "eb corrupted: item %d eb level %d next level %d, skipping the rest",
70                                 i, btrfs_header_level(next),
71                                 btrfs_header_level(eb));
72                         goto out;
73                 }
74                 print_extents(root, next);
75                 free_extent_buffer(next);
76         }
77
78         return;
79
80 out:
81         free_extent_buffer(next);
82 }
83
84 static void print_old_roots(struct btrfs_super_block *super)
85 {
86         struct btrfs_root_backup *backup;
87         int i;
88
89         for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; i++) {
90                 backup = super->super_roots + i;
91                 printf("btrfs root backup slot %d\n", i);
92                 printf("\ttree root gen %llu block %llu\n",
93                        (unsigned long long)btrfs_backup_tree_root_gen(backup),
94                        (unsigned long long)btrfs_backup_tree_root(backup));
95
96                 printf("\t\textent root gen %llu block %llu\n",
97                        (unsigned long long)btrfs_backup_extent_root_gen(backup),
98                        (unsigned long long)btrfs_backup_extent_root(backup));
99
100                 printf("\t\tchunk root gen %llu block %llu\n",
101                        (unsigned long long)btrfs_backup_chunk_root_gen(backup),
102                        (unsigned long long)btrfs_backup_chunk_root(backup));
103
104                 printf("\t\tdevice root gen %llu block %llu\n",
105                        (unsigned long long)btrfs_backup_dev_root_gen(backup),
106                        (unsigned long long)btrfs_backup_dev_root(backup));
107
108                 printf("\t\tcsum root gen %llu block %llu\n",
109                        (unsigned long long)btrfs_backup_csum_root_gen(backup),
110                        (unsigned long long)btrfs_backup_csum_root(backup));
111
112                 printf("\t\tfs root gen %llu block %llu\n",
113                        (unsigned long long)btrfs_backup_fs_root_gen(backup),
114                        (unsigned long long)btrfs_backup_fs_root(backup));
115
116                 printf("\t\t%llu used %llu total %llu devices\n",
117                        (unsigned long long)btrfs_backup_bytes_used(backup),
118                        (unsigned long long)btrfs_backup_total_bytes(backup),
119                        (unsigned long long)btrfs_backup_num_devices(backup));
120         }
121 }
122
123 /*
124  * Convert a tree name from various forms to the numerical id if possible
125  * Accepted forms:
126  * - case does not matter
127  * - same as the key name, BTRFS_ROOT_TREE_OBJECTID
128  * - dtto shortened, BTRFS_ROOT_TREE
129  * - dtto without prefix, ROOT_TREE
130  * - common name, ROOT, CHUNK, EXTENT, ...
131  * - dtto alias, DEVICE for DEV, CHECKSUM for CSUM
132  *
133  * Returns 0 if the tree id was not recognized.
134  */
135 static u64 treeid_from_string(const char *str, const char **end)
136 {
137         int match = 0;
138         int i;
139         u64 id;
140         static struct treename {
141                 const char *name;
142                 u64 id;
143         } tn[] = {
144                 { "ROOT", BTRFS_ROOT_TREE_OBJECTID },
145                 { "EXTENT", BTRFS_EXTENT_TREE_OBJECTID },
146                 { "CHUNK", BTRFS_CHUNK_TREE_OBJECTID },
147                 { "DEVICE", BTRFS_DEV_TREE_OBJECTID },
148                 { "DEV", BTRFS_DEV_TREE_OBJECTID },
149                 { "FS_TREE", BTRFS_FS_TREE_OBJECTID },
150                 { "CSUM", BTRFS_CSUM_TREE_OBJECTID },
151                 { "CHECKSUM", BTRFS_CSUM_TREE_OBJECTID },
152                 { "QUOTA", BTRFS_QUOTA_TREE_OBJECTID },
153                 { "UUID", BTRFS_UUID_TREE_OBJECTID },
154                 { "FREE_SPACE", BTRFS_FREE_SPACE_TREE_OBJECTID },
155                 { "TREE_LOG_FIXUP", BTRFS_TREE_LOG_FIXUP_OBJECTID },
156                 { "TREE_LOG", BTRFS_TREE_LOG_OBJECTID },
157                 { "TREE_RELOC", BTRFS_TREE_RELOC_OBJECTID },
158                 { "DATA_RELOC", BTRFS_DATA_RELOC_TREE_OBJECTID }
159         };
160
161         if (strncasecmp("BTRFS_", str, strlen("BTRFS_")) == 0)
162                 str += strlen("BTRFS_");
163
164         for (i = 0; i < ARRAY_SIZE(tn); i++) {
165                 int len = strlen(tn[i].name);
166
167                 if (strncasecmp(tn[i].name, str, len) == 0) {
168                         id = tn[i].id;
169                         match = 1;
170                         str += len;
171                         break;
172                 }
173         }
174
175         if (!match)
176                 return 0;
177
178         if (strncasecmp("_TREE", str, strlen("_TREE")) == 0)
179                 str += strlen("_TREE");
180
181         if (strncasecmp("_OBJECTID", str, strlen("_OBJECTID")) == 0)
182                 str += strlen("_OBJECTID");
183
184         *end = str;
185
186         return id;
187 }
188
189 const char * const cmd_inspect_dump_tree_usage[] = {
190         "btrfs inspect-internal dump-tree [options] device",
191         "Dump tree structures from a given device",
192         "Dump tree structures from a given device in textual form, expand keys to human",
193         "readable equivalents where possible.",
194         "Note: contains file names, consider that if you're asked to send the dump",
195         "for analysis.",
196         "",
197         "-e|--extents           print only extent info: extent and device trees",
198         "-d|--device            print only device info: tree root, chunk and device trees",
199         "-r|--roots             print only short root node info",
200         "-R|--backups           same as --roots plus print backup root info",
201         "-u|--uuid              print only the uuid tree",
202         "-b|--block <block_num> print info from the specified block only",
203         "-t|--tree <tree_id>    print only tree with the given id (string or number)",
204         NULL
205 };
206
207 int cmd_inspect_dump_tree(int argc, char **argv)
208 {
209         struct btrfs_root *root;
210         struct btrfs_fs_info *info;
211         struct btrfs_path path;
212         struct btrfs_key key;
213         struct btrfs_root_item ri;
214         struct extent_buffer *leaf;
215         struct btrfs_disk_key disk_key;
216         struct btrfs_key found_key;
217         char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
218         int ret;
219         int slot;
220         int extent_only = 0;
221         int device_only = 0;
222         int uuid_tree_only = 0;
223         int roots_only = 0;
224         int root_backups = 0;
225         unsigned open_ctree_flags = OPEN_CTREE_FS_PARTIAL;
226         u64 block_only = 0;
227         struct btrfs_root *tree_root_scan;
228         u64 tree_id = 0;
229
230         while (1) {
231                 int c;
232                 static const struct option long_options[] = {
233                         { "extents", no_argument, NULL, 'e'},
234                         { "device", no_argument, NULL, 'd'},
235                         { "roots", no_argument, NULL, 'r'},
236                         { "backups", no_argument, NULL, 'R'},
237                         { "uuid", no_argument, NULL, 'u'},
238                         { "block", required_argument, NULL, 'b'},
239                         { "tree", required_argument, NULL, 't'},
240                         { NULL, 0, NULL, 0 }
241                 };
242
243                 c = getopt_long(argc, argv, "deb:rRut:", long_options, NULL);
244                 if (c < 0)
245                         break;
246                 switch (c) {
247                 case 'e':
248                         extent_only = 1;
249                         break;
250                 case 'd':
251                         device_only = 1;
252                         break;
253                 case 'r':
254                         roots_only = 1;
255                         break;
256                 case 'u':
257                         uuid_tree_only = 1;
258                         break;
259                 case 'R':
260                         roots_only = 1;
261                         root_backups = 1;
262                         break;
263                 case 'b':
264                         /*
265                          * If only showing one block, no need to fill roots
266                          * other than chunk root
267                          */
268                         open_ctree_flags |= __OPEN_CTREE_RETURN_CHUNK_ROOT;
269                         block_only = arg_strtou64(optarg);
270                         break;
271                 case 't': {
272                         const char *end = NULL;
273
274                         if (string_is_numerical(optarg))
275                                 tree_id = arg_strtou64(optarg);
276                         else
277                                 tree_id = treeid_from_string(optarg, &end);
278
279                         if (!tree_id) {
280                                 error("unrecognized tree id: %s",
281                                                 optarg);
282                                 exit(1);
283                         }
284
285                         if (end && *end) {
286                                 error("unexpected tree id suffix of '%s': %s",
287                                                 optarg, end);
288                                 exit(1);
289                         }
290                         break;
291                         }
292                 default:
293                         usage(cmd_inspect_dump_tree_usage);
294                 }
295         }
296
297         if (check_argc_exact(argc - optind, 1))
298                 usage(cmd_inspect_dump_tree_usage);
299
300         ret = check_arg_type(argv[optind]);
301         if (ret != BTRFS_ARG_BLKDEV && ret != BTRFS_ARG_REG) {
302                 error("not a block device or regular file: %s", argv[optind]);
303                 goto out;
304         }
305
306         printf("%s\n", PACKAGE_STRING);
307
308         info = open_ctree_fs_info(argv[optind], 0, 0, 0, open_ctree_flags);
309         if (!info) {
310                 error("unable to open %s", argv[optind]);
311                 goto out;
312         }
313
314         if (block_only) {
315                 root = info->chunk_root;
316                 leaf = read_tree_block(info,
317                                       block_only,
318                                       info->nodesize, 0);
319
320                 if (extent_buffer_uptodate(leaf) &&
321                     btrfs_header_level(leaf) != 0) {
322                         free_extent_buffer(leaf);
323                         leaf = NULL;
324                 }
325
326                 if (!leaf) {
327                         leaf = read_tree_block(info,
328                                               block_only,
329                                               info->nodesize, 0);
330                 }
331                 if (!extent_buffer_uptodate(leaf)) {
332                         error("failed to read %llu",
333                                 (unsigned long long)block_only);
334                         goto close_root;
335                 }
336                 btrfs_print_tree(root, leaf, 0);
337                 free_extent_buffer(leaf);
338                 goto close_root;
339         }
340
341         root = info->fs_root;
342         if (!root) {
343                 error("unable to open %s", argv[optind]);
344                 goto out;
345         }
346
347         if (!(extent_only || uuid_tree_only || tree_id)) {
348                 if (roots_only) {
349                         printf("root tree: %llu level %d\n",
350                              (unsigned long long)info->tree_root->node->start,
351                              btrfs_header_level(info->tree_root->node));
352                         printf("chunk tree: %llu level %d\n",
353                              (unsigned long long)info->chunk_root->node->start,
354                              btrfs_header_level(info->chunk_root->node));
355                         if (info->log_root_tree)
356                                 printf("log root tree: %llu level %d\n",
357                                        info->log_root_tree->node->start,
358                                         btrfs_header_level(
359                                                 info->log_root_tree->node));
360                 } else {
361                         if (info->tree_root->node) {
362                                 printf("root tree\n");
363                                 btrfs_print_tree(info->tree_root,
364                                                  info->tree_root->node, 1);
365                         }
366
367                         if (info->chunk_root->node) {
368                                 printf("chunk tree\n");
369                                 btrfs_print_tree(info->chunk_root,
370                                                  info->chunk_root->node, 1);
371                         }
372
373                         if (info->log_root_tree) {
374                                 printf("log root tree\n");
375                                 btrfs_print_tree(info->log_root_tree,
376                                                 info->log_root_tree->node, 1);
377                         }
378                 }
379         }
380         tree_root_scan = info->tree_root;
381
382         btrfs_init_path(&path);
383 again:
384         if (!extent_buffer_uptodate(tree_root_scan->node))
385                 goto no_node;
386
387         /*
388          * Tree's that are not pointed by the tree of tree roots
389          */
390         if (tree_id && tree_id == BTRFS_ROOT_TREE_OBJECTID) {
391                 if (!info->tree_root->node) {
392                         error("cannot print root tree, invalid pointer");
393                         goto close_root;
394                 }
395                 printf("root tree\n");
396                 btrfs_print_tree(info->tree_root, info->tree_root->node, 1);
397                 goto close_root;
398         }
399
400         if (tree_id && tree_id == BTRFS_CHUNK_TREE_OBJECTID) {
401                 if (!info->chunk_root->node) {
402                         error("cannot print chunk tree, invalid pointer");
403                         goto close_root;
404                 }
405                 printf("chunk tree\n");
406                 btrfs_print_tree(info->chunk_root, info->chunk_root->node, 1);
407                 goto close_root;
408         }
409
410         if (tree_id && tree_id == BTRFS_TREE_LOG_OBJECTID) {
411                 if (!info->log_root_tree) {
412                         error("cannot print log root tree, invalid pointer");
413                         goto close_root;
414                 }
415                 printf("log root tree\n");
416                 btrfs_print_tree(info->log_root_tree, info->log_root_tree->node,
417                                  1);
418                 goto close_root;
419         }
420
421         key.offset = 0;
422         key.objectid = 0;
423         key.type = BTRFS_ROOT_ITEM_KEY;
424         ret = btrfs_search_slot(NULL, tree_root_scan, &key, &path, 0, 0);
425         if (ret < 0) {
426                 error("cannot read ROOT_ITEM from tree %llu: %s",
427                         (unsigned long long)tree_root_scan->root_key.objectid,
428                         strerror(-ret));
429                 goto close_root;
430         }
431         while (1) {
432                 leaf = path.nodes[0];
433                 slot = path.slots[0];
434                 if (slot >= btrfs_header_nritems(leaf)) {
435                         ret = btrfs_next_leaf(tree_root_scan, &path);
436                         if (ret != 0)
437                                 break;
438                         leaf = path.nodes[0];
439                         slot = path.slots[0];
440                 }
441                 btrfs_item_key(leaf, &disk_key, path.slots[0]);
442                 btrfs_disk_key_to_cpu(&found_key, &disk_key);
443                 if (found_key.type == BTRFS_ROOT_ITEM_KEY) {
444                         unsigned long offset;
445                         struct extent_buffer *buf;
446                         int skip = extent_only | device_only | uuid_tree_only;
447
448                         offset = btrfs_item_ptr_offset(leaf, slot);
449                         read_extent_buffer(leaf, &ri, offset, sizeof(ri));
450                         buf = read_tree_block(info, btrfs_root_bytenr(&ri),
451                                               info->nodesize, 0);
452                         if (!extent_buffer_uptodate(buf))
453                                 goto next;
454                         if (tree_id && found_key.objectid != tree_id) {
455                                 free_extent_buffer(buf);
456                                 goto next;
457                         }
458
459                         switch (found_key.objectid) {
460                         case BTRFS_ROOT_TREE_OBJECTID:
461                                 if (!skip)
462                                         printf("root");
463                                 break;
464                         case BTRFS_EXTENT_TREE_OBJECTID:
465                                 if (!device_only && !uuid_tree_only)
466                                         skip = 0;
467                                 if (!skip)
468                                         printf("extent");
469                                 break;
470                         case BTRFS_CHUNK_TREE_OBJECTID:
471                                 if (!skip) {
472                                         printf("chunk");
473                                 }
474                                 break;
475                         case BTRFS_DEV_TREE_OBJECTID:
476                                 if (!uuid_tree_only)
477                                         skip = 0;
478                                 if (!skip)
479                                         printf("device");
480                                 break;
481                         case BTRFS_FS_TREE_OBJECTID:
482                                 if (!skip) {
483                                         printf("fs");
484                                 }
485                                 break;
486                         case BTRFS_ROOT_TREE_DIR_OBJECTID:
487                                 skip = 0;
488                                 printf("directory");
489                                 break;
490                         case BTRFS_CSUM_TREE_OBJECTID:
491                                 if (!skip) {
492                                         printf("checksum");
493                                 }
494                                 break;
495                         case BTRFS_ORPHAN_OBJECTID:
496                                 if (!skip) {
497                                         printf("orphan");
498                                 }
499                                 break;
500                         case BTRFS_TREE_LOG_OBJECTID:
501                                 if (!skip) {
502                                         printf("log");
503                                 }
504                                 break;
505                         case BTRFS_TREE_LOG_FIXUP_OBJECTID:
506                                 if (!skip) {
507                                         printf("log fixup");
508                                 }
509                                 break;
510                         case BTRFS_TREE_RELOC_OBJECTID:
511                                 if (!skip) {
512                                         printf("reloc");
513                                 }
514                                 break;
515                         case BTRFS_DATA_RELOC_TREE_OBJECTID:
516                                 if (!skip) {
517                                         printf("data reloc");
518                                 }
519                                 break;
520                         case BTRFS_EXTENT_CSUM_OBJECTID:
521                                 if (!skip) {
522                                         printf("extent checksum");
523                                 }
524                                 break;
525                         case BTRFS_QUOTA_TREE_OBJECTID:
526                                 if (!skip) {
527                                         printf("quota");
528                                 }
529                                 break;
530                         case BTRFS_UUID_TREE_OBJECTID:
531                                 if (!extent_only && !device_only)
532                                         skip = 0;
533                                 if (!skip)
534                                         printf("uuid");
535                                 break;
536                         case BTRFS_FREE_SPACE_TREE_OBJECTID:
537                                 if (!skip)
538                                         printf("free space");
539                                 break;
540                         case BTRFS_MULTIPLE_OBJECTIDS:
541                                 if (!skip) {
542                                         printf("multiple");
543                                 }
544                                 break;
545                         default:
546                                 if (!skip) {
547                                         printf("file");
548                                 }
549                         }
550                         if (extent_only && !skip) {
551                                 printf(" tree ");
552                                 btrfs_print_key(&disk_key);
553                                 printf("\n");
554                                 print_extents(tree_root_scan, buf);
555                         } else if (!skip) {
556                                 printf(" tree ");
557                                 btrfs_print_key(&disk_key);
558                                 if (roots_only) {
559                                         printf(" %llu level %d\n",
560                                                (unsigned long long)buf->start,
561                                                btrfs_header_level(buf));
562                                 } else {
563                                         printf(" \n");
564                                         btrfs_print_tree(tree_root_scan, buf, 1);
565                                 }
566                         }
567                         free_extent_buffer(buf);
568                 }
569 next:
570                 path.slots[0]++;
571         }
572 no_node:
573         btrfs_release_path(&path);
574
575         if (tree_root_scan == info->tree_root && info->log_root_tree) {
576                 tree_root_scan = info->log_root_tree;
577                 goto again;
578         }
579
580         if (extent_only || device_only || uuid_tree_only)
581                 goto close_root;
582
583         if (root_backups)
584                 print_old_roots(info->super_copy);
585
586         printf("total bytes %llu\n",
587                (unsigned long long)btrfs_super_total_bytes(info->super_copy));
588         printf("bytes used %llu\n",
589                (unsigned long long)btrfs_super_bytes_used(info->super_copy));
590         uuidbuf[BTRFS_UUID_UNPARSED_SIZE - 1] = '\0';
591         uuid_unparse(info->super_copy->fsid, uuidbuf);
592         printf("uuid %s\n", uuidbuf);
593 close_root:
594         ret = close_ctree(root);
595 out:
596         return !!ret;
597 }