From: Wang Shilong Date: Sat, 11 Jul 2015 03:49:55 +0000 (+0800) Subject: LU-1026 ldiskfs: make bitmaps corruption not fatal X-Git-Tag: 2.7.64~4 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=e727c383db8b2485d9e6137895136699d57ea047 LU-1026 ldiskfs: make bitmaps corruption not fatal 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 Change-Id: Iabb6ebf719d80d9ba4f41bee0b237e304212832b Reviewed-on: http://review.whamcloud.com/16679 Tested-by: Jenkins Reviewed-by: Bob Glossman Tested-by: Maloo Reviewed-by: Yang Sheng Reviewed-by: Oleg Drokin --- 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 index 7c64193..8ab3de5 100644 --- 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 @@ -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) 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 index d119fbc..a8b4e38 100644 --- 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 @@ -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, 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 index ca1a648..2f4a2a8 100644 --- 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 @@ -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, diff --git a/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.6.series b/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.6.series index 568162f..9b67ab5 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.6.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.6.series @@ -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