btrfs-progs: check: modify check_fs_first_inode()
authorSu Yue <suy.fnst@cn.fujitsu.com>
Mon, 28 Aug 2017 05:54:21 +0000 (13:54 +0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 16 Oct 2017 18:33:00 +0000 (20:33 +0200)
Modify check_fs_first_inode to check the inode ref in first inode.

Which root dir inode differs from other inode is inode_ref points
"..".
So we just handle this special case and treat it as normal
inode in continued check.

Signed-off-by: Su Yue <suy.fnst@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.com>
cmds-check.c

index cbd0d7d..874a75a 100644 (file)
@@ -5308,10 +5308,20 @@ out:
        return err;
 }
 
+/*
+ * check first root dir's inode_item and inode_ref
+ *
+ * returns 0 means no error
+ * returns >0 means error
+ * returns <0 means fatal error
+ */
 static int check_fs_first_inode(struct btrfs_root *root, unsigned int ext_ref)
 {
        struct btrfs_path path;
        struct btrfs_key key;
+       struct btrfs_inode_item *ii;
+       u64 index;
+       u32 mode;
        int err = 0;
        int ret;
 
@@ -5322,28 +5332,44 @@ static int check_fs_first_inode(struct btrfs_root *root, unsigned int ext_ref)
        /* For root being dropped, we don't need to check first inode */
        if (btrfs_root_refs(&root->root_item) == 0 &&
            btrfs_disk_key_objectid(&root->root_item.drop_progress) >=
-           key.objectid)
+           BTRFS_FIRST_FREE_OBJECTID)
                return 0;
 
        btrfs_init_path(&path);
-
        ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
        if (ret < 0)
                goto out;
        if (ret > 0) {
                ret = 0;
                err |= INODE_ITEM_MISSING;
-               error("first inode item of root %llu is missing",
-                     root->objectid);
+       } else {
+               ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
+                                   struct btrfs_inode_item);
+               mode = btrfs_inode_mode(path.nodes[0], ii);
+               if (imode_to_type(mode) != BTRFS_FT_DIR)
+                       err |= INODE_ITEM_MISMATCH;
        }
 
-       err |= check_inode_item(root, &path, ext_ref);
-       err &= ~LAST_ITEM;
-       if (err && !ret)
-               ret = -EIO;
+       /* lookup first inode ref */
+       key.offset = BTRFS_FIRST_FREE_OBJECTID;
+       key.type = BTRFS_INODE_REF_KEY;
+       /* special index value */
+       index = 0;
+
+       ret = find_inode_ref(root, &key, "..", strlen(".."), &index, ext_ref);
+       if (ret < 0)
+               goto out;
+       err |= ret;
+
 out:
        btrfs_release_path(&path);
-       return ret;
+       if (err & (INODE_ITEM_MISSING | INODE_ITEM_MISMATCH))
+               error("root dir INODE_ITEM is %s",
+                     err & INODE_ITEM_MISMATCH ? "mismatch" : "missing");
+       if (err & INODE_REF_MISSING)
+               error("root dir INODE_REF is missing");
+
+       return ret < 0 ? ret : err;
 }
 
 static struct tree_backref *find_tree_backref(struct extent_record *rec,
@@ -5432,6 +5458,7 @@ static int check_fs_root_v2(struct btrfs_root *root, unsigned int ext_ref)
        ret = check_fs_first_inode(root, ext_ref);
        if (ret < 0)
                return ret;
+       err |= !!ret;
 
        memset(&nrefs, 0, sizeof(nrefs));
        level = btrfs_header_level(root->node);