mirror of
https://github.com/kdave/btrfs-progs
synced 2025-02-25 14:30:55 +00:00
btrfs-progs: print-tree: Introduce --bfs and --dfs options
Originally print-tree uses depth first search to print trees. This works fine until we reach 3 level trees (root node level is 2). For tall trees whose root level is 2 or higher, DFS will mix nodes and leaves like the following example: Level 2 A / \ Level 1 B C / | | \ Level 0 D E F G DFS will cause the following output sequence: A B D E C F G Which in term of node/leave is: N N L L N L L Such mixed node/leave result is sometimes hard for human to read. This patch will introduce 2 new options, --bfs and --dfs. --dfs: keeps the original output sequence, and to keep things compatible it's the default behavior. --bfs: uses breadth-first search, and will cause better output sequence like: A B C D E F G Which in term of node/leave is: N N N L L L L Much better sorted and may become default in the future. Reviewed-by: Nikolay Borisov <nborisov@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
61c218756c
commit
0bbd407cbb
@ -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 '<block_num>'
|
||||
--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 <tree_id>::::
|
||||
print only the tree with the specified ID, where the ID can be numerical or
|
||||
common name in a flexible human readable form
|
||||
|
@ -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);
|
||||
|
69
print-tree.c
69
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;
|
||||
}
|
||||
|
15
print-tree.h
15
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);
|
||||
|
Loading…
Reference in New Issue
Block a user