btrfs-progs: check: Fix lowmem false alert on tree reloc tree
authorQu Wenruo <quwenruo@cn.fujitsu.com>
Mon, 5 Dec 2016 09:07:55 +0000 (17:07 +0800)
committerDavid Sterba <dsterba@suse.com>
Wed, 14 Dec 2016 14:21:26 +0000 (15:21 +0100)
Lowmem mode will report false alert if the fs has tree reloc tree like:
ERROR: shared extent[30011392 4096] lost its parent (parent: 30011392,
level: 1)

The problem is check_shared_block_backref() can't handle tree reloc
tree's self-pointing backref.

And still try to read out the tree block then seeking for the
referencer.

The correct method for it is to check if it's tree reloc root.
In that case, we should check found the ROOT_ITEM of tree reloc tree in
root tree.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.com>
cmds-check.c

index fc19e14..657cf5c 100644 (file)
@@ -10441,6 +10441,34 @@ out:
 }
 
 /*
+ * Check if tree block @eb is tree reloc root.
+ * Return 0 if it's not or any problem happens
+ * Return 1 if it's a tree reloc root
+ */
+static int is_tree_reloc_root(struct btrfs_fs_info *fs_info,
+                                struct extent_buffer *eb)
+{
+       struct btrfs_root *tree_reloc_root;
+       struct btrfs_key key;
+       u64 bytenr = btrfs_header_bytenr(eb);
+       u64 owner = btrfs_header_owner(eb);
+       int ret = 0;
+
+       key.objectid = BTRFS_TREE_RELOC_OBJECTID;
+       key.offset = owner;
+       key.type = BTRFS_ROOT_ITEM_KEY;
+
+       tree_reloc_root = btrfs_read_fs_root_no_cache(fs_info, &key);
+       if (IS_ERR(tree_reloc_root))
+               return 0;
+
+       if (bytenr == btrfs_header_bytenr(tree_reloc_root->node))
+               ret = 1;
+       btrfs_free_fs_root(tree_reloc_root);
+       return ret;
+}
+
+/*
  * Check referencer for shared block backref
  * If level == -1, this function will resolve the level.
  */
@@ -10462,6 +10490,13 @@ static int check_shared_block_backref(struct btrfs_fs_info *fs_info,
        if (level < 0)
                goto out;
 
+       /* It's possible it's a tree reloc root */
+       if (parent == bytenr) {
+               if (is_tree_reloc_root(fs_info, eb))
+                       found_parent = 1;
+               goto out;
+       }
+
        if (level + 1 != btrfs_header_level(eb))
                goto out;