lkml.org 
[lkml]   [2020]   [Jun]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 3.16 49/61] ext4: protect journal inode's blocks using block_validity
    3.16.85-rc1 review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Theodore Ts'o <tytso@mit.edu>

    commit 345c0dbf3a30872d9b204db96b5857cd00808cae upstream.

    Add the blocks which belong to the journal inode to block_validity's
    system zone so attempts to deallocate or overwrite the journal due a
    corrupted file system where the journal blocks are also claimed by
    another inode.

    Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=202879
    Signed-off-by: Theodore Ts'o <tytso@mit.edu>
    Cc: stable@kernel.org
    [bwh: Backported to 3.16:
    - Use EXT4_HAS_COMPAT_FEATURE()
    - Use EIO instead of EFSCORRUPTED]
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    ---
    --- a/fs/ext4/block_validity.c
    +++ b/fs/ext4/block_validity.c
    @@ -137,6 +137,48 @@ static void debug_print_tree(struct ext4
    printk("\n");
    }

    +static int ext4_protect_reserved_inode(struct super_block *sb, u32 ino)
    +{
    + struct inode *inode;
    + struct ext4_sb_info *sbi = EXT4_SB(sb);
    + struct ext4_map_blocks map;
    + u32 i = 0, err = 0, num, n;
    +
    + if ((ino < EXT4_ROOT_INO) ||
    + (ino > le32_to_cpu(sbi->s_es->s_inodes_count)))
    + return -EINVAL;
    + inode = ext4_iget(sb, ino, EXT4_IGET_SPECIAL);
    + if (IS_ERR(inode))
    + return PTR_ERR(inode);
    + num = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
    + while (i < num) {
    + map.m_lblk = i;
    + map.m_len = num - i;
    + n = ext4_map_blocks(NULL, inode, &map, 0);
    + if (n < 0) {
    + err = n;
    + break;
    + }
    + if (n == 0) {
    + i++;
    + } else {
    + if (!ext4_data_block_valid(sbi, map.m_pblk, n)) {
    + ext4_error(sb, "blocks %llu-%llu from inode %u "
    + "overlap system zone", map.m_pblk,
    + map.m_pblk + map.m_len - 1, ino);
    + err = -EIO;
    + break;
    + }
    + err = add_system_zone(sbi, map.m_pblk, n);
    + if (err < 0)
    + break;
    + i += n;
    + }
    + }
    + iput(inode);
    + return err;
    +}
    +
    int ext4_setup_system_zone(struct super_block *sb)
    {
    ext4_group_t ngroups = ext4_get_groups_count(sb);
    @@ -171,6 +213,13 @@ int ext4_setup_system_zone(struct super_
    if (ret)
    return ret;
    }
    + if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL) &&
    + sbi->s_es->s_journal_inum) {
    + ret = ext4_protect_reserved_inode(sb,
    + le32_to_cpu(sbi->s_es->s_journal_inum));
    + if (ret)
    + return ret;
    + }

    if (test_opt(sb, DEBUG))
    debug_print_tree(EXT4_SB(sb));
    --- a/fs/ext4/inode.c
    +++ b/fs/ext4/inode.c
    @@ -411,6 +411,11 @@ static int __check_block_validity(struct
    unsigned int line,
    struct ext4_map_blocks *map)
    {
    + if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
    + EXT4_FEATURE_COMPAT_HAS_JOURNAL) &&
    + (inode->i_ino ==
    + le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum)))
    + return 0;
    if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk,
    map->m_len)) {
    ext4_error_inode(inode, func, line, map->m_pblk,
    \
     
     \ /
      Last update: 2020-06-09 20:07    [W:2.322 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site