Whamcloud - gitweb
LU-1026 ldiskfs: make bitmaps corruption not fatal 79/16679/8
authorWang Shilong <wshilong@ddn.com>
Sat, 11 Jul 2015 03:49:55 +0000 (11:49 +0800)
committerOleg Drokin <oleg.drokin@intel.com>
Fri, 4 Dec 2015 17:58:44 +0000 (17:58 +0000)
We still hit bitmaps problems for rhel6 series kernel,
corruptions happen because ext4_mb_check_ondisk_bitmap()
check failed and FS become RO again:

ldiskfs_mb_check_ondisk_bitmap: on-disk bitmap for group
294corrupted: 20180 blocks free in bitmap, 20181 - in gd
Aborting journal on device dm-6-8.
LDISKFS-fs (dm-6): Remounting filesystem read-only
ldiskfs_mb_new_blocks: Updating bitmap error: [err -30]
 [pa ffff880d9d6e4d68] [phy 14974976] [logic 8192] [len 3072]
 [free 3072] [error 1] [inode 278678]
ldiskfs_ext_new_extent_cb: Journal has aborted

this might be caused by some ext4 internal bugs, this patch
did the following things:

1.Inside ext4_read_block_bitmap() have gaven reasons
why it failed, so caller don't need call ext4_error() again.
2. mark block group corrupt and use ext4_warning() instead
of ext4_error().

There are still some bitmaps corruption places not handling,
let's keep it for now, and if it really hurt, let's add the
same handling codes logic later.

Tested by following scripts:

TEST_DEV="/dev/sdb"
TEST_MNT="/mnt/ext4"

mkdir -p $TEST_MNT
mkfs.ext4 -F $TEST_DEV >&/dev/null

mount -t ldiskfs $TEST_DEV $TEST_MNT
dd if=/dev/zero of=$TEST_MNT/largefile
oflag=direct bs=10485760 count=200
umount $TEST_MNT
dd if=/dev/zero of=$TEST_DEV bs=4096 seek=641
count=10 oflag=direct
mount -t ldiskfs $TEST_DEV $TEST_MNT
rm -f $TEST_MNT/largefile
dd if=/dev/zero of=$TEST_MNT/largefile oflag=direct
bs=10485760 count=200 && echo
  "FILESYSTEM still usable after bitmaps corrupts happen"
dmesg | tail
umount $TEST_MNT
e2fsck $TEST_DEV -y

Signed-off-by: Wang Shilong <wshilong@ddn.com>
Change-Id: Iabb6ebf719d80d9ba4f41bee0b237e304212832b
Reviewed-on: http://review.whamcloud.com/16679
Tested-by: Jenkins
Reviewed-by: Bob Glossman <bob.glossman@intel.com>
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Yang Sheng <yang.sheng@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
ldiskfs/kernel_patches/patches/rhel6.6/ext4-corrupted-inode-block-bitmaps-handling-patches.patch
ldiskfs/kernel_patches/patches/rhel7/ext4-corrupted-inode-block-bitmaps-handling-patches.patch
ldiskfs/kernel_patches/patches/sles11sp2/ext4-corrupted-inode-block-bitmaps-handling-patches.patch
ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.6.series

index 7c64193..8ab3de5 100644 (file)
@@ -1,61 +1,68 @@
 diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
-index 61aeacb..6557100 100644
+index 61aeacb..026c89f 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,
+@@ -97,12 +97,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",
++                      ext4_corrupted_block_group(sb, block_group,
++                                      EXT4_GROUP_INFO_BBITMAP_CORRUPT |
++                                      EXT4_GROUP_INFO_IBITMAP_CORRUPT,
++                                      "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,
+@@ -277,7 +276,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",
++      ext4_corrupted_block_group(sb, block_group,
++                      EXT4_GROUP_INFO_BBITMAP_CORRUPT,
++                      "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
+index 4ed330c..938487a 100644
 --- a/fs/ext4/ext4.h
 +++ b/fs/ext4/ext4.h
-@@ -2209,9 +2209,15 @@ struct ext4_group_info {
+@@ -75,8 +75,17 @@ typedef __u32 ext4_lblk_t;
+ /* data type for block group number */
+ typedef unsigned int ext4_group_t;
++void __ext4_corrupted_block_group(struct super_block *sb,
++                                ext4_group_t group, unsigned int flags);
++
++#define ext4_corrupted_block_group(sb, group, flags, fmt...)          \
++      do {                                                            \
++              __ext4_warning(sb, __func__, ## fmt);                   \
++              __ext4_corrupted_block_group(sb, group, flags);         \
++      } while (0)
++
+ /*
+- * Flags used in mballoc's allocation_context flags field.  
++ * Flags used in mballoc's allocation_context flags field.
+  *
+  * Also used to show what's going on for debugging purposes when the
+  * flag field is exported via the traceport interface
+@@ -2203,9 +2212,19 @@ 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_BBITMAP_CORRUPT       \
++      (1 << EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT)
 +#define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT   3
++#define EXT4_GROUP_INFO_IBITMAP_CORRUPT       \
++      (1 << EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT)
  
  #define EXT4_MB_GRP_NEED_INIT(grp)    \
        (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
@@ -67,17 +74,10 @@ index f71111c..86953d0 100644
  #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
+index f3509ba..8894963 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));
+@@ -76,11 +76,10 @@ unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *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)) {
@@ -86,14 +86,14 @@ index f3509ba..9e92917 100644
 -              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);
++              ext4_corrupted_block_group(sb, block_group,
++                              EXT4_GROUP_INFO_BBITMAP_CORRUPT |
++                              EXT4_GROUP_INFO_IBITMAP_CORRUPT,
++                              "Checksum bad for group %u", block_group);
                return 0;
        }
  
-@@ -192,6 +192,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
+@@ -192,6 +191,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;
@@ -101,7 +101,7 @@ index f3509ba..9e92917 100644
  
        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)
+@@ -235,7 +235,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);
@@ -112,7 +112,7 @@ index f3509ba..9e92917 100644
                goto error_return;
  
        BUFFER_TRACE(bitmap_bh, "get_write_access");
-@@ -247,9 +250,10 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
+@@ -247,9 +249,12 @@ 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);
@@ -120,13 +120,15 @@ index f3509ba..9e92917 100644
 -              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);
++              ext4_corrupted_block_group(sb, block_group,
++                                         EXT4_GROUP_INFO_IBITMAP_CORRUPT,
++                                         "bit already cleared for inode %lu",
++                                         ino);
 +      } 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,
+@@ -825,6 +830,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;
@@ -134,7 +136,7 @@ index f3509ba..9e92917 100644
  
        /* Cannot create files in a deleted directory */
        if (!dir || !dir->i_nlink)
-@@ -884,10 +889,21 @@ got_group:
+@@ -884,10 +890,21 @@ got_group:
                if (!gdp)
                        goto fail;
  
@@ -159,10 +161,45 @@ index f3509ba..9e92917 100644
  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
+index efcf909..06cd929 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,
+@@ -715,10 +715,12 @@ 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,
+-                      free, grp->bb_free, ext4_free_blks_count(sb, gdp),
+-                      grp->bb_prealloc_nr);
++              ext4_corrupted_block_group(sb, group,
++                              EXT4_GROUP_INFO_BBITMAP_CORRUPT,
++                              "group %lu: %u blocks in bitmap, %u in bb, %u in gd, %lu pa's\n",
++                              (long unsigned int)group, free, grp->bb_free,
++                              ext4_free_blks_count(sb, gdp),
++                              grp->bb_prealloc_nr);
+               return -EIO;
+       }
+       mb_set_largest_free_order(sb, grp);
+@@ -1120,7 +1122,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
+                */
+               ret = ext4_mb_init_group(sb, group);
+               if (ret)
+-                      return ret;
++                      goto err;
+       }
+       /*
+@@ -1204,6 +1206,8 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
+       return 0;
+ err:
++      ext4_warning(sb, "Error in loading buddy information for %u",
++                   group);
+       if (e4b->bd_bitmap_page)
+               page_cache_release(e4b->bd_bitmap_page);
+       if (e4b->bd_buddy_page)
+@@ -1291,6 +1295,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));
@@ -173,7 +210,7 @@ index efcf909..dc88197 100644
        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,
+@@ -1321,9 +1329,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"
@@ -187,7 +224,7 @@ index efcf909..dc88197 100644
                }
                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,
+@@ -1700,6 +1711,11 @@ int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
        if (err)
                return err;
  
@@ -199,7 +236,7 @@ index efcf909..dc88197 100644
        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,
+@@ -1912,6 +1928,9 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
  
        BUG_ON(cr < 0 || cr >= 4);
  
@@ -209,7 +246,100 @@ index efcf909..dc88197 100644
        /* 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:
+@@ -3382,9 +3401,10 @@ int ext4_mb_check_ondisk_bitmap(struct super_block *sb, void *bitmap,
+       }
+       if (free != ext4_free_blks_count(sb, gdp)) {
+-              ext4_error(sb, "on-disk bitmap for group %d"
+-                      "corrupted: %u blocks free in bitmap, %u - in gd\n",
+-                      group, free, ext4_free_blks_count(sb, gdp));
++              ext4_corrupted_block_group(sb, group,
++                              EXT4_GROUP_INFO_BBITMAP_CORRUPT,
++                              "on-disk bitmap for group %d corrupted: %u blocks free in bitmap, %u - in gd\n",
++                              group, free, ext4_free_blks_count(sb, gdp));
+               return -EIO;
+       }
+       return 0;
+@@ -3753,14 +3773,6 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
+       /* "free < pa->pa_free" means we maybe double alloc the same blocks,
+        * otherwise maybe leave some free blocks unavailable, no need to BUG.*/
+       if ((free > pa->pa_free && !pa->pa_error) || (free < pa->pa_free)) {
+-              ext4_error(sb, "pa free mismatch: [pa %p] "
+-                              "[phy %lu] [logic %lu] [len %u] [free %u] "
+-                              "[error %u] [inode %lu] [freed %u]", pa,
+-                              (unsigned long)pa->pa_pstart,
+-                              (unsigned long)pa->pa_lstart,
+-                              (unsigned)pa->pa_len, (unsigned)pa->pa_free,
+-                              (unsigned)pa->pa_error, pa->pa_inode->i_ino,
+-                              free);
+               ext4_grp_locked_error(sb, group,
+                               __func__, "free %u, pa_free %u",
+                               free, pa->pa_free);
+@@ -3834,14 +3846,11 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
+               return 0;
+       bitmap_bh = ext4_read_block_bitmap(sb, group);
+-      if (bitmap_bh == NULL) {
+-              ext4_error(sb, "Error reading block bitmap for %u", group);
++      if (bitmap_bh == NULL)
+               return 0;
+-      }
+       err = ext4_mb_load_buddy(sb, group, &e4b);
+       if (err) {
+-              ext4_error(sb, "Error loading buddy information for %u", group);
+               put_bh(bitmap_bh);
+               return 0;
+       }
+@@ -4015,16 +4024,11 @@ repeat:
+               ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
+               err = ext4_mb_load_buddy(sb, group, &e4b);
+-              if (err) {
+-                      ext4_error(sb, "Error loading buddy information for %u",
+-                                      group);
++              if (err)
+                       return;
+-              }
+               bitmap_bh = ext4_read_block_bitmap(sb, group);
+               if (bitmap_bh == NULL) {
+-                      ext4_error(sb, "Error reading block bitmap for %u",
+-                                      group);
+                       ext4_mb_release_desc(&e4b);
+                       continue;
+               }
+@@ -4299,11 +4303,8 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
+       list_for_each_entry_safe(pa, tmp, &discard_list, u.pa_tmp_list) {
+               ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
+-              if (ext4_mb_load_buddy(sb, group, &e4b)) {
+-                      ext4_error(sb, "Error loading buddy information for %u",
+-                                      group);
++              if (ext4_mb_load_buddy(sb, group, &e4b))
+                       continue;
+-              }
+               ext4_lock_group(sb, group);
+               list_del(&pa->pa_group_list);
+               ext4_get_group_info(sb, group)->bb_prealloc_nr--;
+@@ -4565,7 +4566,7 @@ repeat:
+                        * been updated or not when fail case. So can
+                        * not revert pa_free back, just mark pa_error*/
+                       pa->pa_error++;
+-                      ext4_error(sb,
++                      ext4_corrupted_block_group(sb, 0, 0,
+                               "Updating bitmap error: [err %d] "
+                               "[pa %p] [phy %lu] [logic %lu] "
+                               "[len %u] [free %u] [error %u] "
+@@ -4710,6 +4711,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
+       struct ext4_sb_info *sbi;
+       struct ext4_buddy e4b;
+       int err = 0;
++      int skip_error = 0;
+       int ret;
+       /*
+@@ -4746,6 +4748,10 @@ do_more:
        overflow = 0;
        ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
  
@@ -220,3 +350,101 @@ index efcf909..dc88197 100644
        /*
         * Check to see if we are freeing blocks across a group
         * boundary.
+@@ -4807,8 +4813,10 @@ do_more:
+       }
+       err = ext4_mb_load_buddy(sb, block_group, &e4b);
+-      if (err)
++      if (err) {
++              skip_error = 1;
+               goto error_return;
++      }
+       if ((flags & EXT4_FREE_BLOCKS_METADATA) && ext4_handle_valid(handle)) {
+               struct ext4_free_data *new_entry;
+               /*
+@@ -4876,10 +4884,10 @@ error_return:
+       if (freed && !(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE))
+               vfs_dq_free_block(inode, freed);
+       brelse(bitmap_bh);
+-      ext4_std_error(sb, err);
++      if (!skip_error)
++              ext4_std_error(sb, err);
+       if (ac)
+               kmem_cache_free(ext4_ac_cachep, ac);
+-      return;
+ }
+ /**
+@@ -4970,7 +4978,7 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
+       err = ext4_mb_load_buddy(sb, block_group, &e4b);
+       if (err)
+-              goto error_return;
++              goto error_brelse;
+       /*
+        * need to update group_info->bb_free and bitmap
+@@ -5006,9 +5014,9 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
+       sb->s_dirt = 1;
+ error_return:
+-      brelse(bitmap_bh);
+       ext4_std_error(sb, err);
+-      return;
++error_brelse:
++      brelse(bitmap_bh);
+ }
+ /**
+@@ -5078,11 +5086,8 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+       trace_ext4_trim_all_free(sb, group, start, max);
+       ret = ext4_mb_load_buddy(sb, group, &e4b);
+-      if (ret) {
+-              ext4_error(sb, "Error in loading buddy "
+-                              "information for %u", group);
++      if (ret)
+               return ret;
+-      }
+       bitmap = e4b.bd_bitmap;
+       ext4_lock_group(sb, group);
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index 31ee33b..f02a632 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -562,6 +562,34 @@ void __ext4_warning(struct super_block *sb, const char *function,
+       va_end(args);
+ }
++void __ext4_corrupted_block_group(struct super_block *sb, ext4_group_t group,
++                                unsigned int flags)
++{
++      struct ext4_sb_info *sbi = EXT4_SB(sb);
++      struct ext4_group_info *grp = ext4_get_group_info(sb, group);
++      struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL);
++
++      if (flags & EXT4_GROUP_INFO_BBITMAP_CORRUPT &&
++          !EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) {
++              ext4_free_blks_set(sb, gdp, 0);
++              set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
++                      &grp->bb_state);
++      }
++
++      if (flags & EXT4_GROUP_INFO_IBITMAP_CORRUPT &&
++          !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
++              if (gdp) {
++                      ext4_free_inodes_set(sb, gdp, 0);
++                      ext4_itable_unused_set(sb, gdp, 0);
++              }
++              set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT,
++                      &grp->bb_state);
++      }
++      sbi->s_mount_state |= EXT4_ERROR_FS;
++      sbi->s_es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
++      ext4_commit_super(sb, 1);
++}
++
+ void ext4_grp_locked_error(struct super_block *sb, ext4_group_t grp,
+                          const char *function, const char *fmt, ...)
+ __releases(bitlock)
index d119fbc..a8b4e38 100644 (file)
@@ -3,101 +3,463 @@ 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
+index e069155..692b5e4 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,
+@@ -185,25 +185,17 @@ static int ext4_init_block_bitmap(struct super_block *sb,
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       ext4_fsblk_t start, tmp;
+       int flex_bg = 0;
+-      struct ext4_group_info *grp;
+       J_ASSERT_BH(bh, buffer_locked(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(sb, block_group, gdp)) {
+-              grp = ext4_get_group_info(sb, block_group);
+-              if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
+-                      percpu_counter_sub(&sbi->s_freeclusters_counter,
+-                                         grp->bb_free);
+-              set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
+-              if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
+-                      int count;
+-                      count = ext4_free_inodes_count(sb, gdp);
+-                      percpu_counter_sub(&sbi->s_freeinodes_counter,
+-                                         count);
+-              }
+-              set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
++              ext4_corrupted_block_group(sb, block_group,
++                              EXT4_GROUP_INFO_BBITMAP_CORRUPT |
++                              EXT4_GROUP_INFO_IBITMAP_CORRUPT,
++                              "Checksum bad for group %u",
++                              block_group);
+               return -EIO;
+       }
+       memset(bh->b_data, 0, sb->s_blocksize);
+@@ -367,8 +359,6 @@ static void ext4_validate_block_bitmap(struct super_block *sb,
+                                      struct buffer_head *bh)
+ {
+       ext4_fsblk_t    blk;
+-      struct ext4_group_info *grp = ext4_get_group_info(sb, block_group);
+-      struct ext4_sb_info *sbi = EXT4_SB(sb);
+       if (buffer_verified(bh))
+               return;
+@@ -377,22 +367,19 @@ 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,
+-                         block_group, blk);
+-              if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
+-                      percpu_counter_sub(&sbi->s_freeclusters_counter,
+-                                         grp->bb_free);
+-              set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
++              ext4_corrupted_block_group(sb, block_group,
++                              EXT4_GROUP_INFO_BBITMAP_CORRUPT,
++                              "bg %u: block %llu: invalid block bitmap",
++                              block_group, blk);
+               return;
+       }
        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)
+-              if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
+-                      percpu_counter_sub(&sbi->s_freeclusters_counter,
+-                                         grp->bb_free);
+-              set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
++              ext4_corrupted_block_group(sb, block_group,
++                              EXT4_GROUP_INFO_BBITMAP_CORRUPT,
++                              "bg %u: bad block bitmap checksum",
++                              block_group);
+               return;
+       }
+       set_buffer_verified(bh);
+@@ -445,8 +432,6 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
+               set_buffer_uptodate(bh);
                ext4_unlock_group(sb, block_group);
                unlock_buffer(bh);
-               if (err)
+-              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/ext4.h b/fs/ext4/ext4.h
+index 3c41773..63a63b6 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -91,6 +91,17 @@ typedef __u32 ext4_lblk_t;
+ /* data type for block group number */
+ typedef unsigned int ext4_group_t;
++void __ext4_corrupted_block_group(struct super_block *sb,
++                                ext4_group_t group, unsigned int flags,
++                                const char *function, unsigned int line);
++
++#define ext4_corrupted_block_group(sb, group, flags, fmt, ...)                \
++      do {                                                            \
++              __ext4_warning(sb, __func__, __LINE__, fmt,             \
++                              ##__VA_ARGS__);                         \
++              __ext4_corrupted_block_group(sb, group, flags,          \
++                                      __func__, __LINE__);            \
++      } while (0)
+ /*
+  * Flags used in mballoc's allocation_context flags field.
+  *
+@@ -2673,7 +2684,11 @@ 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_BBITMAP_CORRUPT               \
++      (1 << EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT)
+ #define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT   3
++#define EXT4_GROUP_INFO_IBITMAP_CORRUPT               \
++      (1 << EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT)
+ #define EXT4_MB_GRP_NEED_INIT(grp)    \
+       (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
-index fc65310..4936bff 100644
+index fc65310..92bcc8d 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,
+@@ -70,26 +70,15 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
+                                      ext4_group_t block_group,
+                                      struct ext4_group_desc *gdp)
+ {
+-      struct ext4_group_info *grp;
+-      struct ext4_sb_info *sbi = EXT4_SB(sb);
+       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(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:
+-              grp = ext4_get_group_info(sb, block_group);
+-              if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
+-                      percpu_counter_sub(&sbi->s_freeclusters_counter,
+-                                         grp->bb_free);
+-              set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
+-              if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
+-                      int count;
+-                      count = ext4_free_inodes_count(sb, gdp);
+-                      percpu_counter_sub(&sbi->s_freeinodes_counter,
+-                                         count);
+-              }
+-              set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
++              ext4_corrupted_block_group(sb, block_group,
++                              EXT4_GROUP_INFO_BBITMAP_CORRUPT |
++                              EXT4_GROUP_INFO_IBITMAP_CORRUPT,
++                              "Checksum bad for group %u", block_group);
+               return 0;
+       }
+@@ -125,8 +114,6 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
+       struct ext4_group_desc *desc;
+       struct buffer_head *bh = NULL;
+       ext4_fsblk_t bitmap_blk;
+-      struct ext4_group_info *grp;
+-      struct ext4_sb_info *sbi = EXT4_SB(sb);
+       desc = ext4_get_group_desc(sb, block_group, NULL);
+       if (!desc)
+@@ -193,16 +180,10 @@ 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:
+-              grp = ext4_get_group_info(sb, block_group);
+-              if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
+-                      int count;
+-                      count = ext4_free_inodes_count(sb, desc);
+-                      percpu_counter_sub(&sbi->s_freeinodes_counter,
+-                                         count);
+-              }
+-              set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
++              ext4_corrupted_block_group(sb, block_group,
++                              EXT4_GROUP_INFO_IBITMAP_CORRUPT,
++                              "Corrupt inode bitmap - block_group = %u, inode_bitmap = %llu",
++                              block_group, bitmap_blk);
+               return NULL;
+       }
+       ext4_unlock_group(sb, block_group);
+@@ -337,14 +318,9 @@ 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);
+-              if (gdp && !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
+-                      int count;
+-                      count = ext4_free_inodes_count(sb, gdp);
+-                      percpu_counter_sub(&sbi->s_freeinodes_counter,
+-                                         count);
+-              }
+-              set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
++              ext4_corrupted_block_group(sb, block_group,
++                              EXT4_GROUP_INFO_IBITMAP_CORRUPT,
++                              "bit already cleared for inode %lu", ino);
+       }
+ error_return:
 diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
-index d2b07bd..695ccd3 100644
+index 7282d07..e6805e6 100644
 --- a/fs/ext4/mballoc.c
 +++ b/fs/ext4/mballoc.c
-@@ -752,11 +752,18 @@ int ext4_mb_generate_buddy(struct super_block *sb,
+@@ -752,10 +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;
+-                      free, grp->bb_free, ext4_free_group_clusters(sb, gdp),
+-                      grp->bb_prealloc_nr);
++
++              ext4_corrupted_block_group(sb, group,
++                              EXT4_GROUP_INFO_BBITMAP_CORRUPT,
++                              "group %lu: %u blocks in bitmap, %u in bb, %u in gd, %lu pa's block bitmap corrupt",
++                              (unsigned long int)group, free, grp->bb_free,
++                              ext4_free_group_clusters(sb, gdp),
++                              grp->bb_prealloc_nr);
 +              /*
 +               * 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);
-+              
+               return -EIO;
        }
        mb_set_largest_free_order(sb, grp);
+@@ -1101,7 +1109,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
+       int block;
+       int pnum;
+       int poff;
+-      struct page *page;
++      struct page *page = NULL;
+       int ret;
+       struct ext4_group_info *grp;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+@@ -1127,7 +1135,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
+                */
+               ret = ext4_mb_init_group(sb, group);
+               if (ret)
+-                      return ret;
++                      goto err;
+       }
+       /*
+@@ -1227,6 +1235,7 @@ err:
+               page_cache_release(e4b->bd_buddy_page);
+       e4b->bd_buddy = NULL;
+       e4b->bd_bitmap = NULL;
++      ext4_warning(sb, "Error loading buddy information for %u", group);
+       return ret;
+ }
+@@ -3599,9 +3608,11 @@ int ext4_mb_check_ondisk_bitmap(struct super_block *sb, void *bitmap,
+       }
+       if (free != ext4_free_group_clusters(sb, gdp)) {
+-              ext4_error(sb, "on-disk bitmap for group %d"
+-                      "corrupted: %u blocks free in bitmap, %u - in gd\n",
+-                      group, free, ext4_free_group_clusters(sb, gdp));
++              ext4_corrupted_block_group(sb, group,
++                              EXT4_GROUP_INFO_BBITMAP_CORRUPT,
++                              "on-disk bitmap for group %d corrupted: %u blocks free in bitmap, %u - in gd\n",
++                              group, free,
++                              ext4_free_group_clusters(sb, gdp));
+               return -EIO;
+       }
+       return 0;
+@@ -3962,16 +3973,8 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
+       /* "free < pa->pa_free" means we maybe double alloc the same blocks,
+        * otherwise maybe leave some free blocks unavailable, no need to BUG.*/
+       if ((free > pa->pa_free && !pa->pa_error) || (free < pa->pa_free)) {
+-              ext4_error(sb, "pa free mismatch: [pa %p] "
+-                              "[phy %lu] [logic %lu] [len %u] [free %u] "
+-                              "[error %u] [inode %lu] [freed %u]", pa,
+-                              (unsigned long)pa->pa_pstart,
+-                              (unsigned long)pa->pa_lstart,
+-                              (unsigned)pa->pa_len, (unsigned)pa->pa_free,
+-                              (unsigned)pa->pa_error, pa->pa_inode->i_ino,
+-                              free);
+               ext4_grp_locked_error(sb, group, 0, 0, "free %u, pa_free %u",
+-                                      free, pa->pa_free);
++                                    free, pa->pa_free);
+               /*
+                * pa is already deleted so we use the value obtained
+                * from the bitmap and continue.
+@@ -4031,14 +4034,11 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
+               return 0;
+       bitmap_bh = ext4_read_block_bitmap(sb, group);
+-      if (bitmap_bh == NULL) {
+-              ext4_error(sb, "Error reading block bitmap for %u", group);
++      if (bitmap_bh == NULL)
+               return 0;
+-      }
+       err = ext4_mb_load_buddy(sb, group, &e4b);
+       if (err) {
+-              ext4_error(sb, "Error loading buddy information for %u", group);
+               put_bh(bitmap_bh);
+               return 0;
+       }
+@@ -4198,16 +4198,11 @@ repeat:
+               group = ext4_get_group_number(sb, pa->pa_pstart);
+               err = ext4_mb_load_buddy(sb, group, &e4b);
+-              if (err) {
+-                      ext4_error(sb, "Error loading buddy information for %u",
+-                                      group);
++              if (err)
+                       return;
+-              }
+               bitmap_bh = ext4_read_block_bitmap(sb, group);
+               if (bitmap_bh == NULL) {
+-                      ext4_error(sb, "Error reading block bitmap for %u",
+-                                      group);
+                       ext4_mb_unload_buddy(&e4b);
+                       continue;
+               }
+@@ -4467,11 +4462,8 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
+       list_for_each_entry_safe(pa, tmp, &discard_list, u.pa_tmp_list) {
+               group = ext4_get_group_number(sb, pa->pa_pstart);
+-              if (ext4_mb_load_buddy(sb, group, &e4b)) {
+-                      ext4_error(sb, "Error loading buddy information for %u",
+-                                      group);
++              if (ext4_mb_load_buddy(sb, group, &e4b))
+                       continue;
+-              }
+               ext4_lock_group(sb, group);
+               list_del(&pa->pa_group_list);
+               ext4_get_group_info(sb, group)->bb_prealloc_nr--;
+@@ -4742,17 +4734,18 @@ errout:
+                        * been updated or not when fail case. So can
+                        * not revert pa_free back, just mark pa_error*/
+                       pa->pa_error++;
+-                      ext4_error(sb,
+-                              "Updating bitmap error: [err %d] "
+-                              "[pa %p] [phy %lu] [logic %lu] "
+-                              "[len %u] [free %u] [error %u] "
+-                              "[inode %lu]", *errp, pa,
+-                              (unsigned long)pa->pa_pstart,
+-                              (unsigned long)pa->pa_lstart,
+-                              (unsigned)pa->pa_len,
+-                              (unsigned)pa->pa_free,
+-                              (unsigned)pa->pa_error,
+-                              pa->pa_inode ? pa->pa_inode->i_ino : 0);
++                      ext4_corrupted_block_group(sb, 0, 0,
++                                      "Updating bitmap error: [err %d] "
++                                      "[pa %p] [phy %lu] [logic %lu] "
++                                      "[len %u] [free %u] [error %u] "
++                                      "[inode %lu]", *errp, pa,
++                                      (unsigned long)pa->pa_pstart,
++                                      (unsigned long)pa->pa_lstart,
++                                      (unsigned)pa->pa_len,
++                                      (unsigned)pa->pa_free,
++                                      (unsigned)pa->pa_error,
++                                      pa->pa_inode ?
++                                      pa->pa_inode->i_ino : 0);
+               }
+       }
+       ext4_mb_release_context(ac);
+@@ -5037,7 +5030,7 @@ do_more:
+       err = ext4_mb_load_buddy(sb, block_group, &e4b);
+       if (err)
+-              goto error_return;
++              goto error_brelse;
+       if ((flags & EXT4_FREE_BLOCKS_METADATA) && ext4_handle_valid(handle)) {
+               struct ext4_free_data *new_entry;
+@@ -5119,8 +5112,9 @@ do_more:
+               goto do_more;
+       }
+ error_return:
+-      brelse(bitmap_bh);
+       ext4_std_error(sb, err);
++error_brelse:
++      brelse(bitmap_bh);
+       return;
+ }
+@@ -5216,7 +5210,7 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
+       err = ext4_mb_load_buddy(sb, block_group, &e4b);
+       if (err)
+-              goto error_return;
++              goto error_brelse;
+       /*
+        * need to update group_info->bb_free and bitmap
+@@ -5253,8 +5247,9 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
+               err = ret;
+ error_return:
+-      brelse(bitmap_bh);
+       ext4_std_error(sb, err);
++error_brelse:
++      brelse(bitmap_bh);
+       return err;
+ }
+@@ -5329,11 +5324,9 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+       trace_ext4_trim_all_free(sb, group, start, max);
+       ret = ext4_mb_load_buddy(sb, group, &e4b);
+-      if (ret) {
+-              ext4_error(sb, "Error in loading buddy "
+-                              "information for %u", group);
++      if (ret)
+               return ret;
+-      }
++
+       bitmap = e4b.bd_bitmap;
+       ext4_lock_group(sb, group);
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index c625960..0de22f2 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -633,6 +633,37 @@ void __ext4_warning(struct super_block *sb, const char *function,
+       va_end(args);
+ }
  
--- 
-1.8.3.1
-
++void __ext4_corrupted_block_group(struct super_block *sb, ext4_group_t group,
++                                unsigned int flags, const char *function,
++                                unsigned int line)
++{
++      struct ext4_sb_info *sbi = EXT4_SB(sb);
++      struct ext4_group_info *grp = ext4_get_group_info(sb, group);
++      struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL);
++
++      if (flags & EXT4_GROUP_INFO_BBITMAP_CORRUPT &&
++          !EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) {
++              percpu_counter_sub(&sbi->s_freeclusters_counter,
++                                      grp->bb_free);
++              set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
++                      &grp->bb_state);
++      }
++
++      if (flags & EXT4_GROUP_INFO_IBITMAP_CORRUPT &&
++          !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
++              if (gdp) {
++                      int count;
++
++                      count = ext4_free_inodes_count(sb, gdp);
++                      percpu_counter_sub(&sbi->s_freeinodes_counter,
++                                         count);
++              }
++              set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT,
++                      &grp->bb_state);
++      }
++      save_error_info(sb, function, line);
++}
++
+ void __ext4_grp_locked_error(const char *function, unsigned int line,
+                            struct super_block *sb, ext4_group_t grp,
+                            unsigned long ino, ext4_fsblk_t block,
index ca1a648..2f4a2a8 100644 (file)
@@ -1,68 +1,70 @@
----
- 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
+index db5b7a3..332078f 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,
+@@ -99,12 +99,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",
++                      ext4_corrupted_block_group(sb, block_group,
++                                      EXT4_GROUP_INFO_BBITMAP_CORRUPT |
++                                      EXT4_GROUP_INFO_IBITMAP_CORRUPT,
++                                      "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,
+@@ -279,8 +278,10 @@ 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);
+-                      block_group, bitmap_blk);
++      ext4_corrupted_block_group(sb, block_group,
++                                 EXT4_GROUP_INFO_BBITMAP_CORRUPT,
++                                 "Invalid block bitmap - block_group = %d, block = %llu",
++                                 block_group, bitmap_blk);
        return 0;
  }
  /**
 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
-index a18fd36..40ad66f 100644
+index a18fd36..949d7be 100644
 --- a/fs/ext4/ext4.h
 +++ b/fs/ext4/ext4.h
-@@ -2257,9 +2257,15 @@ struct ext4_group_info {
+@@ -78,6 +78,18 @@ typedef __u32 ext4_lblk_t;
+ /* data type for block group number */
+ typedef unsigned int ext4_group_t;
++void __ext4_corrupted_block_group(struct super_block *sb,
++                                ext4_group_t group, unsigned int flags,
++                                const char *function,
++                                unsigned int line);
++
++#define ext4_corrupted_block_group(sb, group, flags, fmt...)          \
++      do {                                                            \
++              __ext4_warning(sb, __func__, __LINE__, ## fmt);         \
++              __ext4_corrupted_block_group(sb, group, flags,          \
++                      __func__, __LINE__);                            \
++      } while (0)
++
+ /*
+  * Flags used in mballoc's allocation_context flags field.
+  *
+@@ -2257,9 +2269,19 @@ 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_BBITMAP_CORRUPT               \
++              (1 << EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT)
 +#define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT   3
++#define EXT4_GROUP_INFO_IBITMAP_CORRUPT               \
++              (1 << EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT)
  
  #define EXT4_MB_GRP_NEED_INIT(grp)    \
        (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
@@ -74,17 +76,10 @@ index a18fd36..40ad66f 100644
  #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
+index 532dcaa..6082e54 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));
+@@ -78,11 +78,10 @@ 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(sbi, block_group, gdp)) {
@@ -93,14 +88,14 @@ index 532dcaa..c9e6b19 100644
 -              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);
++              ext4_corrupted_block_group(sb, block_group,
++                              EXT4_GROUP_INFO_BBITMAP_CORRUPT |
++                              EXT4_GROUP_INFO_IBITMAP_CORRUPT,
++                              "Checksum bad for group %u", block_group);
                return 0;
        }
  
-@@ -195,6 +195,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
+@@ -195,6 +194,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;
@@ -108,7 +103,7 @@ index 532dcaa..c9e6b19 100644
  
        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)
+@@ -238,7 +238,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);
@@ -119,20 +114,22 @@ index 532dcaa..c9e6b19 100644
                goto error_return;
  
        BUFFER_TRACE(bitmap_bh, "get_write_access");
-@@ -286,8 +289,10 @@ out:
+@@ -286,8 +288,12 @@ 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);
++              ext4_corrupted_block_group(sb, block_group,
++                              EXT4_GROUP_INFO_IBITMAP_CORRUPT,
++                              "bit already cleared for inode %lu",
++                              ino);
 +      }
  
  error_return:
        brelse(bitmap_bh);
-@@ -820,6 +825,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode,
+@@ -820,6 +826,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;
@@ -140,7 +137,7 @@ index 532dcaa..c9e6b19 100644
  
        /* Cannot create files in a deleted directory */
        if (!dir || !dir->i_nlink)
-@@ -879,10 +885,21 @@ got_group:
+@@ -879,10 +886,21 @@ got_group:
                if (!gdp)
                        goto fail;
  
@@ -165,10 +162,45 @@ index 532dcaa..c9e6b19 100644
  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
+index 1d77581..4d6558e 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,
+@@ -740,7 +740,6 @@ int ext4_mb_generate_buddy(struct super_block *sb,
+                                     "%u blocks in bitmap, %u in bb, %u in gd",
+                                     free, grp->bb_free,
+                                     ext4_free_blks_count(sb, gdp));
+-
+               /*
+                * If we intent to continue, we consider group descritor
+                * corrupt and update bb_free using bitmap value
+@@ -1124,7 +1123,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
+       int block;
+       int pnum;
+       int poff;
+-      struct page *page;
++      struct page *page = NULL;
+       int ret;
+       struct ext4_group_info *grp;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+@@ -1149,7 +1148,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
+                */
+               ret = ext4_mb_init_group(sb, group);
+               if (ret)
+-                      return ret;
++                      goto err;
+       }
+       /*
+@@ -1233,6 +1232,8 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
+       return 0;
+ err:
++      ext4_warning(sb, "Error in loading buddy information for %u",
++                      group);
+       if (page)
+               page_cache_release(page);
+       if (e4b->bd_bitmap_page)
+@@ -1322,6 +1323,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));
@@ -179,20 +211,7 @@ index 1d77581..d19d1ba 100644
        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,
+@@ -1729,6 +1734,11 @@ int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
        if (err)
                return err;
  
@@ -204,7 +223,7 @@ index 1d77581..d19d1ba 100644
        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,
+@@ -1940,6 +1950,9 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
  
        BUG_ON(cr < 0 || cr >= 4);
  
@@ -214,7 +233,106 @@ index 1d77581..d19d1ba 100644
        /* 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:
+@@ -3458,9 +3471,11 @@ int ext4_mb_check_ondisk_bitmap(struct super_block *sb, void *bitmap,
+       }
+       if (free != ext4_free_blks_count(sb, gdp)) {
+-              ext4_error(sb, "on-disk bitmap for group %d"
+-                      "corrupted: %u blocks free in bitmap, %u - in gd\n",
+-                      group, free, ext4_free_blks_count(sb, gdp));
++              ext4_corrupted_block_group(sb, group,
++                              EXT4_GROUP_INFO_BBITMAP_CORRUPT,
++                              "on-disk bitmap for group %d corrupted: %u blocks free in bitmap, %u - in gd\n",
++                              group, free,
++                              ext4_free_blks_count(sb, gdp));
+               return -EIO;
+       }
+       return 0;
+@@ -3813,17 +3828,9 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
+       /* "free < pa->pa_free" means we maybe double alloc the same blocks,
+        * otherwise maybe leave some free blocks unavailable, no need to BUG.*/
+       if ((free > pa->pa_free && !pa->pa_error) || (free < pa->pa_free)) {
+-              ext4_error(sb, "pa free mismatch: [pa %p] "
+-                              "[phy %lu] [logic %lu] [len %u] [free %u] "
+-                              "[error %u] [inode %lu] [freed %u]", pa,
+-                              (unsigned long)pa->pa_pstart,
+-                              (unsigned long)pa->pa_lstart,
+-                              (unsigned)pa->pa_len, (unsigned)pa->pa_free,
+-                              (unsigned)pa->pa_error, pa->pa_inode->i_ino,
+-                              free);
+               ext4_grp_locked_error(sb, group, 0, 0,
+-                                      "free %u, pa_free %u",
+-                                      free, pa->pa_free);
++                                    "free %u, pa_free %u",
++                                    free, pa->pa_free);
+               /*
+                * pa is already deleted so we use the value obtained
+                * from the bitmap and continue.
+@@ -3883,14 +3890,11 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
+               return 0;
+       bitmap_bh = ext4_read_block_bitmap(sb, group);
+-      if (bitmap_bh == NULL) {
+-              ext4_error(sb, "Error reading block bitmap for %u", group);
++      if (bitmap_bh == NULL)
+               return 0;
+-      }
+       err = ext4_mb_load_buddy(sb, group, &e4b);
+       if (err) {
+-              ext4_error(sb, "Error loading buddy information for %u", group);
+               put_bh(bitmap_bh);
+               return 0;
+       }
+@@ -4054,16 +4058,11 @@ repeat:
+               ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
+               err = ext4_mb_load_buddy(sb, group, &e4b);
+-              if (err) {
+-                      ext4_error(sb, "Error loading buddy information for %u",
+-                                      group);
++              if (err)
+                       return;
+-              }
+               bitmap_bh = ext4_read_block_bitmap(sb, group);
+               if (bitmap_bh == NULL) {
+-                      ext4_error(sb, "Error reading block bitmap for %u",
+-                                      group);
+                       ext4_mb_unload_buddy(&e4b);
+                       continue;
+               }
+@@ -4324,11 +4323,8 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
+       list_for_each_entry_safe(pa, tmp, &discard_list, u.pa_tmp_list) {
+               ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
+-              if (ext4_mb_load_buddy(sb, group, &e4b)) {
+-                      ext4_error(sb, "Error loading buddy information for %u",
+-                                      group);
++              if (ext4_mb_load_buddy(sb, group, &e4b))
+                       continue;
+-              }
+               ext4_lock_group(sb, group);
+               list_del(&pa->pa_group_list);
+               ext4_get_group_info(sb, group)->bb_prealloc_nr--;
+@@ -4585,7 +4581,7 @@ repeat:
+                       * been updated or not when fail case. So can
+                       * not revert pa_free back, just mark pa_error*/
+                       pa->pa_error++;
+-                      ext4_error(sb,
++                      ext4_corrupted_block_group(sb, 0, 0,
+                               "Updating bitmap error: [err %d] "
+                               "[pa %p] [phy %lu] [logic %lu] "
+                               "[len %u] [free %u] [error %u] "
+@@ -4731,6 +4727,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
+       struct ext4_buddy e4b;
+       int err = 0;
+       int ret;
++      int skip_error = 0;
+       if (bh) {
+               if (block)
+@@ -4781,6 +4778,10 @@ do_more:
        overflow = 0;
        ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
  
@@ -225,6 +343,96 @@ index 1d77581..d19d1ba 100644
        /*
         * Check to see if we are freeing blocks across a group
         * boundary.
--- 
-1.7.1
-
+@@ -4837,8 +4838,10 @@ do_more:
+       trace_ext4_mballoc_free(sb, inode, block_group, bit, count);
+       err = ext4_mb_load_buddy(sb, block_group, &e4b);
+-      if (err)
++      if (err) {
++              skip_error = 1;
+               goto error_return;
++      }
+       if ((flags & EXT4_FREE_BLOCKS_METADATA) && ext4_handle_valid(handle)) {
+               struct ext4_free_data *new_entry;
+@@ -4905,8 +4908,9 @@ do_more:
+ error_return:
+       if (freed && !(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE))
+               dquot_free_block(inode, freed);
++      if (!skip_error)
++              ext4_std_error(sb, err);
+       brelse(bitmap_bh);
+-      ext4_std_error(sb, err);
+       return;
+ }
+@@ -4991,7 +4995,7 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
+       err = ext4_mb_load_buddy(sb, block_group, &e4b);
+       if (err)
+-              goto error_return;
++              goto error_brelse;
+       /*
+        * need to update group_info->bb_free and bitmap
+@@ -5026,8 +5030,9 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
+               err = ret;
+ error_return:
+-      brelse(bitmap_bh);
+       ext4_std_error(sb, err);
++error_brelse:
++      brelse(bitmap_bh);
+       return;
+ }
+@@ -5094,11 +5099,8 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+       int ret;
+       ret = ext4_mb_load_buddy(sb, group, &e4b);
+-      if (ret) {
+-              ext4_error(sb, "Error in loading buddy "
+-                              "information for %u", group);
++      if (ret)
+               return ret;
+-      }
+       bitmap = e4b.bd_bitmap;
+       ext4_lock_group(sb, group);
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index a21e903..2fca810 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -666,6 +666,32 @@ void __ext4_warning(struct super_block *sb, const char *function,
+       va_end(args);
+ }
++void __ext4_corrupted_block_group(struct super_block *sb, ext4_group_t group,
++                                unsigned int flags, const char *function,
++                                unsigned int line)
++{
++      struct ext4_group_info *grp = ext4_get_group_info(sb, group);
++      struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL);
++
++      if (flags & EXT4_GROUP_INFO_BBITMAP_CORRUPT &&
++          !EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) {
++              ext4_free_blks_set(sb, gdp, 0);
++              set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
++                      &grp->bb_state);
++      }
++
++      if (flags & EXT4_GROUP_INFO_IBITMAP_CORRUPT &&
++          !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
++              if (gdp) {
++                      ext4_free_inodes_set(sb, gdp, 0);
++                      ext4_itable_unused_set(sb, gdp, 0);
++              }
++              set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT,
++                      &grp->bb_state);
++      }
++      save_error_info(sb, function, line);
++}
++
+ void __ext4_grp_locked_error(const char *function, unsigned int line,
+                            struct super_block *sb, ext4_group_t grp,
+                            unsigned long ino, ext4_fsblk_t block,
index 568162f..9b67ab5 100644 (file)
@@ -44,4 +44,5 @@ rhel6.3/ext4-not-discard-preallocation-umount.patch
 rhel6.3/ext4-journal-path-opt.patch
 rhel6.3/ext4-drop-inode-from-orphan-list-if-ext4_delete_inode-fails.patch
 rhel6.6/ext4-remove-truncate-warning.patch
+rhel6.6/ext4-corrupted-inode-block-bitmaps-handling-patches.patch
 rhel6.3/ext4-notalloc_under_idatasem.patch