Whamcloud - gitweb
7c6419377cb534d86db76cd3b052b1caa025e624
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / rhel6.6 / ext4-corrupted-inode-block-bitmaps-handling-patches.patch
1 diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
2 index 61aeacb..6557100 100644
3 --- a/fs/ext4/balloc.c
4 +++ b/fs/ext4/balloc.c
5 @@ -90,6 +90,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
6         ext4_group_t ngroups = ext4_get_groups_count(sb);
7         unsigned free_blocks, group_blocks;
8         struct ext4_sb_info *sbi = EXT4_SB(sb);
9 +       struct ext4_group_info *grp;
10  
11         if (bh) {
12                 J_ASSERT_BH(bh, buffer_locked(bh));
13 @@ -97,12 +98,11 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
14                 /* If checksum is bad mark all blocks used to prevent allocation
15                  * essentially implementing a per-group read-only flag. */
16                 if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
17 -                       ext4_error(sb, "Checksum bad for group %u",
18 +                       ext4_warning(sb, "Checksum bad for group %u",
19                                         block_group);
20 -                       ext4_free_blks_set(sb, gdp, 0);
21 -                       ext4_free_inodes_set(sb, gdp, 0);
22 -                       ext4_itable_unused_set(sb, gdp, 0);
23 -                       memset(bh->b_data, 0xff, sb->s_blocksize);
24 +                       grp = ext4_get_group_info(sb, block_group);
25 +                       set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
26 +                       set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
27                         return 0;
28                 }
29                 memset(bh->b_data, 0, sb->s_blocksize);
30 @@ -240,6 +240,7 @@ static int ext4_valid_block_bitmap(struct super_block *sb,
31         ext4_grpblk_t next_zero_bit;
32         ext4_fsblk_t bitmap_blk;
33         ext4_fsblk_t group_first_block;
34 +       struct ext4_group_info *grp = ext4_get_group_info(sb, block_group);
35  
36         if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
37                 /* with FLEX_BG, the inode/block bitmaps and itable
38 @@ -277,8 +278,9 @@ static int ext4_valid_block_bitmap(struct super_block *sb,
39                 return 1;
40  
41  err_out:
42 -       ext4_error(sb, "Invalid block bitmap - block_group = %d, block = %llu",
43 +       ext4_warning(sb, "Invalid block bitmap - block_group = %d, block = %llu",
44                         block_group, bitmap_blk);
45 +       set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
46         return 0;
47  }
48  /**
49 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
50 index f71111c..86953d0 100644
51 --- a/fs/ext4/ext4.h
52 +++ b/fs/ext4/ext4.h
53 @@ -2209,9 +2209,15 @@ struct ext4_group_info {
54  
55  #define EXT4_GROUP_INFO_NEED_INIT_BIT          0
56  #define EXT4_GROUP_INFO_WAS_TRIMMED_BIT                1
57 +#define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT    2
58 +#define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT    3
59  
60  #define EXT4_MB_GRP_NEED_INIT(grp)     \
61         (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
62 +#define EXT4_MB_GRP_BBITMAP_CORRUPT(grp)       \
63 +       (test_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &((grp)->bb_state)))
64 +#define EXT4_MB_GRP_IBITMAP_CORRUPT(grp)       \
65 +       (test_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &((grp)->bb_state)))
66  
67  #define EXT4_MB_GRP_WAS_TRIMMED(grp)   \
68         (test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
69 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
70 index f3509ba..9e92917 100644
71 --- a/fs/ext4/ialloc.c
72 +++ b/fs/ext4/ialloc.c
73 @@ -70,17 +70,17 @@ unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *bh,
74                                 struct ext4_group_desc *gdp)
75  {
76         struct ext4_sb_info *sbi = EXT4_SB(sb);
77 +       struct ext4_group_info *grp;
78  
79         J_ASSERT_BH(bh, buffer_locked(bh));
80  
81         /* If checksum is bad mark all blocks and inodes use to prevent
82          * allocation, essentially implementing a per-group read-only flag. */
83         if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
84 -               ext4_error(sb, "Checksum bad for group %u", block_group);
85 -               ext4_free_blks_set(sb, gdp, 0);
86 -               ext4_free_inodes_set(sb, gdp, 0);
87 -               ext4_itable_unused_set(sb, gdp, 0);
88 -               memset(bh->b_data, 0xff, sb->s_blocksize);
89 +               ext4_warning(sb, "Checksum bad for group %u", block_group);
90 +               grp = ext4_get_group_info(sb, block_group);
91 +               set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
92 +               set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
93                 return 0;
94         }
95  
96 @@ -192,6 +192,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
97         struct ext4_super_block *es;
98         struct ext4_sb_info *sbi;
99         int fatal = 0, err, count, cleared;
100 +       struct ext4_group_info *grp;
101  
102         if (atomic_read(&inode->i_count) > 1) {
103                 printk(KERN_ERR "ext4_free_inode: inode has count=%d\n",
104 @@ -235,7 +236,9 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
105         block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
106         bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
107         bitmap_bh = ext4_read_inode_bitmap(sb, block_group);
108 -       if (!bitmap_bh)
109 +       /* Don't bother if the inode bitmap is corrupt. */
110 +       grp = ext4_get_group_info(sb, block_group);
111 +       if (unlikely(EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) || !bitmap_bh)
112                 goto error_return;
113  
114         BUFFER_TRACE(bitmap_bh, "get_write_access");
115 @@ -247,9 +250,10 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
116         ext4_lock_group(sb, block_group);
117         cleared = ext4_clear_bit(bit, bitmap_bh->b_data);
118         ext4_unlock_group(sb, block_group);
119 -       if (!cleared)
120 -               ext4_error(sb, "bit already cleared for inode %lu", ino);
121 -       else {
122 +       if (!cleared) {
123 +               ext4_warning(sb, "bit already cleared for inode %lu", ino);
124 +               set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
125 +       } else {
126                 gdp = ext4_get_group_desc(sb, block_group, &bh2);
127  
128                 BUFFER_TRACE(bh2, "get_write_access");
129 @@ -825,6 +829,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode,
130         int free = 0;
131         static int once = 1;
132         ext4_group_t flex_group;
133 +       struct ext4_group_info *grp;
134  
135         /* Cannot create files in a deleted directory */
136         if (!dir || !dir->i_nlink)
137 @@ -884,10 +889,21 @@ got_group:
138                 if (!gdp)
139                         goto fail;
140  
141 +               grp = ext4_get_group_info(sb, group);
142 +               /* Skip groups with already-known suspicious inode tables */
143 +               if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
144 +                       if (++group == ngroups)
145 +                               group = 0;
146 +                       continue;
147 +               }
148                 brelse(inode_bitmap_bh);
149                 inode_bitmap_bh = ext4_read_inode_bitmap(sb, group);
150 -               if (!inode_bitmap_bh)
151 -                       goto fail;
152 +               /* Skip groups with suspicious inode tables */
153 +               if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp) || !inode_bitmap_bh) {
154 +                       if (++group == ngroups)
155 +                               group = 0;
156 +                       continue;
157 +               }
158  
159  repeat_in_this_group:
160                 ino = ext4_find_next_zero_bit((unsigned long *)
161 diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
162 index efcf909..dc88197 100644
163 --- a/fs/ext4/mballoc.c
164 +++ b/fs/ext4/mballoc.c
165 @@ -1291,6 +1291,10 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
166  
167         BUG_ON(first + count > (sb->s_blocksize << 3));
168         assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group));
169 +       /* Don't bother if the block group is corrupt. */
170 +       if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info)))
171 +               return;
172 +
173         mb_check_buddy(e4b);
174         mb_free_blocks_double(inode, e4b, first, count);
175  
176 @@ -1321,9 +1325,12 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
177                             le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
178                         ext4_grp_locked_error(sb, e4b->bd_group,
179                                    __func__, "double-free of inode"
180 -                                  " %lu's block %llu(bit %u in group %u)",
181 +                                  " %lu's block %llu(bit %u in group %u) block bitmap corrupt",
182                                    inode ? inode->i_ino : 0, blocknr, block,
183                                    e4b->bd_group);
184 +                       /* Mark the block group as corrupt. */
185 +                       set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
186 +                               &e4b->bd_info->bb_state);
187                 }
188                 mb_clear_bit(block, EXT4_MB_BITMAP(e4b));
189                 e4b->bd_info->bb_counters[order]++;
190 @@ -1700,6 +1707,11 @@ int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
191         if (err)
192                 return err;
193  
194 +       if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info))) {
195 +               ext4_mb_release_desc(e4b);
196 +               return 0;
197 +       }
198 +
199         ext4_lock_group(ac->ac_sb, group);
200         max = mb_find_extent(e4b, 0, ac->ac_g_ex.fe_start,
201                              ac->ac_g_ex.fe_len, &ex);
202 @@ -1912,6 +1924,9 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
203  
204         BUG_ON(cr < 0 || cr >= 4);
205  
206 +       if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(grp)))
207 +               return 0;
208 +
209         /* We only do this if the grp has never been initialized */
210         if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
211                 int ret = ext4_mb_init_group(ac->ac_sb, group);
212 @@ -4746,6 +4761,10 @@ do_more:
213         overflow = 0;
214         ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
215  
216 +       if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(
217 +                       ext4_get_group_info(sb, block_group))))
218 +               return;
219 +
220         /*
221          * Check to see if we are freeing blocks across a group
222          * boundary.