| From 1465af12e254a68706e110846f59cf0f09683184 Mon Sep 17 00:00:00 2001 |
| From: Qu Wenruo <wqu@suse.com> |
| Date: Tue, 22 Sep 2020 10:37:01 +0800 |
| Subject: btrfs: tree-checker: fix false alert caused by legacy btrfs root item |
| |
| From: Qu Wenruo <wqu@suse.com> |
| |
| commit 1465af12e254a68706e110846f59cf0f09683184 upstream. |
| |
| Commit 259ee7754b67 ("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: 259ee7754b67 ("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> |
| |
| --- |
| fs/btrfs/tree-checker.c | 17 ++++++++++++----- |
| include/uapi/linux/btrfs_tree.h | 14 ++++++++++++++ |
| 2 files changed, 26 insertions(+), 5 deletions(-) |
| |
| --- a/fs/btrfs/tree-checker.c |
| +++ b/fs/btrfs/tree-checker.c |
| @@ -1035,7 +1035,7 @@ static int check_root_item(struct extent |
| int slot) |
| { |
| 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 | |
| BTRFS_ROOT_SUBVOL_DEAD; |
| int ret; |
| @@ -1044,14 +1044,21 @@ static int check_root_item(struct extent |
| if (ret < 0) |
| 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, |
| - "invalid root item size, have %u expect %zu", |
| - btrfs_item_size_nr(leaf, slot), sizeof(ri)); |
| + "invalid root item size, have %u expect %zu or %u", |
| + 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), |
| - sizeof(ri)); |
| + btrfs_item_size_nr(leaf, slot)); |
| |
| /* Generation related */ |
| if (btrfs_root_generation(&ri) > |
| --- a/include/uapi/linux/btrfs_tree.h |
| +++ b/include/uapi/linux/btrfs_tree.h |
| @@ -4,6 +4,11 @@ |
| |
| #include <linux/btrfs.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 |
| @@ -645,6 +650,15 @@ struct btrfs_root_item { |
| } __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 |
| */ |
| struct btrfs_root_ref { |