diff options
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/balloc.c | 3 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 3 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 28 |
3 files changed, 31 insertions, 3 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index a40b1f96c021..d9b66c4a26e8 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -356,6 +356,7 @@ void ext4_validate_block_bitmap(struct super_block *sb, | |||
356 | struct buffer_head *bh) | 356 | struct buffer_head *bh) |
357 | { | 357 | { |
358 | ext4_fsblk_t blk; | 358 | ext4_fsblk_t blk; |
359 | struct ext4_group_info *grp = ext4_get_group_info(sb, block_group); | ||
359 | 360 | ||
360 | if (buffer_verified(bh)) | 361 | if (buffer_verified(bh)) |
361 | return; | 362 | return; |
@@ -366,12 +367,14 @@ void ext4_validate_block_bitmap(struct super_block *sb, | |||
366 | ext4_unlock_group(sb, block_group); | 367 | ext4_unlock_group(sb, block_group); |
367 | ext4_error(sb, "bg %u: block %llu: invalid block bitmap", | 368 | ext4_error(sb, "bg %u: block %llu: invalid block bitmap", |
368 | block_group, blk); | 369 | block_group, blk); |
370 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); | ||
369 | return; | 371 | return; |
370 | } | 372 | } |
371 | if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group, | 373 | if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group, |
372 | desc, bh))) { | 374 | desc, bh))) { |
373 | ext4_unlock_group(sb, block_group); | 375 | ext4_unlock_group(sb, block_group); |
374 | ext4_error(sb, "bg %u: bad block bitmap checksum", block_group); | 376 | ext4_error(sb, "bg %u: bad block bitmap checksum", block_group); |
377 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); | ||
375 | return; | 378 | return; |
376 | } | 379 | } |
377 | set_buffer_verified(bh); | 380 | set_buffer_verified(bh); |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 2e5818267565..02b764b4e635 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -2480,9 +2480,12 @@ struct ext4_group_info { | |||
2480 | 2480 | ||
2481 | #define EXT4_GROUP_INFO_NEED_INIT_BIT 0 | 2481 | #define EXT4_GROUP_INFO_NEED_INIT_BIT 0 |
2482 | #define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1 | 2482 | #define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1 |
2483 | #define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT 2 | ||
2483 | 2484 | ||
2484 | #define EXT4_MB_GRP_NEED_INIT(grp) \ | 2485 | #define EXT4_MB_GRP_NEED_INIT(grp) \ |
2485 | (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) | 2486 | (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) |
2487 | #define EXT4_MB_GRP_BBITMAP_CORRUPT(grp) \ | ||
2488 | (test_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &((grp)->bb_state))) | ||
2486 | 2489 | ||
2487 | #define EXT4_MB_GRP_WAS_TRIMMED(grp) \ | 2490 | #define EXT4_MB_GRP_WAS_TRIMMED(grp) \ |
2488 | (test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state))) | 2491 | (test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state))) |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index aa7d058e9e48..a41e3ba8cfaa 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -751,13 +751,15 @@ void ext4_mb_generate_buddy(struct super_block *sb, | |||
751 | 751 | ||
752 | if (free != grp->bb_free) { | 752 | if (free != grp->bb_free) { |
753 | ext4_grp_locked_error(sb, group, 0, 0, | 753 | ext4_grp_locked_error(sb, group, 0, 0, |
754 | "%u clusters in bitmap, %u in gd", | 754 | "%u clusters in bitmap, %u in gd; " |
755 | "block bitmap corrupt.", | ||
755 | free, grp->bb_free); | 756 | free, grp->bb_free); |
756 | /* | 757 | /* |
757 | * If we intent to continue, we consider group descritor | 758 | * If we intend to continue, we consider group descriptor |
758 | * corrupt and update bb_free using bitmap value | 759 | * corrupt and update bb_free using bitmap value |
759 | */ | 760 | */ |
760 | grp->bb_free = free; | 761 | grp->bb_free = free; |
762 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); | ||
761 | } | 763 | } |
762 | mb_set_largest_free_order(sb, grp); | 764 | mb_set_largest_free_order(sb, grp); |
763 | 765 | ||
@@ -1398,6 +1400,10 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, | |||
1398 | 1400 | ||
1399 | BUG_ON(last >= (sb->s_blocksize << 3)); | 1401 | BUG_ON(last >= (sb->s_blocksize << 3)); |
1400 | assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group)); | 1402 | assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group)); |
1403 | /* Don't bother if the block group is corrupt. */ | ||
1404 | if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info))) | ||
1405 | return; | ||
1406 | |||
1401 | mb_check_buddy(e4b); | 1407 | mb_check_buddy(e4b); |
1402 | mb_free_blocks_double(inode, e4b, first, count); | 1408 | mb_free_blocks_double(inode, e4b, first, count); |
1403 | 1409 | ||
@@ -1423,7 +1429,11 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, | |||
1423 | inode ? inode->i_ino : 0, | 1429 | inode ? inode->i_ino : 0, |
1424 | blocknr, | 1430 | blocknr, |
1425 | "freeing already freed block " | 1431 | "freeing already freed block " |
1426 | "(bit %u)", block); | 1432 | "(bit %u); block bitmap corrupt.", |
1433 | block); | ||
1434 | /* Mark the block group as corrupt. */ | ||
1435 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, | ||
1436 | &e4b->bd_info->bb_state); | ||
1427 | mb_regenerate_buddy(e4b); | 1437 | mb_regenerate_buddy(e4b); |
1428 | goto done; | 1438 | goto done; |
1429 | } | 1439 | } |
@@ -1790,6 +1800,11 @@ int ext4_mb_find_by_goal(struct ext4_allocation_context *ac, | |||
1790 | if (err) | 1800 | if (err) |
1791 | return err; | 1801 | return err; |
1792 | 1802 | ||
1803 | if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info))) { | ||
1804 | ext4_mb_unload_buddy(e4b); | ||
1805 | return 0; | ||
1806 | } | ||
1807 | |||
1793 | ext4_lock_group(ac->ac_sb, group); | 1808 | ext4_lock_group(ac->ac_sb, group); |
1794 | max = mb_find_extent(e4b, ac->ac_g_ex.fe_start, | 1809 | max = mb_find_extent(e4b, ac->ac_g_ex.fe_start, |
1795 | ac->ac_g_ex.fe_len, &ex); | 1810 | ac->ac_g_ex.fe_len, &ex); |
@@ -1987,6 +2002,9 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac, | |||
1987 | if (cr <= 2 && free < ac->ac_g_ex.fe_len) | 2002 | if (cr <= 2 && free < ac->ac_g_ex.fe_len) |
1988 | return 0; | 2003 | return 0; |
1989 | 2004 | ||
2005 | if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(grp))) | ||
2006 | return 0; | ||
2007 | |||
1990 | /* We only do this if the grp has never been initialized */ | 2008 | /* We only do this if the grp has never been initialized */ |
1991 | if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) { | 2009 | if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) { |
1992 | int ret = ext4_mb_init_group(ac->ac_sb, group); | 2010 | int ret = ext4_mb_init_group(ac->ac_sb, group); |
@@ -4674,6 +4692,10 @@ do_more: | |||
4674 | overflow = 0; | 4692 | overflow = 0; |
4675 | ext4_get_group_no_and_offset(sb, block, &block_group, &bit); | 4693 | ext4_get_group_no_and_offset(sb, block, &block_group, &bit); |
4676 | 4694 | ||
4695 | if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT( | ||
4696 | ext4_get_group_info(sb, block_group)))) | ||
4697 | return; | ||
4698 | |||
4677 | /* | 4699 | /* |
4678 | * Check to see if we are freeing blocks across a group | 4700 | * Check to see if we are freeing blocks across a group |
4679 | * boundary. | 4701 | * boundary. |