Whamcloud - gitweb
LU-7114 ldiskfs: corrupted bitmaps handling patches 12/16312/2
authorWang Shilong <wshilong@ddn.com>
Tue, 8 Sep 2015 13:54:29 +0000 (21:54 +0800)
committerOleg Drokin <oleg.drokin@intel.com>
Wed, 16 Sep 2015 01:07:44 +0000 (01:07 +0000)
This patch backported following patches from upstream:

163a203ddb36c36d4a1c942aececda0cc8d06aa7
ext4: mark block group as corrupt on block bitmap error

87a39389be3e3b007d341be510a7e4a0542bdf05
ext4: mark block group as corrupt on inode bitmap error

bdfb6ff4a255dcebeb09a901250e13a97eff75af
ext4: mark group corrupt on group descriptor checksum

Also use ext4_warning() instead of ext4_error() so that
filesystem don't become RO in default, and together
with these patches,FS wil still be usable even such
bad things happen.

Signed-off-by: Wang Shilong <wshilong@ddn.com>
Change-Id: Ib4075aba7df6f7f59e89a90475405080acd43dd0
Reviewed-on: http://review.whamcloud.com/16312
Tested-by: Jenkins
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: Yang Sheng <yang.sheng@intel.com>
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
ldiskfs/kernel_patches/patches/rhel6.6/ext4-corrupted-inode-block-bitmaps-handling-patches.patch [new file with mode: 0644]
ldiskfs/kernel_patches/patches/rhel7/ext4-corrupted-inode-block-bitmaps-handling-patches.patch [new file with mode: 0644]
ldiskfs/kernel_patches/patches/sles11sp2/ext4-corrupted-inode-block-bitmaps-handling-patches.patch [new file with mode: 0644]
ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.7.series
ldiskfs/kernel_patches/series/ldiskfs-3.0-sles11sp3.series
ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.series

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