@@ -4906,6 +4906,60 @@ out:
}
/*
+ * Call repair_inode_item_missing and repair_ternary_lowmem to repair
+ *
+ * @diff_ret: same as repair_ternary_lowmem
+ *
+ * Returns 0 means success
+ */
+static int repair_dir_item(struct btrfs_root *root, u64 dirid, u64 ino,
+ u64 index, u8 filetype, char *namebuf, u32 name_len,
+ int *err_ret)
+{
+ int ret = 0;
+
+ if (*err_ret & INODE_ITEM_MISSING) {
+ ret = repair_inode_item_missing(root, ino, filetype, *err_ret);
+ if (!ret)
+ *err_ret &= ~(INODE_ITEM_MISMATCH |
+ INODE_ITEM_MISSING);
+ }
+
+ if (*err_ret & ~(INODE_ITEM_MISMATCH | INODE_ITEM_MISSING)) {
+ ret = repair_ternary_lowmem(root, dirid, ino, index, namebuf,
+ name_len, filetype, *err_ret);
+ if (!ret) {
+ *err_ret &= ~(DIR_INDEX_MISMATCH | DIR_INDEX_MISSING);
+ *err_ret &= ~(DIR_ITEM_MISMATCH | DIR_ITEM_MISSING);
+ *err_ret &= ~(INODE_REF_MISSING);
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Research @path by the @key, if it fails then change path to previous item.
+ *
+ * returns 0 means success
+ * returns <0 means failure
+ * return >0 means jumped to previous item
+ */
+static int research_path(struct btrfs_root *root, struct btrfs_path *path,
+ struct btrfs_key *key)
+{
+ int ret;
+ /* research path */
+ btrfs_release_path(path);
+ ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
+ if (ret > 0) {
+ ret = btrfs_previous_item(root, path, key->objectid,
+ key->type);
+ }
+
+ return ret;
+}
+/*
* Traverse the given DIR_ITEM/DIR_INDEX and check related INODE_ITEM and
* call find_inode_ref() to check related INODE_REF/INODE_EXTREF.If repair
* is enable, do repair and research by @path->nodes[0].
@@ -4941,6 +4995,7 @@ static int check_dir_item(struct btrfs_root *root, struct btrfs_key *key,
int ret;
int err = 0;
int tmp_err;
+ int need_research = 0;
/*
* For DIR_ITEM set index to (u64)-1, so that find_inode_ref
@@ -4948,10 +5003,22 @@ static int check_dir_item(struct btrfs_root *root, struct btrfs_key *key,
*/
index = (key->type == BTRFS_DIR_INDEX_KEY) ? key->offset : (u64)-1;
+research:
+ if (need_research) {
+ ret = research_path(root, path, key);
+ need_research = 0;
+ if (ret)
+ return ret > 0 ? 0 : ret;
+ }
+
+ err = 0;
+ cur = 0;
node = path->nodes[0];
slot = path->slots[0];
+
di = btrfs_item_ptr(node, slot, struct btrfs_dir_item);
total = btrfs_item_size_nr(node, slot);
+ memset(namebuf, 0, sizeof(namebuf) / sizeof(*namebuf));
while (cur < total) {
data_len = btrfs_dir_data_len(node, di);
@@ -5021,6 +5088,16 @@ static int check_dir_item(struct btrfs_root *root, struct btrfs_key *key,
next:
btrfs_release_path(path);
+ if (tmp_err && repair) {
+ ret = repair_dir_item(root, key->objectid,
+ location.objectid, index,
+ imode_to_type(mode), namebuf,
+ name_len, &tmp_err);
+ if (!ret) {
+ need_research = 1;
+ goto research;
+ }
+ }
print_dir_item_err(root, key, location.objectid,
index, namebuf, name_len, filetype,
tmp_err);
@@ -5043,6 +5120,7 @@ next:
err |= ret > 0 ? ENOENT : ret;
return err;
}
+
/*
* Check file extent datasum/hole, update the size of the file extents,
* check and update the last offset of the file extent.
Introduce 'repair_dir_item' to repair dir item/index missing/mismatch and relative inode item missing while checking. Signed-off-by: Su Yue <suy.fnst@cn.fujitsu.com> --- cmds-check.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+)