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;
/* 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,
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);