|
@@ -751,13 +751,15 @@ void ext4_mb_generate_buddy(struct super_block *sb,
|
|
|
|
|
|
if (free != grp->bb_free) {
|
|
|
ext4_grp_locked_error(sb, group, 0, 0,
|
|
|
- "%u clusters in bitmap, %u in gd",
|
|
|
+ "%u clusters in bitmap, %u in gd; "
|
|
|
+ "block bitmap corrupt.",
|
|
|
free, grp->bb_free);
|
|
|
/*
|
|
|
- * If we intent to continue, we consider group descritor
|
|
|
+ * If we intend to continue, we consider group descriptor
|
|
|
* corrupt and update bb_free using bitmap value
|
|
|
*/
|
|
|
grp->bb_free = free;
|
|
|
+ set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
|
|
|
}
|
|
|
mb_set_largest_free_order(sb, grp);
|
|
|
|
|
@@ -1398,6 +1400,10 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
|
|
|
|
|
|
BUG_ON(last >= (sb->s_blocksize << 3));
|
|
|
assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group));
|
|
|
+ /* Don't bother if the block group is corrupt. */
|
|
|
+ if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info)))
|
|
|
+ return;
|
|
|
+
|
|
|
mb_check_buddy(e4b);
|
|
|
mb_free_blocks_double(inode, e4b, first, count);
|
|
|
|
|
@@ -1423,7 +1429,11 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
|
|
|
inode ? inode->i_ino : 0,
|
|
|
blocknr,
|
|
|
"freeing already freed block "
|
|
|
- "(bit %u)", block);
|
|
|
+ "(bit %u); block bitmap corrupt.",
|
|
|
+ block);
|
|
|
+ /* Mark the block group as corrupt. */
|
|
|
+ set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
|
|
|
+ &e4b->bd_info->bb_state);
|
|
|
mb_regenerate_buddy(e4b);
|
|
|
goto done;
|
|
|
}
|
|
@@ -1790,6 +1800,11 @@ int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
+ if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info))) {
|
|
|
+ ext4_mb_unload_buddy(e4b);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
ext4_lock_group(ac->ac_sb, group);
|
|
|
max = mb_find_extent(e4b, ac->ac_g_ex.fe_start,
|
|
|
ac->ac_g_ex.fe_len, &ex);
|
|
@@ -1987,6 +2002,9 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
|
|
|
if (cr <= 2 && free < ac->ac_g_ex.fe_len)
|
|
|
return 0;
|
|
|
|
|
|
+ if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(grp)))
|
|
|
+ return 0;
|
|
|
+
|
|
|
/* We only do this if the grp has never been initialized */
|
|
|
if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
|
|
|
int ret = ext4_mb_init_group(ac->ac_sb, group);
|
|
@@ -4674,6 +4692,10 @@ do_more:
|
|
|
overflow = 0;
|
|
|
ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
|
|
|
|
|
|
+ if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(
|
|
|
+ ext4_get_group_info(sb, block_group))))
|
|
|
+ return;
|
|
|
+
|
|
|
/*
|
|
|
* Check to see if we are freeing blocks across a group
|
|
|
* boundary.
|