From 2963f3d09eb3a0817f87386c0bd7be7ce086809d Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Tue, 8 Sep 2015 21:54:29 +0800 Subject: [PATCH] LU-7114 ldiskfs: corrupted bitmaps handling patches This patch backported following patches from upstream: 163a203ddb36c36d4a1c942aececda0cc8d06aa7 ext4: mark block group as corrupt on block bitmap error 87a39389be3e3b007d341be510a7e4a0542bdf05 ext4: mark block group as corrupt on inode bitmap error bdfb6ff4a255dcebeb09a901250e13a97eff75af ext4: mark group corrupt on group descriptor checksum Also use ext4_warning() instead of ext4_error() so that filesystem don't become RO in default, and together with these patches,FS wil still be usable even such bad things happen. Signed-off-by: Wang Shilong Change-Id: Ib4075aba7df6f7f59e89a90475405080acd43dd0 Reviewed-on: http://review.whamcloud.com/16312 Tested-by: Jenkins Reviewed-by: Andreas Dilger Reviewed-by: Yang Sheng Tested-by: Maloo Reviewed-by: Oleg Drokin --- ...pted-inode-block-bitmaps-handling-patches.patch | 222 ++++++++++++++++++++ ...pted-inode-block-bitmaps-handling-patches.patch | 103 +++++++++ ...pted-inode-block-bitmaps-handling-patches.patch | 230 +++++++++++++++++++++ .../series/ldiskfs-2.6-rhel6.7.series | 1 + .../series/ldiskfs-3.0-sles11sp3.series | 1 + .../series/ldiskfs-3.10-rhel7.series | 1 + 6 files changed, 558 insertions(+) create mode 100644 ldiskfs/kernel_patches/patches/rhel6.6/ext4-corrupted-inode-block-bitmaps-handling-patches.patch create mode 100644 ldiskfs/kernel_patches/patches/rhel7/ext4-corrupted-inode-block-bitmaps-handling-patches.patch create mode 100644 ldiskfs/kernel_patches/patches/sles11sp2/ext4-corrupted-inode-block-bitmaps-handling-patches.patch diff --git a/ldiskfs/kernel_patches/patches/rhel6.6/ext4-corrupted-inode-block-bitmaps-handling-patches.patch b/ldiskfs/kernel_patches/patches/rhel6.6/ext4-corrupted-inode-block-bitmaps-handling-patches.patch new file mode 100644 index 0000000..7c64193 --- /dev/null +++ b/ldiskfs/kernel_patches/patches/rhel6.6/ext4-corrupted-inode-block-bitmaps-handling-patches.patch @@ -0,0 +1,222 @@ +diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c +index 61aeacb..6557100 100644 +--- a/fs/ext4/balloc.c ++++ b/fs/ext4/balloc.c +@@ -90,6 +90,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, + ext4_group_t ngroups = ext4_get_groups_count(sb); + unsigned free_blocks, group_blocks; + struct ext4_sb_info *sbi = EXT4_SB(sb); ++ struct ext4_group_info *grp; + + if (bh) { + J_ASSERT_BH(bh, buffer_locked(bh)); +@@ -97,12 +98,11 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, + /* If checksum is bad mark all blocks used to prevent allocation + * essentially implementing a per-group read-only flag. */ + if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { +- ext4_error(sb, "Checksum bad for group %u", ++ ext4_warning(sb, "Checksum bad for group %u", + block_group); +- ext4_free_blks_set(sb, gdp, 0); +- ext4_free_inodes_set(sb, gdp, 0); +- ext4_itable_unused_set(sb, gdp, 0); +- memset(bh->b_data, 0xff, sb->s_blocksize); ++ grp = ext4_get_group_info(sb, block_group); ++ set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); ++ set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); + return 0; + } + memset(bh->b_data, 0, sb->s_blocksize); +@@ -240,6 +240,7 @@ static int ext4_valid_block_bitmap(struct super_block *sb, + ext4_grpblk_t next_zero_bit; + ext4_fsblk_t bitmap_blk; + ext4_fsblk_t group_first_block; ++ struct ext4_group_info *grp = ext4_get_group_info(sb, block_group); + + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { + /* with FLEX_BG, the inode/block bitmaps and itable +@@ -277,8 +278,9 @@ static int ext4_valid_block_bitmap(struct super_block *sb, + return 1; + + err_out: +- ext4_error(sb, "Invalid block bitmap - block_group = %d, block = %llu", ++ ext4_warning(sb, "Invalid block bitmap - block_group = %d, block = %llu", + block_group, bitmap_blk); ++ set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); + return 0; + } + /** +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index f71111c..86953d0 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -2209,9 +2209,15 @@ struct ext4_group_info { + + #define EXT4_GROUP_INFO_NEED_INIT_BIT 0 + #define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1 ++#define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT 2 ++#define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT 3 + + #define EXT4_MB_GRP_NEED_INIT(grp) \ + (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) ++#define EXT4_MB_GRP_BBITMAP_CORRUPT(grp) \ ++ (test_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &((grp)->bb_state))) ++#define EXT4_MB_GRP_IBITMAP_CORRUPT(grp) \ ++ (test_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &((grp)->bb_state))) + + #define EXT4_MB_GRP_WAS_TRIMMED(grp) \ + (test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state))) +diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c +index f3509ba..9e92917 100644 +--- a/fs/ext4/ialloc.c ++++ b/fs/ext4/ialloc.c +@@ -70,17 +70,17 @@ unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *bh, + struct ext4_group_desc *gdp) + { + struct ext4_sb_info *sbi = EXT4_SB(sb); ++ struct ext4_group_info *grp; + + J_ASSERT_BH(bh, buffer_locked(bh)); + + /* If checksum is bad mark all blocks and inodes use to prevent + * allocation, essentially implementing a per-group read-only flag. */ + if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { +- ext4_error(sb, "Checksum bad for group %u", block_group); +- ext4_free_blks_set(sb, gdp, 0); +- ext4_free_inodes_set(sb, gdp, 0); +- ext4_itable_unused_set(sb, gdp, 0); +- memset(bh->b_data, 0xff, sb->s_blocksize); ++ ext4_warning(sb, "Checksum bad for group %u", block_group); ++ grp = ext4_get_group_info(sb, block_group); ++ set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); ++ set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); + return 0; + } + +@@ -192,6 +192,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) + struct ext4_super_block *es; + struct ext4_sb_info *sbi; + int fatal = 0, err, count, cleared; ++ struct ext4_group_info *grp; + + if (atomic_read(&inode->i_count) > 1) { + printk(KERN_ERR "ext4_free_inode: inode has count=%d\n", +@@ -235,7 +236,9 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) + block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); + bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); + bitmap_bh = ext4_read_inode_bitmap(sb, block_group); +- if (!bitmap_bh) ++ /* Don't bother if the inode bitmap is corrupt. */ ++ grp = ext4_get_group_info(sb, block_group); ++ if (unlikely(EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) || !bitmap_bh) + goto error_return; + + BUFFER_TRACE(bitmap_bh, "get_write_access"); +@@ -247,9 +250,10 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) + ext4_lock_group(sb, block_group); + cleared = ext4_clear_bit(bit, bitmap_bh->b_data); + ext4_unlock_group(sb, block_group); +- if (!cleared) +- ext4_error(sb, "bit already cleared for inode %lu", ino); +- else { ++ if (!cleared) { ++ ext4_warning(sb, "bit already cleared for inode %lu", ino); ++ set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); ++ } else { + gdp = ext4_get_group_desc(sb, block_group, &bh2); + + BUFFER_TRACE(bh2, "get_write_access"); +@@ -825,6 +829,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode, + int free = 0; + static int once = 1; + ext4_group_t flex_group; ++ struct ext4_group_info *grp; + + /* Cannot create files in a deleted directory */ + if (!dir || !dir->i_nlink) +@@ -884,10 +889,21 @@ got_group: + if (!gdp) + goto fail; + ++ grp = ext4_get_group_info(sb, group); ++ /* Skip groups with already-known suspicious inode tables */ ++ if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { ++ if (++group == ngroups) ++ group = 0; ++ continue; ++ } + brelse(inode_bitmap_bh); + inode_bitmap_bh = ext4_read_inode_bitmap(sb, group); +- if (!inode_bitmap_bh) +- goto fail; ++ /* Skip groups with suspicious inode tables */ ++ if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp) || !inode_bitmap_bh) { ++ if (++group == ngroups) ++ group = 0; ++ continue; ++ } + + repeat_in_this_group: + ino = ext4_find_next_zero_bit((unsigned long *) +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index efcf909..dc88197 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -1291,6 +1291,10 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, + + BUG_ON(first + count > (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); + +@@ -1321,9 +1325,12 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); + ext4_grp_locked_error(sb, e4b->bd_group, + __func__, "double-free of inode" +- " %lu's block %llu(bit %u in group %u)", ++ " %lu's block %llu(bit %u in group %u) block bitmap corrupt", + inode ? inode->i_ino : 0, blocknr, block, + e4b->bd_group); ++ /* Mark the block group as corrupt. */ ++ set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, ++ &e4b->bd_info->bb_state); + } + mb_clear_bit(block, EXT4_MB_BITMAP(e4b)); + e4b->bd_info->bb_counters[order]++; +@@ -1700,6 +1707,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_release_desc(e4b); ++ return 0; ++ } ++ + ext4_lock_group(ac->ac_sb, group); + max = mb_find_extent(e4b, 0, ac->ac_g_ex.fe_start, + ac->ac_g_ex.fe_len, &ex); +@@ -1912,6 +1924,9 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac, + + BUG_ON(cr < 0 || cr >= 4); + ++ 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); +@@ -4746,6 +4761,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. diff --git a/ldiskfs/kernel_patches/patches/rhel7/ext4-corrupted-inode-block-bitmaps-handling-patches.patch b/ldiskfs/kernel_patches/patches/rhel7/ext4-corrupted-inode-block-bitmaps-handling-patches.patch new file mode 100644 index 0000000..d119fbc --- /dev/null +++ b/ldiskfs/kernel_patches/patches/rhel7/ext4-corrupted-inode-block-bitmaps-handling-patches.patch @@ -0,0 +1,103 @@ +Since we could skip corrupt block groups, this patch +use ext4_warning() intead of ext4_error() to make FS not +emount RO in default, also fix a leftover from upstream +commit 163a203ddb36c36d4a1c942 +--- + fs/ext4/balloc.c | 6 +++--- + fs/ext4/ialloc.c | 8 ++++---- + fs/ext4/mballoc.c | 13 ++++++++++--- + 3 files changed, 17 insertions(+), 10 deletions(-) + +diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c +index e069155..8ecf06e 100644 +--- a/fs/ext4/balloc.c ++++ b/fs/ext4/balloc.c +@@ -377,7 +377,7 @@ static void ext4_validate_block_bitmap(struct super_block *sb, + blk = ext4_valid_block_bitmap(sb, desc, block_group, bh); + if (unlikely(blk != 0)) { + ext4_unlock_group(sb, block_group); +- ext4_error(sb, "bg %u: block %llu: invalid block bitmap", ++ ext4_warning(sb, "bg %u: block %llu: invalid block bitmap", + block_group, blk); + if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) + percpu_counter_sub(&sbi->s_freeclusters_counter, +@@ -388,7 +388,7 @@ static void ext4_validate_block_bitmap(struct super_block *sb, + if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group, + desc, bh))) { + ext4_unlock_group(sb, block_group); +- ext4_error(sb, "bg %u: bad block bitmap checksum", block_group); ++ ext4_warning(sb, "bg %u: bad block bitmap checksum", block_group); + if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) + percpu_counter_sub(&sbi->s_freeclusters_counter, + grp->bb_free); +@@ -446,7 +446,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) + ext4_unlock_group(sb, block_group); + unlock_buffer(bh); + if (err) +- ext4_error(sb, "Checksum bad for grp %u", block_group); ++ ext4_warning(sb, "Checksum bad for grp %u", block_group); + return bh; + } + ext4_unlock_group(sb, block_group); +diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c +index fc65310..4936bff 100644 +--- a/fs/ext4/ialloc.c ++++ b/fs/ext4/ialloc.c +@@ -77,7 +77,7 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb, + /* If checksum is bad mark all blocks and inodes use to prevent + * allocation, essentially implementing a per-group read-only flag. */ + if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { +- ext4_error(sb, "Checksum bad for group %u", block_group); ++ ext4_warning(sb, "Checksum bad for group %u", block_group); + grp = ext4_get_group_info(sb, block_group); + if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) + percpu_counter_sub(&sbi->s_freeclusters_counter, +@@ -193,8 +193,8 @@ verify: + EXT4_INODES_PER_GROUP(sb) / 8)) { + ext4_unlock_group(sb, block_group); + put_bh(bh); +- ext4_error(sb, "Corrupt inode bitmap - block_group = %u, " +- "inode_bitmap = %llu", block_group, bitmap_blk); ++ ext4_warning(sb, "Corrupt inode bitmap - block_group = %u, " ++ "inode_bitmap = %llu", block_group, bitmap_blk); + grp = ext4_get_group_info(sb, block_group); + if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { + int count; +@@ -337,7 +337,7 @@ out: + if (!fatal) + fatal = err; + } else { +- ext4_error(sb, "bit already cleared for inode %lu", ino); ++ ext4_warning(sb, "bit already cleared for inode %lu", ino); + if (gdp && !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { + int count; + count = ext4_free_inodes_count(sb, gdp); +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index d2b07bd..695ccd3 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -752,11 +752,18 @@ int ext4_mb_generate_buddy(struct super_block *sb, + if (free != grp->bb_free) { + struct ext4_group_desc *gdp; + gdp = ext4_get_group_desc(sb, group, NULL); +- ext4_error(sb, "group %lu: %u blocks in bitmap, %u in bb, " +- "%u in gd, %lu pa's\n", (long unsigned int)group, ++ ext4_warning(sb, "group %lu: %u blocks in bitmap, %u in bb, " ++ "%u in gd, %lu pa's block bitmap corrupt", ++ (long unsigned int)group, + free, grp->bb_free, ext4_free_group_clusters(sb, gdp), + grp->bb_prealloc_nr); +- return -EIO; ++ /* ++ * 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); + +-- +1.8.3.1 + diff --git a/ldiskfs/kernel_patches/patches/sles11sp2/ext4-corrupted-inode-block-bitmaps-handling-patches.patch b/ldiskfs/kernel_patches/patches/sles11sp2/ext4-corrupted-inode-block-bitmaps-handling-patches.patch new file mode 100644 index 0000000..ca1a648 --- /dev/null +++ b/ldiskfs/kernel_patches/patches/sles11sp2/ext4-corrupted-inode-block-bitmaps-handling-patches.patch @@ -0,0 +1,230 @@ +--- + fs/ext4/balloc.c | 14 ++++++++------ + fs/ext4/ext4.h | 6 ++++++ + fs/ext4/ialloc.c | 37 +++++++++++++++++++++++++++---------- + fs/ext4/mballoc.c | 22 +++++++++++++++++++++- + 4 files changed, 62 insertions(+), 17 deletions(-) + +diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c +index db5b7a3..c631a37 100644 +--- a/fs/ext4/balloc.c ++++ b/fs/ext4/balloc.c +@@ -92,6 +92,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, + ext4_group_t ngroups = ext4_get_groups_count(sb); + unsigned free_blocks, group_blocks; + struct ext4_sb_info *sbi = EXT4_SB(sb); ++ struct ext4_group_info *grp; + + if (bh) { + J_ASSERT_BH(bh, buffer_locked(bh)); +@@ -99,12 +100,11 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, + /* If checksum is bad mark all blocks used to prevent allocation + * essentially implementing a per-group read-only flag. */ + if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { +- ext4_error(sb, "Checksum bad for group %u", ++ ext4_warning(sb, "Checksum bad for group %u", + block_group); +- ext4_free_blks_set(sb, gdp, 0); +- ext4_free_inodes_set(sb, gdp, 0); +- ext4_itable_unused_set(sb, gdp, 0); +- memset(bh->b_data, 0xff, sb->s_blocksize); ++ grp = ext4_get_group_info(sb, block_group); ++ set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); ++ set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); + return 0; + } + memset(bh->b_data, 0, sb->s_blocksize); +@@ -242,6 +242,7 @@ static int ext4_valid_block_bitmap(struct super_block *sb, + ext4_grpblk_t next_zero_bit; + ext4_fsblk_t bitmap_blk; + ext4_fsblk_t group_first_block; ++ struct ext4_group_info *grp = ext4_get_group_info(sb, block_group); + + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { + /* with FLEX_BG, the inode/block bitmaps and itable +@@ -279,8 +280,9 @@ static int ext4_valid_block_bitmap(struct super_block *sb, + return 1; + + err_out: +- ext4_error(sb, "Invalid block bitmap - block_group = %d, block = %llu", ++ ext4_warning(sb, "Invalid block bitmap - block_group = %d, block = %llu", + block_group, bitmap_blk); ++ set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); + return 0; + } + /** +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index a18fd36..40ad66f 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -2257,9 +2257,15 @@ struct ext4_group_info { + + #define EXT4_GROUP_INFO_NEED_INIT_BIT 0 + #define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1 ++#define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT 2 ++#define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT 3 + + #define EXT4_MB_GRP_NEED_INIT(grp) \ + (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) ++#define EXT4_MB_GRP_BBITMAP_CORRUPT(grp) \ ++ (test_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &((grp)->bb_state))) ++#define EXT4_MB_GRP_IBITMAP_CORRUPT(grp) \ ++ (test_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &((grp)->bb_state))) + + #define EXT4_MB_GRP_WAS_TRIMMED(grp) \ + (test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state))) +diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c +index 532dcaa..c9e6b19 100644 +--- a/fs/ext4/ialloc.c ++++ b/fs/ext4/ialloc.c +@@ -72,17 +72,17 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb, + struct ext4_group_desc *gdp) + { + struct ext4_sb_info *sbi = EXT4_SB(sb); ++ struct ext4_group_info *grp; + + J_ASSERT_BH(bh, buffer_locked(bh)); + + /* If checksum is bad mark all blocks and inodes use to prevent + * allocation, essentially implementing a per-group read-only flag. */ + if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { +- ext4_error(sb, "Checksum bad for group %u", block_group); +- ext4_free_blks_set(sb, gdp, 0); +- ext4_free_inodes_set(sb, gdp, 0); +- ext4_itable_unused_set(sb, gdp, 0); +- memset(bh->b_data, 0xff, sb->s_blocksize); ++ ext4_warning(sb, "Checksum bad for group %u", block_group); ++ grp = ext4_get_group_info(sb, block_group); ++ set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); ++ set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); + return 0; + } + +@@ -195,6 +195,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) + struct ext4_super_block *es; + struct ext4_sb_info *sbi; + int fatal = 0, err, count, cleared; ++ struct ext4_group_info *grp; + + if (atomic_read(&inode->i_count) > 1) { + printk(KERN_ERR "ext4_free_inode: inode has count=%d\n", +@@ -238,7 +239,9 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) + block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); + bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); + bitmap_bh = ext4_read_inode_bitmap(sb, block_group); +- if (!bitmap_bh) ++ /* Don't bother if the inode bitmap is corrupt. */ ++ grp = ext4_get_group_info(sb, block_group); ++ if (unlikely(EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) || !bitmap_bh) + goto error_return; + + BUFFER_TRACE(bitmap_bh, "get_write_access"); +@@ -286,8 +289,10 @@ out: + if (!fatal) + fatal = err; + ext4_mark_super_dirty(sb); +- } else +- ext4_error(sb, "bit already cleared for inode %lu", ino); ++ } else { ++ ext4_warning(sb, "bit already cleared for inode %lu", ino); ++ set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); ++ } + + error_return: + brelse(bitmap_bh); +@@ -820,6 +825,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode, + int free = 0; + static int once = 1; + ext4_group_t flex_group; ++ struct ext4_group_info *grp; + + /* Cannot create files in a deleted directory */ + if (!dir || !dir->i_nlink) +@@ -879,10 +885,21 @@ got_group: + if (!gdp) + goto fail; + ++ grp = ext4_get_group_info(sb, group); ++ /* Skip groups with already-known suspicious inode tables */ ++ if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { ++ if (++group == ngroups) ++ group = 0; ++ continue; ++ } + brelse(inode_bitmap_bh); + inode_bitmap_bh = ext4_read_inode_bitmap(sb, group); +- if (!inode_bitmap_bh) +- goto fail; ++ /* Skip groups with suspicious inode tables */ ++ if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp) || !inode_bitmap_bh) { ++ if (++group == ngroups) ++ group = 0; ++ continue; ++ } + + repeat_in_this_group: + ino = ext4_find_next_zero_bit((unsigned long *) +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index 1d77581..d19d1ba 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -1322,6 +1322,10 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, + + BUG_ON(first + count > (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); + +@@ -1353,7 +1357,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_clear_bit(block, EXT4_MB_BITMAP(e4b)); + e4b->bd_info->bb_counters[order]++; +@@ -1729,6 +1737,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, 0, ac->ac_g_ex.fe_start, + ac->ac_g_ex.fe_len, &ex); +@@ -1940,6 +1953,9 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac, + + BUG_ON(cr < 0 || cr >= 4); + ++ 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); +@@ -4781,6 +4797,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. +-- +1.7.1 + diff --git a/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.7.series b/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.7.series index a737a5a..832e5b1 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.7.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.7.series @@ -43,3 +43,4 @@ rhel6.4/ext4-max-dir-size-options.patch rhel6.3/ext4-not-discard-preallocation-umount.patch rhel6.3/ext4-journal-path-opt.patch rhel6.6/ext4-remove-truncate-warning.patch +rhel6.6/ext4-corrupted-inode-block-bitmaps-handling-patches.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-3.0-sles11sp3.series b/ldiskfs/kernel_patches/series/ldiskfs-3.0-sles11sp3.series index 4d9d6bf..5932eb7 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-3.0-sles11sp3.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-3.0-sles11sp3.series @@ -36,3 +36,4 @@ rhel6.3/ext4-max-dir-size.patch sles11sp2/ext4-max-dir-size-options.patch rhel6.3/ext4-not-discard-preallocation-umount.patch rhel6.3/ext4-journal-path-opt.patch +sles11sp2/ext4-corrupted-inode-block-bitmaps-handling-patches.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.series b/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.series index 2ae3b1e..c48b1ac 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.series @@ -16,3 +16,4 @@ rhel7/ext4-large-dir.patch rhel7/ext4-pdirop.patch rhel7/ext4-max-dir-size.patch rhel7/ext4-remove-truncate-warning.patch +rhel7/ext4-corrupted-inode-block-bitmaps-handling-patches.patch -- 1.8.3.1