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