diff --git a/Documentation/btrfs-inspect-internal.asciidoc b/Documentation/btrfs-inspect-internal.asciidoc index e2db6466..381497d2 100644 --- a/Documentation/btrfs-inspect-internal.asciidoc +++ b/Documentation/btrfs-inspect-internal.asciidoc @@ -89,6 +89,12 @@ print only the uuid tree information, empty output if the tree does not exist print info of the specified block only --follow:::: use with '-b', print all children tree blocks of '' +--dfs:::: +use depth-first search to print trees. (default) the nodes and leaves are +intermixed in the output +--bfs:::: +use breadth-first search to print trees. the nodes are printed before all +leaves -t :::: print only the tree with the specified ID, where the ID can be numerical or common name in a flexible human readable form diff --git a/cmds-inspect-dump-tree.c b/cmds-inspect-dump-tree.c index 563b4e37..1f217a9d 100644 --- a/cmds-inspect-dump-tree.c +++ b/cmds-inspect-dump-tree.c @@ -221,6 +221,7 @@ int cmd_inspect_dump_tree(int argc, char **argv) int uuid_tree_only = 0; int roots_only = 0; int root_backups = 0; + int traverse = BTRFS_PRINT_TREE_DEFAULT; unsigned open_ctree_flags; u64 block_only = 0; struct btrfs_root *tree_root_scan; @@ -238,7 +239,8 @@ int cmd_inspect_dump_tree(int argc, char **argv) optind = 0; while (1) { int c; - enum { GETOPT_VAL_FOLLOW = 256 }; + enum { GETOPT_VAL_FOLLOW = 256, GETOPT_VAL_DFS, + GETOPT_VAL_BFS }; static const struct option long_options[] = { { "extents", no_argument, NULL, 'e'}, { "device", no_argument, NULL, 'd'}, @@ -248,6 +250,8 @@ int cmd_inspect_dump_tree(int argc, char **argv) { "block", required_argument, NULL, 'b'}, { "tree", required_argument, NULL, 't'}, { "follow", no_argument, NULL, GETOPT_VAL_FOLLOW }, + { "bfs", no_argument, NULL, GETOPT_VAL_BFS }, + { "dfs", no_argument, NULL, GETOPT_VAL_DFS }, { NULL, 0, NULL, 0 } }; @@ -303,6 +307,12 @@ int cmd_inspect_dump_tree(int argc, char **argv) case GETOPT_VAL_FOLLOW: follow = true; break; + case GETOPT_VAL_DFS: + traverse = BTRFS_PRINT_TREE_DFS; + break; + case GETOPT_VAL_BFS: + traverse = BTRFS_PRINT_TREE_BFS; + break; default: usage(cmd_inspect_dump_tree_usage); } @@ -347,7 +357,7 @@ int cmd_inspect_dump_tree(int argc, char **argv) (unsigned long long)block_only); goto close_root; } - btrfs_print_tree(leaf, follow); + btrfs_print_tree(leaf, follow, BTRFS_PRINT_TREE_DEFAULT); free_extent_buffer(leaf); goto close_root; } @@ -374,17 +384,20 @@ int cmd_inspect_dump_tree(int argc, char **argv) } else { if (info->tree_root->node) { printf("root tree\n"); - btrfs_print_tree(info->tree_root->node, 1); + btrfs_print_tree(info->tree_root->node, 1, + traverse); } if (info->chunk_root->node) { printf("chunk tree\n"); - btrfs_print_tree(info->chunk_root->node, 1); + btrfs_print_tree(info->chunk_root->node, 1, + traverse); } if (info->log_root_tree) { printf("log root tree\n"); - btrfs_print_tree(info->log_root_tree->node, 1); + btrfs_print_tree(info->log_root_tree->node, 1, + traverse); } } } @@ -404,7 +417,7 @@ again: goto close_root; } printf("root tree\n"); - btrfs_print_tree(info->tree_root->node, 1); + btrfs_print_tree(info->tree_root->node, 1, traverse); goto close_root; } @@ -414,7 +427,7 @@ again: goto close_root; } printf("chunk tree\n"); - btrfs_print_tree(info->chunk_root->node, 1); + btrfs_print_tree(info->chunk_root->node, 1, traverse); goto close_root; } @@ -424,7 +437,7 @@ again: goto close_root; } printf("log root tree\n"); - btrfs_print_tree(info->log_root_tree->node, 1); + btrfs_print_tree(info->log_root_tree->node, 1, traverse); goto close_root; } @@ -570,7 +583,7 @@ again: btrfs_header_level(buf)); } else { printf(" \n"); - btrfs_print_tree(buf, 1); + btrfs_print_tree(buf, 1, traverse); } } free_extent_buffer(buf); diff --git a/print-tree.c b/print-tree.c index 8560d12a..bc05d591 100644 --- a/print-tree.c +++ b/print-tree.c @@ -1438,7 +1438,8 @@ static void bfs_print_children(struct extent_buffer *root_eb) /* Print all sibling tree blocks */ while (1) { - btrfs_print_tree(path.nodes[cur_level], 0); + btrfs_print_tree(path.nodes[cur_level], 0, + BTRFS_PRINT_TREE_BFS); ret = btrfs_next_sibling_tree_block(fs_info, &path); if (ret < 0) goto out; @@ -1453,7 +1454,38 @@ out: return; } -void btrfs_print_tree(struct extent_buffer *eb, int follow) +static void dfs_print_children(struct extent_buffer *root_eb) +{ + struct btrfs_fs_info *fs_info = root_eb->fs_info; + struct extent_buffer *next; + int nr = btrfs_header_nritems(root_eb); + int root_eb_level = btrfs_header_level(root_eb); + int i; + + for (i = 0; i < nr; i++) { + next = read_tree_block(fs_info, btrfs_node_blockptr(root_eb, i), + btrfs_node_ptr_generation(root_eb, i)); + if (!extent_buffer_uptodate(next)) { + fprintf(stderr, "failed to read %llu in tree %llu\n", + btrfs_node_blockptr(root_eb, i), + btrfs_header_owner(root_eb)); + continue; + } + if (btrfs_header_level(next) != root_eb_level - 1) { + warning( +"eb corrupted: parent bytenr %llu slot %d level %d child bytenr %llu level has %d expect %d, skipping the slot", + btrfs_header_bytenr(root_eb), i, root_eb_level, + btrfs_header_bytenr(next), + btrfs_header_level(next), root_eb_level - 1); + free_extent_buffer(next); + continue; + } + btrfs_print_tree(next, 1, BTRFS_PRINT_TREE_DFS); + free_extent_buffer(next); + } +} + +void btrfs_print_tree(struct extent_buffer *eb, int follow, int traverse) { u32 i; u32 nr; @@ -1461,10 +1493,12 @@ void btrfs_print_tree(struct extent_buffer *eb, int follow) struct btrfs_fs_info *fs_info = eb->fs_info; struct btrfs_disk_key disk_key; struct btrfs_key key; - struct extent_buffer *next; if (!eb) return; + if (traverse != BTRFS_PRINT_TREE_DFS && traverse != BTRFS_PRINT_TREE_BFS) + traverse = BTRFS_PRINT_TREE_DEFAULT; + nr = btrfs_header_nritems(eb); if (btrfs_is_leaf(eb)) { btrfs_print_leaf(eb); @@ -1503,30 +1537,9 @@ void btrfs_print_tree(struct extent_buffer *eb, int follow) if (follow && !fs_info) return; - for (i = 0; i < nr; i++) { - next = read_tree_block(fs_info, - btrfs_node_blockptr(eb, i), - btrfs_node_ptr_generation(eb, i)); - if (!extent_buffer_uptodate(next)) { - fprintf(stderr, "failed to read %llu in tree %llu\n", - (unsigned long long)btrfs_node_blockptr(eb, i), - (unsigned long long)btrfs_header_owner(eb)); - continue; - } - if (btrfs_header_level(next) != btrfs_header_level(eb) - 1) { - warning( -"eb corrupted: parent bytenr %llu slot %d level %d child bytenr %llu level has %d expect %d, skipping the slot", - btrfs_header_bytenr(eb), i, - btrfs_header_level(eb), - btrfs_header_bytenr(next), - btrfs_header_level(next), - btrfs_header_level(eb) - 1); - free_extent_buffer(next); - continue; - } - btrfs_print_tree(next, 1); - free_extent_buffer(next); - } - + if (traverse == BTRFS_PRINT_TREE_DFS) + dfs_print_children(eb); + else + bfs_print_children(eb); return; } diff --git a/print-tree.h b/print-tree.h index 62667d7f..9e041a34 100644 --- a/print-tree.h +++ b/print-tree.h @@ -20,7 +20,20 @@ #define __PRINT_TREE_H__ void btrfs_print_leaf(struct extent_buffer *l); -void btrfs_print_tree(struct extent_buffer *t, int follow); + +/* + * Print a tree block (applies to both node and leaf). + * + * @eb: Tree block + * @follow: Set non-zero to print all its children. + * @traverse: The traverse order. Support DFS and BFS. + * Will fallback to DFS for unknown order. + */ +#define BTRFS_PRINT_TREE_DFS 0 +#define BTRFS_PRINT_TREE_BFS 1 +#define BTRFS_PRINT_TREE_DEFAULT BTRFS_PRINT_TREE_DFS +void btrfs_print_tree(struct extent_buffer *eb, int follow, int traverse); + void btrfs_print_key(struct btrfs_disk_key *disk_key); void print_chunk_item(struct extent_buffer *eb, struct btrfs_chunk *chunk); void print_extent_item(struct extent_buffer *eb, int slot, int metadata);