mirror of
https://github.com/kdave/btrfs-progs
synced 2025-04-11 03:31:17 +00:00
btrfs-progs: backport btrfs_check_node() from kernel
The btrfs_check_node() has far less meaningful error message compared to kernel counterpart, and it even lacks certain checks like level check. Backport btrfs_check_node() to btrfs-progs to not only unify the code but greatly improve the readability of the error messages. Extra modification includes: - No fs_info needed As we don't need to output fsid. - Remove unlikely() macro - Extra BTRFS_TREE_BLOCK_* error type - Btrfs-progs specific error handling To record the corrupted tree blocks. Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
8f8cafa2ce
commit
9a11b1b792
@ -583,41 +583,71 @@ static void generic_err(const struct extent_buffer *buf, int slot,
|
||||
|
||||
enum btrfs_tree_block_status
|
||||
btrfs_check_node(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_key *parent_key, struct extent_buffer *buf)
|
||||
struct btrfs_key *parent_key, struct extent_buffer *node)
|
||||
{
|
||||
int i;
|
||||
struct btrfs_key key;
|
||||
u32 nritems = btrfs_header_nritems(buf);
|
||||
unsigned long nr = btrfs_header_nritems(node);
|
||||
struct btrfs_key key, next_key;
|
||||
int slot;
|
||||
int level = btrfs_header_level(node);
|
||||
u64 bytenr;
|
||||
enum btrfs_tree_block_status ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS;
|
||||
|
||||
if (nritems == 0 || nritems > BTRFS_NODEPTRS_PER_BLOCK(fs_info))
|
||||
if (level <= 0 || level >= BTRFS_MAX_LEVEL) {
|
||||
generic_err(node, 0,
|
||||
"invalid level for node, have %d expect [1, %d]",
|
||||
level, BTRFS_MAX_LEVEL - 1);
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_LEVEL;
|
||||
goto fail;
|
||||
}
|
||||
if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(fs_info)) {
|
||||
generic_err(node, 0,
|
||||
"corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]",
|
||||
btrfs_header_owner(node), node->start,
|
||||
nr == 0 ? "small" : "large", nr,
|
||||
BTRFS_NODEPTRS_PER_BLOCK(fs_info));
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS;
|
||||
goto fail;
|
||||
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_PARENT_KEY;
|
||||
if (parent_key && parent_key->type) {
|
||||
btrfs_node_key_to_cpu(buf, &key, 0);
|
||||
if (memcmp(parent_key, &key, sizeof(key)))
|
||||
goto fail;
|
||||
}
|
||||
ret = BTRFS_TREE_BLOCK_BAD_KEY_ORDER;
|
||||
for (i = 0; nritems > 1 && i < nritems - 2; i++) {
|
||||
struct btrfs_key next_key;
|
||||
|
||||
btrfs_node_key_to_cpu(buf, &key, i);
|
||||
btrfs_node_key_to_cpu(buf, &next_key, i + 1);
|
||||
if (btrfs_comp_cpu_keys(&key, &next_key) >= 0)
|
||||
for (slot = 0; slot < nr - 1; slot++) {
|
||||
bytenr = btrfs_node_blockptr(node, slot);
|
||||
btrfs_node_key_to_cpu(node, &key, slot);
|
||||
btrfs_node_key_to_cpu(node, &next_key, slot + 1);
|
||||
|
||||
if (!bytenr) {
|
||||
generic_err(node, slot,
|
||||
"invalid NULL node pointer");
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_BLOCKPTR;
|
||||
goto fail;
|
||||
}
|
||||
if (!IS_ALIGNED(bytenr, fs_info->sectorsize)) {
|
||||
generic_err(node, slot,
|
||||
"unaligned pointer, have %llu should be aligned to %u",
|
||||
bytenr, fs_info->sectorsize);
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_BLOCKPTR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
|
||||
generic_err(node, slot,
|
||||
"bad key order, current (%llu %u %llu) next (%llu %u %llu)",
|
||||
key.objectid, key.type, key.offset,
|
||||
next_key.objectid, next_key.type,
|
||||
next_key.offset);
|
||||
ret = BTRFS_TREE_BLOCK_BAD_KEY_ORDER;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return BTRFS_TREE_BLOCK_CLEAN;
|
||||
fail:
|
||||
if (btrfs_header_owner(buf) == BTRFS_EXTENT_TREE_OBJECTID) {
|
||||
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(buf, &key, 0);
|
||||
btrfs_node_key_to_cpu(node, &key, 0);
|
||||
btrfs_add_corrupt_extent_record(fs_info, &key,
|
||||
buf->start, buf->len,
|
||||
btrfs_header_level(buf));
|
||||
node->start, node->len,
|
||||
btrfs_header_level(node));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -698,6 +698,7 @@ enum btrfs_tree_block_status {
|
||||
BTRFS_TREE_BLOCK_INVALID_LEVEL,
|
||||
BTRFS_TREE_BLOCK_INVALID_FREE_SPACE,
|
||||
BTRFS_TREE_BLOCK_INVALID_OFFSETS,
|
||||
BTRFS_TREE_BLOCK_INVALID_BLOCKPTR,
|
||||
};
|
||||
|
||||
struct btrfs_inode_item {
|
||||
|
Loading…
Reference in New Issue
Block a user