add patch avoid-drop-reference-to-iloc.bh-twice
[ext4-patch-queue.git] / protect-add-journal-inode-blocks-using-block_validity
blob040ba5ab6bed59fd20568da0532a335e1dc23174
1 ext4: protect journal inode's blocks using block_validity
3 Add the blocks which belong to the journal inode to block_validity's
4 system zone so attempts to deallocate or overwrite the journal due a
5 corrupted file system where the journal blocks are also claimed by
6 another inode.
8 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=202879
9 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
10 Cc: stable@kernel.org
11 ---
12  fs/ext4/block_validity.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
13  fs/ext4/inode.c          |  4 ++++
14  2 files changed, 52 insertions(+)
16 diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c
17 index 913061c0de1b..9409b1e11a22 100644
18 --- a/fs/ext4/block_validity.c
19 +++ b/fs/ext4/block_validity.c
20 @@ -137,6 +137,48 @@ static void debug_print_tree(struct ext4_sb_info *sbi)
21         printk(KERN_CONT "\n");
22  }
24 +static int ext4_protect_reserved_inode(struct super_block *sb, u32 ino)
26 +       struct inode *inode;
27 +       struct ext4_sb_info *sbi = EXT4_SB(sb);
28 +       struct ext4_map_blocks map;
29 +       u32 i = 0, err = 0, num, n;
31 +       if ((ino < EXT4_ROOT_INO) ||
32 +           (ino > le32_to_cpu(sbi->s_es->s_inodes_count)))
33 +               return -EINVAL;
34 +       inode = ext4_iget(sb, ino, EXT4_IGET_SPECIAL);
35 +       if (IS_ERR(inode))
36 +               return PTR_ERR(inode);
37 +       num = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
38 +       while (i < num) {
39 +               map.m_lblk = i;
40 +               map.m_len = num - i;
41 +               n = ext4_map_blocks(NULL, inode, &map, 0);
42 +               if (n < 0) {
43 +                       err = n;
44 +                       break;
45 +               }
46 +               if (n == 0) {
47 +                       i++;
48 +               } else {
49 +                       if (!ext4_data_block_valid(sbi, map.m_pblk, n)) {
50 +                               ext4_error(sb, "blocks %llu-%llu from inode %u "
51 +                                          "overlap system zone", map.m_pblk,
52 +                                          map.m_pblk + map.m_len - 1, ino);
53 +                               err = -EFSCORRUPTED;
54 +                               break;
55 +                       }
56 +                       err = add_system_zone(sbi, map.m_pblk, n);
57 +                       if (err < 0)
58 +                               break;
59 +                       i += n;
60 +               }
61 +       }
62 +       iput(inode);
63 +       return err;
66  int ext4_setup_system_zone(struct super_block *sb)
67  {
68         ext4_group_t ngroups = ext4_get_groups_count(sb);
69 @@ -171,6 +213,12 @@ int ext4_setup_system_zone(struct super_block *sb)
70                 if (ret)
71                         return ret;
72         }
73 +       if (ext4_has_feature_journal(sb) && sbi->s_es->s_journal_inum) {
74 +               ret = ext4_protect_reserved_inode(sb,
75 +                               le32_to_cpu(sbi->s_es->s_journal_inum));
76 +               if (ret)
77 +                       return ret;
78 +       }
80         if (test_opt(sb, DEBUG))
81                 debug_print_tree(sbi);
82 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
83 index 190f0478582a..609c8366d029 100644
84 --- a/fs/ext4/inode.c
85 +++ b/fs/ext4/inode.c
86 @@ -399,6 +399,10 @@ static int __check_block_validity(struct inode *inode, const char *func,
87                                 unsigned int line,
88                                 struct ext4_map_blocks *map)
89  {
90 +       if (ext4_has_feature_journal(inode->i_sb) &&
91 +           (inode->i_ino ==
92 +            le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum)))
93 +               return 0;
94         if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk,
95                                    map->m_len)) {
96                 ext4_error_inode(inode, func, line, map->m_pblk,