Skip to content

Commit 1700e87

Browse files
adam900710gregkh
authored andcommitted
btrfs: tree-checker: fix false alert caused by legacy btrfs root item
commit 1465af1 upstream. Commit 259ee77 ("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: Martin Steigerwald <martin@lichtvoll.de> Fixes: 259ee77 ("btrfs: tree-checker: Add ROOT_ITEM check") CC: stable@vger.kernel.org # 5.4+ Tested-By: Martin Steigerwald <martin@lichtvoll.de> Reviewed-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent a3be5ff commit 1700e87

2 files changed

Lines changed: 26 additions & 5 deletions

File tree

fs/btrfs/tree-checker.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,7 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
10351035
int slot)
10361036
{
10371037
struct btrfs_fs_info *fs_info = leaf->fs_info;
1038-
struct btrfs_root_item ri;
1038+
struct btrfs_root_item ri = { 0 };
10391039
const u64 valid_root_flags = BTRFS_ROOT_SUBVOL_RDONLY |
10401040
BTRFS_ROOT_SUBVOL_DEAD;
10411041
int ret;
@@ -1044,14 +1044,21 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
10441044
if (ret < 0)
10451045
return ret;
10461046

1047-
if (btrfs_item_size_nr(leaf, slot) != sizeof(ri)) {
1047+
if (btrfs_item_size_nr(leaf, slot) != sizeof(ri) &&
1048+
btrfs_item_size_nr(leaf, slot) != btrfs_legacy_root_item_size()) {
10481049
generic_err(leaf, slot,
1049-
"invalid root item size, have %u expect %zu",
1050-
btrfs_item_size_nr(leaf, slot), sizeof(ri));
1050+
"invalid root item size, have %u expect %zu or %u",
1051+
btrfs_item_size_nr(leaf, slot), sizeof(ri),
1052+
btrfs_legacy_root_item_size());
10511053
}
10521054

1055+
/*
1056+
* For legacy root item, the members starting at generation_v2 will be
1057+
* all filled with 0.
1058+
* And since we allow geneartion_v2 as 0, it will still pass the check.
1059+
*/
10531060
read_extent_buffer(leaf, &ri, btrfs_item_ptr_offset(leaf, slot),
1054-
sizeof(ri));
1061+
btrfs_item_size_nr(leaf, slot));
10551062

10561063
/* Generation related */
10571064
if (btrfs_root_generation(&ri) >

include/uapi/linux/btrfs_tree.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
#include <linux/btrfs.h>
66
#include <linux/types.h>
7+
#ifdef __KERNEL__
8+
#include <linux/stddef.h>
9+
#else
10+
#include <stddef.h>
11+
#endif
712

813
/*
914
* This header contains the structure definitions and constants used
@@ -644,6 +649,15 @@ struct btrfs_root_item {
644649
__le64 reserved[8]; /* for future */
645650
} __attribute__ ((__packed__));
646651

652+
/*
653+
* Btrfs root item used to be smaller than current size. The old format ends
654+
* at where member generation_v2 is.
655+
*/
656+
static inline __u32 btrfs_legacy_root_item_size(void)
657+
{
658+
return offsetof(struct btrfs_root_item, generation_v2);
659+
}
660+
647661
/*
648662
* this is used for both forward and backward root refs
649663
*/

0 commit comments

Comments
 (0)