diff options
Diffstat (limited to 'fs/ext4/balloc.c')
-rw-r--r-- | fs/ext4/balloc.c | 99 |
1 files changed, 81 insertions, 18 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index ff3428e195b4..d460223b8e1d 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -189,13 +189,65 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, | |||
189 | return desc; | 189 | return desc; |
190 | } | 190 | } |
191 | 191 | ||
192 | static int ext4_valid_block_bitmap(struct super_block *sb, | ||
193 | struct ext4_group_desc *desc, | ||
194 | unsigned int block_group, | ||
195 | struct buffer_head *bh) | ||
196 | { | ||
197 | ext4_grpblk_t offset; | ||
198 | ext4_grpblk_t next_zero_bit; | ||
199 | ext4_fsblk_t bitmap_blk; | ||
200 | ext4_fsblk_t group_first_block; | ||
201 | |||
202 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { | ||
203 | /* with FLEX_BG, the inode/block bitmaps and itable | ||
204 | * blocks may not be in the group at all | ||
205 | * so the bitmap validation will be skipped for those groups | ||
206 | * or it has to also read the block group where the bitmaps | ||
207 | * are located to verify they are set. | ||
208 | */ | ||
209 | return 1; | ||
210 | } | ||
211 | group_first_block = ext4_group_first_block_no(sb, block_group); | ||
212 | |||
213 | /* check whether block bitmap block number is set */ | ||
214 | bitmap_blk = ext4_block_bitmap(sb, desc); | ||
215 | offset = bitmap_blk - group_first_block; | ||
216 | if (!ext4_test_bit(offset, bh->b_data)) | ||
217 | /* bad block bitmap */ | ||
218 | goto err_out; | ||
219 | |||
220 | /* check whether the inode bitmap block number is set */ | ||
221 | bitmap_blk = ext4_inode_bitmap(sb, desc); | ||
222 | offset = bitmap_blk - group_first_block; | ||
223 | if (!ext4_test_bit(offset, bh->b_data)) | ||
224 | /* bad block bitmap */ | ||
225 | goto err_out; | ||
226 | |||
227 | /* check whether the inode table block number is set */ | ||
228 | bitmap_blk = ext4_inode_table(sb, desc); | ||
229 | offset = bitmap_blk - group_first_block; | ||
230 | next_zero_bit = ext4_find_next_zero_bit(bh->b_data, | ||
231 | offset + EXT4_SB(sb)->s_itb_per_group, | ||
232 | offset); | ||
233 | if (next_zero_bit >= offset + EXT4_SB(sb)->s_itb_per_group) | ||
234 | /* good bitmap for inode tables */ | ||
235 | return 1; | ||
236 | |||
237 | err_out: | ||
238 | ext4_error(sb, __FUNCTION__, | ||
239 | "Invalid block bitmap - " | ||
240 | "block_group = %d, block = %llu", | ||
241 | block_group, bitmap_blk); | ||
242 | return 0; | ||
243 | } | ||
192 | /** | 244 | /** |
193 | * read_block_bitmap() | 245 | * read_block_bitmap() |
194 | * @sb: super block | 246 | * @sb: super block |
195 | * @block_group: given block group | 247 | * @block_group: given block group |
196 | * | 248 | * |
197 | * Read the bitmap for a given block_group, reading into the specified | 249 | * Read the bitmap for a given block_group,and validate the |
198 | * slot in the superblock's bitmap cache. | 250 | * bits for block/inode/inode tables are set in the bitmaps |
199 | * | 251 | * |
200 | * Return buffer_head on success or NULL in case of failure. | 252 | * Return buffer_head on success or NULL in case of failure. |
201 | */ | 253 | */ |
@@ -210,25 +262,36 @@ read_block_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
210 | if (!desc) | 262 | if (!desc) |
211 | return NULL; | 263 | return NULL; |
212 | bitmap_blk = ext4_block_bitmap(sb, desc); | 264 | bitmap_blk = ext4_block_bitmap(sb, desc); |
265 | bh = sb_getblk(sb, bitmap_blk); | ||
266 | if (unlikely(!bh)) { | ||
267 | ext4_error(sb, __FUNCTION__, | ||
268 | "Cannot read block bitmap - " | ||
269 | "block_group = %d, block_bitmap = %llu", | ||
270 | (int)block_group, (unsigned long long)bitmap_blk); | ||
271 | return NULL; | ||
272 | } | ||
273 | if (bh_uptodate_or_lock(bh)) | ||
274 | return bh; | ||
275 | |||
213 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { | 276 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { |
214 | bh = sb_getblk(sb, bitmap_blk); | 277 | ext4_init_block_bitmap(sb, bh, block_group, desc); |
215 | if (!buffer_uptodate(bh)) { | 278 | set_buffer_uptodate(bh); |
216 | lock_buffer(bh); | 279 | unlock_buffer(bh); |
217 | if (!buffer_uptodate(bh)) { | 280 | return bh; |
218 | ext4_init_block_bitmap(sb, bh, block_group, | ||
219 | desc); | ||
220 | set_buffer_uptodate(bh); | ||
221 | } | ||
222 | unlock_buffer(bh); | ||
223 | } | ||
224 | } else { | ||
225 | bh = sb_bread(sb, bitmap_blk); | ||
226 | } | 281 | } |
227 | if (!bh) | 282 | if (bh_submit_read(bh) < 0) { |
228 | ext4_error (sb, __FUNCTION__, | 283 | put_bh(bh); |
284 | ext4_error(sb, __FUNCTION__, | ||
229 | "Cannot read block bitmap - " | 285 | "Cannot read block bitmap - " |
230 | "block_group = %lu, block_bitmap = %llu", | 286 | "block_group = %d, block_bitmap = %llu", |
231 | block_group, bitmap_blk); | 287 | (int)block_group, (unsigned long long)bitmap_blk); |
288 | return NULL; | ||
289 | } | ||
290 | if (!ext4_valid_block_bitmap(sb, desc, block_group, bh)) { | ||
291 | put_bh(bh); | ||
292 | return NULL; | ||
293 | } | ||
294 | |||
232 | return bh; | 295 | return bh; |
233 | } | 296 | } |
234 | /* | 297 | /* |