diff mbox

[16/20] btrfs-progs: cmds-check.c: Introduce repair_dir_item

Message ID 20170301031403.23902-17-suy.fnst@cn.fujitsu.com (mailing list archive)
State New, archived
Headers show

Commit Message

Su Yue March 1, 2017, 3:13 a.m. UTC
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(+)
diff mbox

Patch

diff --git a/cmds-check.c b/cmds-check.c
index 9a76107e..1b35a5fd 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -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.