]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/ext4/namei.c
Merge tag 'linux-kselftest-5.6-rc3' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / fs / ext4 / namei.c
index 1cb42d94078479dc9a9e107c79e361e0c385a02b..ceff4b4b1877dd32c5c4772d05231a458035d0f8 100644 (file)
@@ -109,7 +109,10 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode,
        struct ext4_dir_entry *dirent;
        int is_dx_block = 0;
 
-       bh = ext4_bread(NULL, inode, block, 0);
+       if (ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_EIO))
+               bh = ERR_PTR(-EIO);
+       else
+               bh = ext4_bread(NULL, inode, block, 0);
        if (IS_ERR(bh)) {
                __ext4_warning(inode->i_sb, func, line,
                               "inode #%lu: lblock %lu: comm %s: "
@@ -153,9 +156,11 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode,
         * caller is sure it should be an index block.
         */
        if (is_dx_block && type == INDEX) {
-               if (ext4_dx_csum_verify(inode, dirent))
+               if (ext4_dx_csum_verify(inode, dirent) &&
+                   !ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_CRC))
                        set_buffer_verified(bh);
                else {
+                       ext4_set_errno(inode->i_sb, EFSBADCRC);
                        ext4_error_inode(inode, func, line, block,
                                         "Directory index failed checksum");
                        brelse(bh);
@@ -163,9 +168,11 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode,
                }
        }
        if (!is_dx_block) {
-               if (ext4_dirblock_csum_verify(inode, bh))
+               if (ext4_dirblock_csum_verify(inode, bh) &&
+                   !ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_CRC))
                        set_buffer_verified(bh);
                else {
+                       ext4_set_errno(inode->i_sb, EFSBADCRC);
                        ext4_error_inode(inode, func, line, block,
                                         "Directory block failed checksum");
                        brelse(bh);
@@ -1002,7 +1009,6 @@ static int htree_dirblock_to_tree(struct file *dir_file,
        top = (struct ext4_dir_entry_2 *) ((char *) de +
                                           dir->i_sb->s_blocksize -
                                           EXT4_DIR_REC_LEN(0));
-#ifdef CONFIG_FS_ENCRYPTION
        /* Check if the directory is encrypted */
        if (IS_ENCRYPTED(dir)) {
                err = fscrypt_get_encryption_info(dir);
@@ -1017,7 +1023,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
                        return err;
                }
        }
-#endif
+
        for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) {
                if (ext4_check_dir_entry(dir, NULL, de, bh,
                                bh->b_data, bh->b_size,
@@ -1065,9 +1071,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
        }
 errout:
        brelse(bh);
-#ifdef CONFIG_FS_ENCRYPTION
        fscrypt_fname_free_buffer(&fname_crypto_str);
-#endif
        return count;
 }
 
@@ -1527,6 +1531,7 @@ static struct buffer_head *__ext4_find_entry(struct inode *dir,
                        goto next;
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh)) {
+                       ext4_set_errno(sb, EIO);
                        EXT4_ERROR_INODE(dir, "reading directory lblock %lu",
                                         (unsigned long) block);
                        brelse(bh);
@@ -1537,6 +1542,7 @@ static struct buffer_head *__ext4_find_entry(struct inode *dir,
                    !is_dx_internal_node(dir, block,
                                         (struct ext4_dir_entry *)bh->b_data) &&
                    !ext4_dirblock_csum_verify(dir, bh)) {
+                       ext4_set_errno(sb, EFSBADCRC);
                        EXT4_ERROR_INODE(dir, "checksumming directory "
                                         "block %lu", (unsigned long)block);
                        brelse(bh);
@@ -2207,6 +2213,13 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
                retval = ext4_dx_add_entry(handle, &fname, dir, inode);
                if (!retval || (retval != ERR_BAD_DX_DIR))
                        goto out;
+               /* Can we just ignore htree data? */
+               if (ext4_has_metadata_csum(sb)) {
+                       EXT4_ERROR_INODE(dir,
+                               "Directory has corrupted htree index.");
+                       retval = -EFSCORRUPTED;
+                       goto out;
+               }
                ext4_clear_inode_flag(dir, EXT4_INODE_INDEX);
                dx_fallback++;
                ext4_mark_inode_dirty(handle, dir);