}
 
 /*
- * this returns the key found in the dir entry in the location pointer.
+ * Return the key found in the dir entry in the location pointer, fill @type
+ * with BTRFS_FT_*, and return 0.
+ *
  * If no dir entries were found, returns -ENOENT.
  * If found a corrupted location in dir entry, returns -EUCLEAN.
  */
 static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
-                              struct btrfs_key *location)
+                              struct btrfs_key *location, u8 *type)
 {
        const char *name = dentry->d_name.name;
        int namelen = dentry->d_name.len;
                           __func__, name, btrfs_ino(BTRFS_I(dir)),
                           location->objectid, location->type, location->offset);
        }
+       if (!ret)
+               *type = btrfs_dir_type(path->nodes[0], di);
 out:
        btrfs_free_path(path);
        return ret;
        return inode;
 }
 
+static inline u8 btrfs_inode_type(struct inode *inode)
+{
+       return btrfs_type_by_mode[(inode->i_mode & S_IFMT) >> S_SHIFT];
+}
+
 struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct btrfs_root *sub_root = root;
        struct btrfs_key location;
+       u8 di_type = 0;
        int index;
        int ret = 0;
 
        if (dentry->d_name.len > BTRFS_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
 
-       ret = btrfs_inode_by_name(dir, dentry, &location);
+       ret = btrfs_inode_by_name(dir, dentry, &location, &di_type);
        if (ret < 0)
                return ERR_PTR(ret);
 
        if (location.type == BTRFS_INODE_ITEM_KEY) {
                inode = btrfs_iget(dir->i_sb, &location, root, NULL);
+               if (IS_ERR(inode))
+                       return inode;
+
+               /* Do extra check against inode mode with di_type */
+               if (btrfs_inode_type(inode) != di_type) {
+                       btrfs_crit(fs_info,
+"inode mode mismatch with dir: inode mode=0%o btrfs type=%u dir type=%u",
+                                 inode->i_mode, btrfs_inode_type(inode),
+                                 di_type);
+                       iput(inode);
+                       return ERR_PTR(-EUCLEAN);
+               }
                return inode;
        }
 
        return ERR_PTR(ret);
 }
 
-static inline u8 btrfs_inode_type(struct inode *inode)
-{
-       return btrfs_type_by_mode[(inode->i_mode & S_IFMT) >> S_SHIFT];
-}
-
 /*
  * utility function to add 'inode' into 'parent_inode' with
  * a give name and a given sequence number.
        extent_start = found_key.offset;
        if (found_type == BTRFS_FILE_EXTENT_REG ||
            found_type == BTRFS_FILE_EXTENT_PREALLOC) {
+               /* Only regular file could have regular/prealloc extent */
+               if (!S_ISREG(inode->vfs_inode.i_mode)) {
+                       ret = -EUCLEAN;
+                       btrfs_crit(fs_info,
+               "regular/prealloc extent found for non-regular inode %llu",
+                                  btrfs_ino(inode));
+                       goto out;
+               }
                extent_end = extent_start +
                       btrfs_file_extent_num_bytes(leaf, item);