+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.