mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 22:51:42 +00:00
Btrfs: improve check_node to avoid reading corrupted nodes
We need to check items in a node to make sure that we're reading a valid one, otherwise we could get various crashes while processing delayed_refs. Signed-off-by: Liu Bo <bo.li.liu@oracle.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
a42cbec9c6
commit
6b722c1747
@ -546,9 +546,10 @@ static int check_tree_block_fsid(struct btrfs_fs_info *fs_info,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define CORRUPT(reason, eb, root, slot) \
|
#define CORRUPT(reason, eb, root, slot) \
|
||||||
btrfs_crit(root->fs_info, "corrupt leaf, %s: block=%llu," \
|
btrfs_crit(root->fs_info, "corrupt %s, %s: block=%llu," \
|
||||||
"root=%llu, slot=%d", reason, \
|
" root=%llu, slot=%d", \
|
||||||
btrfs_header_bytenr(eb), root->objectid, slot)
|
btrfs_header_level(eb) == 0 ? "leaf" : "node",\
|
||||||
|
reason, btrfs_header_bytenr(eb), root->objectid, slot)
|
||||||
|
|
||||||
static noinline int check_leaf(struct btrfs_root *root,
|
static noinline int check_leaf(struct btrfs_root *root,
|
||||||
struct extent_buffer *leaf)
|
struct extent_buffer *leaf)
|
||||||
@ -635,6 +636,10 @@ static noinline int check_leaf(struct btrfs_root *root,
|
|||||||
static int check_node(struct btrfs_root *root, struct extent_buffer *node)
|
static int check_node(struct btrfs_root *root, struct extent_buffer *node)
|
||||||
{
|
{
|
||||||
unsigned long nr = btrfs_header_nritems(node);
|
unsigned long nr = btrfs_header_nritems(node);
|
||||||
|
struct btrfs_key key, next_key;
|
||||||
|
int slot;
|
||||||
|
u64 bytenr;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) {
|
if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) {
|
||||||
btrfs_crit(root->fs_info,
|
btrfs_crit(root->fs_info,
|
||||||
@ -642,7 +647,26 @@ static int check_node(struct btrfs_root *root, struct extent_buffer *node)
|
|||||||
node->start, root->objectid, nr);
|
node->start, root->objectid, nr);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
return 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) {
|
||||||
|
CORRUPT("invalid item slot", node, root, slot);
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
|
||||||
|
CORRUPT("bad key order", node, root, slot);
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
|
static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
|
||||||
|
Loading…
Reference in New Issue
Block a user