diff --git a/cmds-check.c b/cmds-check.c
index f302724dd840..59575506c83e 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -3074,7 +3074,7 @@ static int delete_dir_index(struct btrfs_root *root,
 	btrfs_init_path(&path);
 	di = btrfs_lookup_dir_index(trans, root, &path, backref->dir,
 				    backref->name, backref->namelen,
-				    backref->index, -1);
+				    backref->index, -1, false);
 	if (IS_ERR(di)) {
 		ret = PTR_ERR(di);
 		btrfs_release_path(&path);
diff --git a/convert/main.c b/convert/main.c
index 89f9261172ca..102ba4fc5ae2 100644
--- a/convert/main.c
+++ b/convert/main.c
@@ -1580,7 +1580,7 @@ static int do_rollback(const char *devname)
 	/* Search the image file */
 	root_dir = btrfs_root_dirid(&image_root->root_item);
 	dir = btrfs_lookup_dir_item(NULL, image_root, &path, root_dir,
-			image_name, strlen(image_name), 0);
+			image_name, strlen(image_name), 0, true);
 
 	if (!dir || IS_ERR(dir)) {
 		btrfs_release_path(&path);
diff --git a/ctree.h b/ctree.h
index ef422ea60031..02529f4cb021 100644
--- a/ctree.h
+++ b/ctree.h
@@ -2679,12 +2679,12 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
 					     struct btrfs_root *root,
 					     struct btrfs_path *path, u64 dir,
 					     const char *name, int name_len,
-					     int mod);
+					     int mod, bool verify);
 struct btrfs_dir_item *btrfs_lookup_dir_index(struct btrfs_trans_handle *trans,
 					      struct btrfs_root *root,
 					      struct btrfs_path *path, u64 dir,
 					      const char *name, int name_len,
-					      u64 index, int mod);
+					      u64 index, int mod, bool verify);
 int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
 			      struct btrfs_root *root,
 			      struct btrfs_path *path,
diff --git a/dir-item.c b/dir-item.c
index 462546c0eaf4..31ad1eca29d5 100644
--- a/dir-item.c
+++ b/dir-item.c
@@ -24,7 +24,7 @@
 
 static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
 			      struct btrfs_path *path,
-			      const char *name, int name_len);
+			      const char *name, int name_len, bool verify);
 
 static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
 						   *trans,
@@ -43,7 +43,8 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
 	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
 	if (ret == -EEXIST) {
 		struct btrfs_dir_item *di;
-		di = btrfs_match_dir_item_name(root, path, name, name_len);
+		di = btrfs_match_dir_item_name(root, path, name, name_len,
+					       true);
 		if (di)
 			return ERR_PTR(-EEXIST);
 		ret = btrfs_extend_item(root, path, data_size);
@@ -196,7 +197,7 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
 					     struct btrfs_root *root,
 					     struct btrfs_path *path, u64 dir,
 					     const char *name, int name_len,
-					     int mod)
+					     int mod, bool verify)
 {
 	int ret;
 	struct btrfs_key key;
@@ -227,14 +228,31 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
 	    found_key.offset != key.offset)
 		return NULL;
 
-	return btrfs_match_dir_item_name(root, path, name, name_len);
+	return btrfs_match_dir_item_name(root, path, name, name_len, verify);
 }
 
+/*
+ * Lookup dir index
+ * 
+ * @dir:	dir inode number
+ * @name:	the filename we're looking for
+ * @name_len:	name length
+ * @index:	dir index
+ *
+ * Normally (@root, @dir, @index) should be enough to locate a dir index in a
+ * *healthy* fs.
+ * But with @name and @name_len, we can even handle corrupted fs with
+ * duplicated DIR_INDEX.
+ *
+ * @mod:	if we're going to modify the dir_index, needs @trans
+ * @verify:	if we need to verify the dir_item before search
+ * 		useful for check to delet corrupted dir index.
+ */
 struct btrfs_dir_item *btrfs_lookup_dir_index(struct btrfs_trans_handle *trans,
 					      struct btrfs_root *root,
 					      struct btrfs_path *path, u64 dir,
 					      const char *name, int name_len,
-					      u64 index, int mod)
+					      u64 index, int mod, bool verify)
 {
 	int ret;
 	struct btrfs_key key;
@@ -251,7 +269,7 @@ struct btrfs_dir_item *btrfs_lookup_dir_index(struct btrfs_trans_handle *trans,
 	if (ret > 0)
 		return ERR_PTR(-ENOENT);
 
-	return btrfs_match_dir_item_name(root, path, name, name_len);
+	return btrfs_match_dir_item_name(root, path, name, name_len, verify);
 }
 
 /*
@@ -323,7 +341,7 @@ static int verify_dir_item(struct btrfs_root *root,
 
 static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
 			      struct btrfs_path *path,
-			      const char *name, int name_len)
+			      const char *name, int name_len, bool verify)
 {
 	struct btrfs_dir_item *dir_item;
 	unsigned long name_ptr;
@@ -335,7 +353,7 @@ static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
 	leaf = path->nodes[0];
 	dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
 	total_len = btrfs_item_size_nr(leaf, path->slots[0]);
-	if (verify_dir_item(root, leaf, dir_item))
+	if (verify && verify_dir_item(root, leaf, dir_item))
 		return NULL;
 
 	while(cur < total_len) {
diff --git a/inode.c b/inode.c
index 2398bca4a109..7b9a40062bb3 100644
--- a/inode.c
+++ b/inode.c
@@ -123,7 +123,7 @@ int check_dir_conflict(struct btrfs_root *root, char *name, int namelen,
 
 	/* Name conflicting? */
 	dir_item = btrfs_lookup_dir_item(NULL, root, path, dir, name,
-					 namelen, 0);
+					 namelen, 0, true);
 	if (IS_ERR(dir_item)) {
 		ret = PTR_ERR(dir_item);
 		goto out;
@@ -136,7 +136,7 @@ int check_dir_conflict(struct btrfs_root *root, char *name, int namelen,
 
 	/* Index conflicting? */
 	dir_item = btrfs_lookup_dir_index(NULL, root, path, dir, name,
-					  namelen, index, 0);
+					  namelen, index, 0, true);
 	if (IS_ERR(dir_item) && PTR_ERR(dir_item) == -ENOENT)
 		dir_item = NULL;
 	if (IS_ERR(dir_item)) {
@@ -301,7 +301,7 @@ int btrfs_unlink(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 	btrfs_release_path(path);
 
 	dir_item = btrfs_lookup_dir_item(NULL, root, path, parent_ino,
-					 name, namelen, 0);
+					 name, namelen, 0, false);
 	if (IS_ERR(dir_item)) {
 		ret = PTR_ERR(dir_item);
 		goto out;
@@ -311,7 +311,7 @@ int btrfs_unlink(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 	btrfs_release_path(path);
 
 	dir_item = btrfs_lookup_dir_index(NULL, root, path, parent_ino,
-					  name, namelen, index, 0);
+					  name, namelen, index, 0, false);
 	/*
 	 * Since lookup_dir_index() will return -ENOENT when not found,
 	 * we need to do extra check.
@@ -370,7 +370,7 @@ int btrfs_unlink(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 	if (del_dir_index) {
 		dir_item = btrfs_lookup_dir_index(trans, root, path,
 						  parent_ino, name, namelen,
-						  index, -1);
+						  index, -1, false);
 		if (IS_ERR(dir_item)) {
 			ret = PTR_ERR(dir_item);
 			goto out;
@@ -403,7 +403,7 @@ int btrfs_unlink(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 
 	if (del_dir_item) {
 		dir_item = btrfs_lookup_dir_item(trans, root, path, parent_ino,
-						 name, namelen, -1);
+						 name, namelen, -1, false);
 		if (IS_ERR(dir_item)) {
 			ret = PTR_ERR(dir_item);
 			goto out;
@@ -532,7 +532,7 @@ int btrfs_mkdir(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		ret_ino = *ino;
 
 	dir_item = btrfs_lookup_dir_item(NULL, root, path, parent_ino,
-					 name, namelen, 0);
+					 name, namelen, 0, true);
 	if (IS_ERR(dir_item)) {
 		ret = PTR_ERR(dir_item);
 		goto out;
