--- /dev/null
+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.
--- /dev/null
+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
+
--- /dev/null
+---
+ 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
+
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
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
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