Commit 1465af12 authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba

btrfs: tree-checker: fix false alert caused by legacy btrfs root item

Commit 259ee775 ("btrfs: tree-checker: Add ROOT_ITEM check")
introduced btrfs root item size check, however btrfs root item has two
versions, the legacy one which just ends before generation_v2 member, is
smaller than current btrfs root item size.

This caused btrfs kernel to reject valid but old tree root leaves.

Fix this problem by also allowing legacy root item, since kernel can
already handle them pretty well and upgrade to newer root item format
when needed.
Reported-by: default avatarMartin Steigerwald <martin@lichtvoll.de>
Fixes: 259ee775 ("btrfs: tree-checker: Add ROOT_ITEM check")
CC: stable@vger.kernel.org # 5.4+
Tested-By: default avatarMartin Steigerwald <martin@lichtvoll.de>
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent e97659ce
...@@ -1035,7 +1035,7 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key, ...@@ -1035,7 +1035,7 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
int slot) int slot)
{ {
struct btrfs_fs_info *fs_info = leaf->fs_info; struct btrfs_fs_info *fs_info = leaf->fs_info;
struct btrfs_root_item ri; struct btrfs_root_item ri = { 0 };
const u64 valid_root_flags = BTRFS_ROOT_SUBVOL_RDONLY | const u64 valid_root_flags = BTRFS_ROOT_SUBVOL_RDONLY |
BTRFS_ROOT_SUBVOL_DEAD; BTRFS_ROOT_SUBVOL_DEAD;
int ret; int ret;
...@@ -1044,14 +1044,21 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key, ...@@ -1044,14 +1044,21 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
if (ret < 0) if (ret < 0)
return ret; return ret;
if (btrfs_item_size_nr(leaf, slot) != sizeof(ri)) { if (btrfs_item_size_nr(leaf, slot) != sizeof(ri) &&
btrfs_item_size_nr(leaf, slot) != btrfs_legacy_root_item_size()) {
generic_err(leaf, slot, generic_err(leaf, slot,
"invalid root item size, have %u expect %zu", "invalid root item size, have %u expect %zu or %u",
btrfs_item_size_nr(leaf, slot), sizeof(ri)); btrfs_item_size_nr(leaf, slot), sizeof(ri),
btrfs_legacy_root_item_size());
} }
/*
* For legacy root item, the members starting at generation_v2 will be
* all filled with 0.
* And since we allow geneartion_v2 as 0, it will still pass the check.
*/
read_extent_buffer(leaf, &ri, btrfs_item_ptr_offset(leaf, slot), read_extent_buffer(leaf, &ri, btrfs_item_ptr_offset(leaf, slot),
sizeof(ri)); btrfs_item_size_nr(leaf, slot));
/* Generation related */ /* Generation related */
if (btrfs_root_generation(&ri) > if (btrfs_root_generation(&ri) >
......
...@@ -4,6 +4,11 @@ ...@@ -4,6 +4,11 @@
#include <linux/btrfs.h> #include <linux/btrfs.h>
#include <linux/types.h> #include <linux/types.h>
#ifdef __KERNEL__
#include <linux/stddef.h>
#else
#include <stddef.h>
#endif
/* /*
* This header contains the structure definitions and constants used * This header contains the structure definitions and constants used
...@@ -644,6 +649,15 @@ struct btrfs_root_item { ...@@ -644,6 +649,15 @@ struct btrfs_root_item {
__le64 reserved[8]; /* for future */ __le64 reserved[8]; /* for future */
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
/*
* Btrfs root item used to be smaller than current size. The old format ends
* at where member generation_v2 is.
*/
static inline __u32 btrfs_legacy_root_item_size(void)
{
return offsetof(struct btrfs_root_item, generation_v2);
}
/* /*
* this is used for both forward and backward root refs * this is used for both forward and backward root refs
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment