aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2013-08-28 17:35:51 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-08-28 17:35:51 -0400
commit163a203ddb36c36d4a1c942aececda0cc8d06aa7 (patch)
tree262380f2ba7f37d8213ae815ab7af77cd9b17818 /fs/ext4
parentdbde0abed8c6e9e938c2194675ce63f5769b0d37 (diff)
ext4: mark block group as corrupt on block bitmap error
When we notice a block-bitmap corruption (because of device failure or something else), we should mark this group as corrupt and prevent further block allocations/deallocations from it. Currently, we end up generating one error message for every block in the bitmap. This potentially could make the system unstable as noticed in some bugs. With this patch, the error will be printed only the first time and mark the entire block group as corrupted. This prevents future access allocations/deallocations from it. Also tested by corrupting the block bitmap and forcefully introducing the mb_free_blocks error: (1) create a largefile (2Gb) $ dd if=/dev/zero of=largefile oflag=direct bs=10485760 count=200 (2) umount filesystem. use dumpe2fs to see which block-bitmaps are in use by largefile and note their block numbers (3) use dd to zero-out the used block bitmaps $ dd if=/dev/zero of=/dev/hdc4 bs=4096 seek=14 count=8 oflag=direct (4) mount the FS and delete the largefile. (5) recreate the largefile. verify that the new largefile does not get any blocks from the groups marked as bad. Without the patch, we will see mb_free_blocks error for each bit in each zero'ed out bitmap at (4). With the patch, we only see the error once per blockgroup: [ 309.706803] EXT4-fs error (device sdb4): ext4_mb_generate_buddy:735: group 15: 32768 clusters in bitmap, 0 in gd. blk grp corrupted. [ 309.720824] EXT4-fs error (device sdb4): ext4_mb_generate_buddy:735: group 14: 32768 clusters in bitmap, 0 in gd. blk grp corrupted. [ 309.732858] EXT4-fs error (device sdb4) in ext4_free_blocks:4802: IO failure [ 309.748321] EXT4-fs error (device sdb4): ext4_mb_generate_buddy:735: group 13: 32768 clusters in bitmap, 0 in gd. blk grp corrupted. [ 309.760331] EXT4-fs error (device sdb4) in ext4_free_blocks:4802: IO failure [ 309.769695] EXT4-fs error (device sdb4): ext4_mb_generate_buddy:735: group 12: 32768 clusters in bitmap, 0 in gd. blk grp corrupted. [ 309.781721] EXT4-fs error (device sdb4) in ext4_free_blocks:4802: IO failure [ 309.798166] EXT4-fs error (device sdb4): ext4_mb_generate_buddy:735: group 11: 32768 clusters in bitmap, 0 in gd. blk grp corrupted. [ 309.810184] EXT4-fs error (device sdb4) in ext4_free_blocks:4802: IO failure [ 309.819532] EXT4-fs error (device sdb4): ext4_mb_generate_buddy:735: group 10: 32768 clusters in bitmap, 0 in gd. blk grp corrupted. Google-Bug-Id: 7258357 [darrick.wong@oracle.com] Further modifications (by Darrick) to make more obvious that this corruption bit applies to blocks only. Set the corruption flag if the block group bitmap verification fails. Original-author: Aditya Kali <adityakali@google.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/balloc.c3
-rw-r--r--fs/ext4/ext4.h3
-rw-r--r--fs/ext4/mballoc.c28
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.