summaryrefslogtreecommitdiff
path: root/cmds-check.c
diff options
context:
space:
mode:
authorSu Yue <suy.fnst@cn.fujitsu.com>2017-08-28 16:08:55 +0800
committerDavid Sterba <dsterba@suse.com>2017-10-16 20:33:00 +0200
commit839b3c5214c7d0fb3fa87969ab0b9ece9e6baa77 (patch)
tree0ec7d575d79226728d4ebd7981235d9a9226c017 /cmds-check.c
parentcac2b0390de8cd4f9a79ddf7e9a6a6e9522cef56 (diff)
btrfs-progs: check: introduce repair_fs_first_inode()
Introduce 'repair_fs_first_inode' to repair first inode errors (ref missing and inode item missing). Signed-off-by: Su Yue <suy.fnst@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'cmds-check.c')
-rw-r--r--cmds-check.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/cmds-check.c b/cmds-check.c
index 17ce0bb1..ebb542c6 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -5535,6 +5535,70 @@ out:
}
/*
+ * Insert the missing inode item and inode ref.
+ *
+ * Normal INODE_ITEM_MISSING and INODE_REF_MISSING are handled in backref * dir.
+ * Root dir should be handled specially because root dir is the root of fs.
+ *
+ * returns err (>0 or 0) after repair
+ */
+static int repair_fs_first_inode(struct btrfs_root *root, int err)
+{
+ struct btrfs_trans_handle *trans;
+ struct btrfs_key key;
+ struct btrfs_path path;
+ int filetype = BTRFS_FT_DIR;
+ int ret = 0;
+
+ btrfs_init_path(&path);
+
+ if (err & INODE_REF_MISSING) {
+ key.objectid = BTRFS_FIRST_FREE_OBJECTID;
+ key.type = BTRFS_INODE_REF_KEY;
+ key.offset = BTRFS_FIRST_FREE_OBJECTID;
+
+ trans = btrfs_start_transaction(root, 1);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out;
+ }
+
+ btrfs_release_path(&path);
+ ret = btrfs_search_slot(trans, root, &key, &path, 1, 1);
+ if (ret)
+ goto trans_fail;
+
+ ret = btrfs_insert_inode_ref(trans, root, "..", 2,
+ BTRFS_FIRST_FREE_OBJECTID,
+ BTRFS_FIRST_FREE_OBJECTID, 0);
+ if (ret)
+ goto trans_fail;
+
+ printf("Add INODE_REF[%llu %llu] name %s\n",
+ BTRFS_FIRST_FREE_OBJECTID, BTRFS_FIRST_FREE_OBJECTID,
+ "..");
+ err &= ~INODE_REF_MISSING;
+trans_fail:
+ if (ret)
+ error("fail to insert first inode's ref");
+ btrfs_commit_transaction(trans, root);
+ }
+
+ if (err & INODE_ITEM_MISSING) {
+ ret = repair_inode_item_missing(root,
+ BTRFS_FIRST_FREE_OBJECTID, filetype);
+ if (ret)
+ goto out;
+ err &= ~INODE_ITEM_MISSING;
+ }
+out:
+ if (ret)
+ error("fail to repair first inode");
+ btrfs_release_path(&path);
+ return err;
+}
+
+/*
* check first root dir's inode_item and inode_ref
*
* returns 0 means no error
@@ -5589,6 +5653,10 @@ static int check_fs_first_inode(struct btrfs_root *root, unsigned int ext_ref)
out:
btrfs_release_path(&path);
+
+ if (err && repair)
+ err = repair_fs_first_inode(root, err);
+
if (err & (INODE_ITEM_MISSING | INODE_ITEM_MISMATCH))
error("root dir INODE_ITEM is %s",
err & INODE_ITEM_MISMATCH ? "mismatch" : "missing");