btrfs-progs: inspect-dump-tree: Allow --block to be specified multiple times
Reuse extent-cache facility to record multiple bytenr so --block can be specified multiple times. Despite that, add a sector size alignment check before we try to print a tree block. Please note that, nodesize alignment check is not suitable here as meta chunk start bytenr could be unaligned to nodesize. 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
7a12d8470e
commit
f312aff23f
2 changed files with 91 additions and 20 deletions
|
@ -86,7 +86,7 @@ the respective tree root block offset
|
|||
-u|--uuid::::
|
||||
print only the uuid tree information, empty output if the tree does not exist
|
||||
-b <block_num>::::
|
||||
print info of the specified block only
|
||||
print info of the specified block only, can be specified multiple times
|
||||
--follow::::
|
||||
use with '-b', print all children tree blocks of '<block_num>'
|
||||
--dfs::::
|
||||
|
|
|
@ -198,11 +198,92 @@ const char * const cmd_inspect_dump_tree_usage[] = {
|
|||
"-R|--backups same as --roots plus print backup root info",
|
||||
"-u|--uuid print only the uuid tree",
|
||||
"-b|--block <block_num> print info from the specified block only",
|
||||
" can be specified multiple times",
|
||||
"-t|--tree <tree_id> print only tree with the given id (string or number)",
|
||||
"--follow use with -b, to show all children tree blocks of <block_num>",
|
||||
NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper function to record all tree block bytenr so we don't need to put
|
||||
* all code into deep indent.
|
||||
*
|
||||
* Return >0 if we hit a duplicated bytenr (already recorded)
|
||||
* Return 0 if nothing went wrong
|
||||
* Return <0 if error happens (ENOMEM)
|
||||
*
|
||||
* For != 0 return value, all warning/error will be outputted by this function.
|
||||
*/
|
||||
static int dump_add_tree_block(struct cache_tree *tree, u64 bytenr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We don't really care about the size and we don't have
|
||||
* nodesize before we open the fs, so just use 1 as size here.
|
||||
*/
|
||||
ret = add_cache_extent(tree, bytenr, 1);
|
||||
if (ret == -EEXIST) {
|
||||
warning("tree block bytenr %llu is duplicated", bytenr);
|
||||
return 1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
error("failed to record tree block bytenr %llu: %d(%s)",
|
||||
bytenr, ret, strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print all tree blocks recorded.
|
||||
* All tree block bytenr record will also be freed in this function.
|
||||
*
|
||||
* Return 0 if nothing wrong happened for *each* tree blocks
|
||||
* Return <0 if anything wrong happened, and return value will be the last
|
||||
* error.
|
||||
*/
|
||||
static int dump_print_tree_blocks(struct btrfs_fs_info *fs_info,
|
||||
struct cache_tree *tree, bool follow)
|
||||
{
|
||||
struct cache_extent *ce;
|
||||
struct extent_buffer *eb;
|
||||
u64 bytenr;
|
||||
int ret = 0;
|
||||
|
||||
ce = first_cache_extent(tree);
|
||||
while (ce) {
|
||||
bytenr = ce->start;
|
||||
|
||||
/*
|
||||
* Please note that here we can't check it against nodesize,
|
||||
* as it's possible a chunk is just aligned to sectorsize but
|
||||
* not aligned to nodesize.
|
||||
*/
|
||||
if (!IS_ALIGNED(bytenr, fs_info->sectorsize)) {
|
||||
error(
|
||||
"tree block bytenr %llu is not aligned to sectorsize %u",
|
||||
bytenr, fs_info->sectorsize);
|
||||
ret = -EINVAL;
|
||||
goto next;
|
||||
}
|
||||
|
||||
eb = read_tree_block(fs_info, bytenr, 0);
|
||||
if (!extent_buffer_uptodate(eb)) {
|
||||
error("failed to read tree block %llu", bytenr);
|
||||
ret = -EIO;
|
||||
goto next;
|
||||
}
|
||||
btrfs_print_tree(eb, follow, BTRFS_PRINT_TREE_DEFAULT);
|
||||
free_extent_buffer(eb);
|
||||
next:
|
||||
remove_cache_extent(tree, ce);
|
||||
free(ce);
|
||||
ce = first_cache_extent(tree);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_inspect_dump_tree(int argc, char **argv)
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
|
@ -213,6 +294,7 @@ int cmd_inspect_dump_tree(int argc, char **argv)
|
|||
struct extent_buffer *leaf;
|
||||
struct btrfs_disk_key disk_key;
|
||||
struct btrfs_key found_key;
|
||||
struct cache_tree block_root; /* for multiple --block parameters */
|
||||
char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
|
||||
int ret;
|
||||
int slot;
|
||||
|
@ -223,7 +305,7 @@ int cmd_inspect_dump_tree(int argc, char **argv)
|
|||
int root_backups = 0;
|
||||
int traverse = BTRFS_PRINT_TREE_DEFAULT;
|
||||
unsigned open_ctree_flags;
|
||||
u64 block_only = 0;
|
||||
u64 block_bytenr;
|
||||
struct btrfs_root *tree_root_scan;
|
||||
u64 tree_id = 0;
|
||||
bool follow = false;
|
||||
|
@ -236,6 +318,7 @@ int cmd_inspect_dump_tree(int argc, char **argv)
|
|||
* tree blocks as possible.
|
||||
*/
|
||||
open_ctree_flags = OPEN_CTREE_PARTIAL | OPEN_CTREE_NO_BLOCK_GROUPS;
|
||||
cache_tree_init(&block_root);
|
||||
optind = 0;
|
||||
while (1) {
|
||||
int c;
|
||||
|
@ -281,7 +364,10 @@ int cmd_inspect_dump_tree(int argc, char **argv)
|
|||
* other than chunk root
|
||||
*/
|
||||
open_ctree_flags |= __OPEN_CTREE_RETURN_CHUNK_ROOT;
|
||||
block_only = arg_strtou64(optarg);
|
||||
block_bytenr = arg_strtou64(optarg);
|
||||
ret = dump_add_tree_block(&block_root, block_bytenr);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
break;
|
||||
case 't': {
|
||||
const char *end = NULL;
|
||||
|
@ -341,24 +427,9 @@ int cmd_inspect_dump_tree(int argc, char **argv)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (block_only) {
|
||||
if (!cache_tree_empty(&block_root)) {
|
||||
root = info->chunk_root;
|
||||
leaf = read_tree_block(info, block_only, 0);
|
||||
if (extent_buffer_uptodate(leaf) &&
|
||||
btrfs_header_level(leaf) != 0) {
|
||||
free_extent_buffer(leaf);
|
||||
leaf = NULL;
|
||||
}
|
||||
|
||||
if (!leaf)
|
||||
leaf = read_tree_block(info, block_only, 0);
|
||||
if (!extent_buffer_uptodate(leaf)) {
|
||||
error("failed to read %llu",
|
||||
(unsigned long long)block_only);
|
||||
goto close_root;
|
||||
}
|
||||
btrfs_print_tree(leaf, follow, BTRFS_PRINT_TREE_DEFAULT);
|
||||
free_extent_buffer(leaf);
|
||||
ret = dump_print_tree_blocks(info, &block_root, follow);
|
||||
goto close_root;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue