btrfs-progs: add a btrfs check helper for checking blocks

btrfs check wants to be able to record corrupted extents if it finds any
bad blocks.  This has been done directly inside of the
btrfs_check_leaf/btrfs_check_node helpers, but these are going to be
sync'ed from the kernel in the future.  Add another helper and move the
corrupt block handling into this helper and keep it inside of the check
code.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Josef Bacik 2023-04-19 17:13:52 -04:00 committed by David Sterba
parent d36571ed9a
commit 90e687d90c
5 changed files with 39 additions and 40 deletions

View File

@ -1920,10 +1920,7 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
goto out;
}
if (btrfs_is_leaf(next))
status = btrfs_check_leaf(NULL, next);
else
status = btrfs_check_node(NULL, next);
status = btrfs_check_block_for_repair(next, NULL);
if (status != BTRFS_TREE_BLOCK_CLEAN) {
free_extent_buffer(next);
err = -EIO;
@ -3701,10 +3698,7 @@ static int check_fs_root(struct btrfs_root *root,
wc->root_level = level;
/* We may not have checked the root block, lets do that now */
if (btrfs_is_leaf(root->node))
status = btrfs_check_leaf(NULL, root->node);
else
status = btrfs_check_node(NULL, root->node);
status = btrfs_check_block_for_repair(root->node, NULL);
if (status != BTRFS_TREE_BLOCK_CLEAN)
return -EIO;
@ -4607,11 +4601,7 @@ static int check_block(struct btrfs_root *root,
}
rec->info_level = level;
if (btrfs_is_leaf(buf))
status = btrfs_check_leaf(&rec->parent_key, buf);
else
status = btrfs_check_node(&rec->parent_key, buf);
status = btrfs_check_block_for_repair(buf, &rec->parent_key);
if (status != BTRFS_TREE_BLOCK_CLEAN) {
if (opt_check_repair)
status = try_to_fix_bad_block(root, buf, status);

View File

@ -2695,7 +2695,7 @@ static int check_inode_item(struct btrfs_root *root, struct btrfs_path *path)
* we need to bail otherwise we could end up stuck.
*/
if (path->slots[0] == 0 &&
btrfs_check_leaf(NULL, path->nodes[0]))
btrfs_check_block_for_repair(path->nodes[0], NULL))
ret = -EIO;
if (ret < 0) {
@ -5001,7 +5001,7 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
if (*level == 0) {
/* skip duplicate check */
if (check || !check_all) {
ret = btrfs_check_leaf(NULL, cur);
ret = btrfs_check_block_for_repair(cur, NULL);
if (ret != BTRFS_TREE_BLOCK_CLEAN) {
err |= -EIO;
break;
@ -5018,7 +5018,7 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
break;
}
if (check || !check_all) {
ret = btrfs_check_node(NULL, cur);
ret = btrfs_check_block_for_repair(cur, NULL);
if (ret != BTRFS_TREE_BLOCK_CLEAN) {
err |= -EIO;
break;
@ -5065,10 +5065,7 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
if (ret < 0)
break;
if (btrfs_is_leaf(next))
status = btrfs_check_leaf(NULL, next);
else
status = btrfs_check_node(NULL, next);
status = btrfs_check_block_for_repair(next, NULL);
if (status != BTRFS_TREE_BLOCK_CLEAN) {
free_extent_buffer(next);
err |= -EIO;

View File

@ -299,3 +299,31 @@ out:
extent_io_tree_cleanup(&used);
return ret;
}
enum btrfs_tree_block_status btrfs_check_block_for_repair(struct extent_buffer *eb,
struct btrfs_key *first_key)
{
struct btrfs_fs_info *fs_info = eb->fs_info;
enum btrfs_tree_block_status status;
if (btrfs_is_leaf(eb))
status = btrfs_check_leaf(first_key, eb);
else
status = btrfs_check_node(first_key, eb);
if (status == BTRFS_TREE_BLOCK_CLEAN)
return status;
if (btrfs_header_owner(eb) == BTRFS_EXTENT_TREE_OBJECTID) {
struct btrfs_key key;
if (first_key)
memcpy(&key, first_key, sizeof(struct btrfs_key));
else
btrfs_node_key_to_cpu(eb, &key, 0);
btrfs_add_corrupt_extent_record(fs_info, &key,
eb->start, eb->len,
btrfs_header_level(eb));
}
return status;
}

View File

@ -43,5 +43,7 @@ int btrfs_mark_used_tree_blocks(struct btrfs_fs_info *fs_info,
struct extent_io_tree *tree);
int btrfs_mark_used_blocks(struct btrfs_fs_info *fs_info,
struct extent_io_tree *tree);
enum btrfs_tree_block_status btrfs_check_block_for_repair(struct extent_buffer *eb,
struct btrfs_key *first_key);
#endif

View File

@ -668,17 +668,8 @@ btrfs_check_node(struct btrfs_key *parent_key, struct extent_buffer *node)
goto fail;
}
}
return BTRFS_TREE_BLOCK_CLEAN;
ret = BTRFS_TREE_BLOCK_CLEAN;
fail:
if (btrfs_header_owner(node) == BTRFS_EXTENT_TREE_OBJECTID) {
if (parent_key)
memcpy(&key, parent_key, sizeof(struct btrfs_key));
else
btrfs_node_key_to_cpu(node, &key, 0);
btrfs_add_corrupt_extent_record(fs_info, &key,
node->start, node->len,
btrfs_header_level(node));
}
return ret;
}
@ -782,17 +773,8 @@ btrfs_check_leaf(struct btrfs_key *parent_key, struct extent_buffer *leaf)
prev_key.offset = key.offset;
}
return BTRFS_TREE_BLOCK_CLEAN;
ret = BTRFS_TREE_BLOCK_CLEAN;
fail:
if (btrfs_header_owner(leaf) == BTRFS_EXTENT_TREE_OBJECTID) {
if (parent_key)
memcpy(&key, parent_key, sizeof(struct btrfs_key));
else
btrfs_item_key_to_cpu(leaf, &key, 0);
btrfs_add_corrupt_extent_record(fs_info, &key,
leaf->start, leaf->len, 0);
}
return ret;
}