Android-x86
Fork
Donation

  • R/O
  • HTTP
  • SSH
  • HTTPS

kernel: Commit

kernel


Commit MetaInfo

Revisionabfcb33ca386374b7782a2a90dcac54cf538eba0 (tree)
Time2017-06-07 16:31:48
AuthorWang Shilong <wshilong@ddn....>
CommiterChih-Wei Huang

Log Message

HACK: ext4: make bitmap corruption not fatal

There can be occasional reasons for bitmap problems, which are
detected by ext4_mb_check_ondisk_bitmap() and cause the
filesystem to be remounted read-only due to ext4_error():

EXT4-fs error (device /dev/dm-6-8): ext4_mb_generate_buddy:755:
group 294, block 0: block bitmap and bg descriptor inconsistent:
20180 vs 20181 free clusters
Aborting journal on device dm-6-8.
EXT4-fs (dm-6): Remounting filesystem read-only

This might be caused by some ext4 internal bugs, which are addressed
separately. This patch makes ext4 more robust by the following changes:

- ext4_read_block_bitmap() printed error, so do not call ext4_error() again
- mark all bits in bitmap used so that it will not be used for allocation
- mark block group corrupt, use ext4_warning() instead of ext4_error()

Tested by following script:

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

mkdir -p $TEST_MNT
mkfs.ext4 -F $TEST_DEV

mount -t ext4 $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 oflag=direct bs=4096 seek=641 count=10
mount -t ext4 $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"

umount $TEST_MNT
e2fsck $TEST_DEV -y

Signed-off-by: Wang Shilong <wshilong@ddn.com>
Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-1026
Reviewed-on: http://review.whamcloud.com/16679
Reviewed-by: Bob Glossman <bob.glossman@intel.com>
Reviewed-by: Yang Sheng <yang.sheng@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>

Change Summary

Incremental Difference

--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -184,25 +184,17 @@ static int ext4_init_block_bitmap(struct super_block *sb,
184184 struct ext4_sb_info *sbi = EXT4_SB(sb);
185185 ext4_fsblk_t start, tmp;
186186 int flex_bg = 0;
187- struct ext4_group_info *grp;
188187
189188 J_ASSERT_BH(bh, buffer_locked(bh));
190189
191190 /* If checksum is bad mark all blocks used to prevent allocation
192191 * essentially implementing a per-group read-only flag. */
193192 if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
194- grp = ext4_get_group_info(sb, block_group);
195- if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
196- percpu_counter_sub(&sbi->s_freeclusters_counter,
197- grp->bb_free);
198- set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
199- if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
200- int count;
201- count = ext4_free_inodes_count(sb, gdp);
202- percpu_counter_sub(&sbi->s_freeinodes_counter,
203- count);
204- }
205- set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
193+ ext4_corrupted_block_group(sb, block_group,
194+ EXT4_GROUP_INFO_BBITMAP_CORRUPT |
195+ EXT4_GROUP_INFO_IBITMAP_CORRUPT,
196+ "Checksum bad for group %u",
197+ block_group);
206198 return -EFSBADCRC;
207199 }
208200 memset(bh->b_data, 0, sb->s_blocksize);
@@ -381,23 +373,20 @@ static int ext4_validate_block_bitmap(struct super_block *sb,
381373 if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group,
382374 desc, bh))) {
383375 ext4_unlock_group(sb, block_group);
384- ext4_error(sb, "bg %u: bad block bitmap checksum", block_group);
385- if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
386- percpu_counter_sub(&sbi->s_freeclusters_counter,
387- grp->bb_free);
388- set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
389- return -EFSBADCRC;
376+ ext4_corrupted_block_group(sb, block_group,
377+ EXT4_GROUP_INFO_BBITMAP_CORRUPT,
378+ "bg %u: bad block bitmap checksum",
379+ block_group);
380+ return 0;
390381 }
391382 blk = ext4_valid_block_bitmap(sb, desc, block_group, bh);
392383 if (unlikely(blk != 0)) {
393384 ext4_unlock_group(sb, block_group);
394- ext4_error(sb, "bg %u: block %llu: invalid block bitmap",
395- block_group, blk);
396- if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
397- percpu_counter_sub(&sbi->s_freeclusters_counter,
398- grp->bb_free);
399- set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
400- return -EFSCORRUPTED;
385+ ext4_corrupted_block_group(sb, block_group,
386+ EXT4_GROUP_INFO_BBITMAP_CORRUPT,
387+ "bg %u: block %llu: invalid block bitmap",
388+ block_group, blk);
389+ return 0;
401390 }
402391 set_buffer_verified(bh);
403392 ext4_unlock_group(sb, block_group);
@@ -449,11 +438,6 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
449438 set_buffer_uptodate(bh);
450439 ext4_unlock_group(sb, block_group);
451440 unlock_buffer(bh);
452- if (err) {
453- ext4_error(sb, "Failed to init block bitmap for group "
454- "%u: %d", block_group, err);
455- goto out;
456- }
457441 goto verify;
458442 }
459443 ext4_unlock_group(sb, block_group);
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -96,6 +96,18 @@ typedef __u32 ext4_lblk_t;
9696 /* data type for block group number */
9797 typedef unsigned int ext4_group_t;
9898
99+void __ext4_corrupted_block_group(struct super_block *sb,
100+ ext4_group_t group, unsigned int flags,
101+ const char *function, unsigned int line);
102+
103+#define ext4_corrupted_block_group(sb, group, flags, fmt, ...) \
104+ do { \
105+ __ext4_warning(sb, __func__, __LINE__, fmt, \
106+ ##__VA_ARGS__); \
107+ __ext4_corrupted_block_group(sb, group, flags, \
108+ __func__, __LINE__); \
109+ } while (0)
110+
99111 enum SHIFT_DIRECTION {
100112 SHIFT_LEFT = 0,
101113 SHIFT_RIGHT,
@@ -2897,7 +2909,11 @@ struct ext4_group_info {
28972909 #define EXT4_GROUP_INFO_NEED_INIT_BIT 0
28982910 #define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1
28992911 #define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT 2
2912+#define EXT4_GROUP_INFO_BBITMAP_CORRUPT \
2913+ (1 << EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT)
29002914 #define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT 3
2915+#define EXT4_GROUP_INFO_IBITMAP_CORRUPT \
2916+ (1 << EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT)
29012917
29022918 #define EXT4_MB_GRP_NEED_INIT(grp) \
29032919 (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -69,26 +69,16 @@ static int ext4_init_inode_bitmap(struct super_block *sb,
6969 ext4_group_t block_group,
7070 struct ext4_group_desc *gdp)
7171 {
72- struct ext4_group_info *grp;
73- struct ext4_sb_info *sbi = EXT4_SB(sb);
7472 J_ASSERT_BH(bh, buffer_locked(bh));
7573
7674 /* If checksum is bad mark all blocks and inodes use to prevent
7775 * allocation, essentially implementing a per-group read-only flag. */
7876 if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
79- grp = ext4_get_group_info(sb, block_group);
80- if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
81- percpu_counter_sub(&sbi->s_freeclusters_counter,
82- grp->bb_free);
83- set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
84- if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
85- int count;
86- count = ext4_free_inodes_count(sb, gdp);
87- percpu_counter_sub(&sbi->s_freeinodes_counter,
88- count);
89- }
90- set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
91- return -EFSBADCRC;
77+ ext4_corrupted_block_group(sb, block_group,
78+ EXT4_GROUP_INFO_BBITMAP_CORRUPT |
79+ EXT4_GROUP_INFO_IBITMAP_CORRUPT,
80+ "Checksum bad for group %u", block_group);
81+ return 0;
9282 }
9383
9484 memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
@@ -130,17 +120,11 @@ static int ext4_validate_inode_bitmap(struct super_block *sb,
130120 if (!ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh,
131121 EXT4_INODES_PER_GROUP(sb) / 8)) {
132122 ext4_unlock_group(sb, block_group);
133- ext4_error(sb, "Corrupt inode bitmap - block_group = %u, "
134- "inode_bitmap = %llu", block_group, blk);
135- grp = ext4_get_group_info(sb, block_group);
136- if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
137- int count;
138- count = ext4_free_inodes_count(sb, desc);
139- percpu_counter_sub(&sbi->s_freeinodes_counter,
140- count);
141- }
142- set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
143- return -EFSBADCRC;
123+ ext4_corrupted_block_group(sb, block_group,
124+ EXT4_GROUP_INFO_IBITMAP_CORRUPT,
125+ "Corrupt inode bitmap - block_group = %u, inode_bitmap = %llu",
126+ block_group, blk);
127+ return 0;
144128 }
145129 set_buffer_verified(bh);
146130 ext4_unlock_group(sb, block_group);
@@ -368,14 +352,9 @@ out:
368352 if (!fatal)
369353 fatal = err;
370354 } else {
371- ext4_error(sb, "bit already cleared for inode %lu", ino);
372- if (gdp && !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
373- int count;
374- count = ext4_free_inodes_count(sb, gdp);
375- percpu_counter_sub(&sbi->s_freeinodes_counter,
376- count);
377- }
378- set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
355+ ext4_corrupted_block_group(sb, block_group,
356+ EXT4_GROUP_INFO_IBITMAP_CORRUPT,
357+ "bit already cleared for inode %lu", ino);
379358 }
380359
381360 error_return:
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -1116,7 +1116,7 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
11161116 int block;
11171117 int pnum;
11181118 int poff;
1119- struct page *page;
1119+ struct page *page = NULL;
11201120 int ret;
11211121 struct ext4_group_info *grp;
11221122 struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -1142,7 +1142,7 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
11421142 */
11431143 ret = ext4_mb_init_group(sb, group, gfp);
11441144 if (ret)
1145- return ret;
1145+ goto err;
11461146 }
11471147
11481148 /*
@@ -1245,6 +1245,7 @@ err:
12451245 put_page(e4b->bd_buddy_page);
12461246 e4b->bd_buddy = NULL;
12471247 e4b->bd_bitmap = NULL;
1248+ ext4_warning(sb, "Error loading buddy information for %u", group);
12481249 return ret;
12491250 }
12501251
@@ -3861,14 +3862,14 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
38613862 bitmap_bh = ext4_read_block_bitmap(sb, group);
38623863 if (IS_ERR(bitmap_bh)) {
38633864 err = PTR_ERR(bitmap_bh);
3864- ext4_error(sb, "Error %d reading block bitmap for %u",
3865+ ext4_warning(sb, "Error %d reading block bitmap for %u",
38653866 err, group);
38663867 return 0;
38673868 }
38683869
38693870 err = ext4_mb_load_buddy(sb, group, &e4b);
38703871 if (err) {
3871- ext4_error(sb, "Error loading buddy information for %u", group);
3872+ ext4_warning(sb, "Error loading buddy information for %u", group);
38723873 put_bh(bitmap_bh);
38733874 return 0;
38743875 }
@@ -4027,7 +4028,7 @@ repeat:
40274028
40284029 err = ext4_mb_load_buddy(sb, group, &e4b);
40294030 if (err) {
4030- ext4_error(sb, "Error loading buddy information for %u",
4031+ ext4_warning(sb, "Error loading buddy information for %u",
40314032 group);
40324033 continue;
40334034 }
@@ -4035,7 +4036,7 @@ repeat:
40354036 bitmap_bh = ext4_read_block_bitmap(sb, group);
40364037 if (IS_ERR(bitmap_bh)) {
40374038 err = PTR_ERR(bitmap_bh);
4038- ext4_error(sb, "Error %d reading block bitmap for %u",
4039+ ext4_warning(sb, "Error %d reading block bitmap for %u",
40394040 err, group);
40404041 ext4_mb_unload_buddy(&e4b);
40414042 continue;
@@ -4287,7 +4288,7 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
42874288
42884289 group = ext4_get_group_number(sb, pa->pa_pstart);
42894290 if (ext4_mb_load_buddy(sb, group, &e4b)) {
4290- ext4_error(sb, "Error loading buddy information for %u",
4291+ ext4_warning(sb, "Error loading buddy information for %u",
42914292 group);
42924293 continue;
42934294 }
@@ -4815,7 +4816,7 @@ do_more:
48154816 err = ext4_mb_load_buddy_gfp(sb, block_group, &e4b,
48164817 GFP_NOFS|__GFP_NOFAIL);
48174818 if (err)
4818- goto error_return;
4819+ goto error_brelse;
48194820
48204821 /*
48214822 * We need to make sure we don't reuse the freed block until after the
@@ -4896,8 +4897,9 @@ do_more:
48964897 goto do_more;
48974898 }
48984899 error_return:
4899- brelse(bitmap_bh);
49004900 ext4_std_error(sb, err);
4901+error_brelse:
4902+ brelse(bitmap_bh);
49014903 return;
49024904 }
49034905
@@ -4994,7 +4996,7 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
49944996
49954997 err = ext4_mb_load_buddy(sb, block_group, &e4b);
49964998 if (err)
4997- goto error_return;
4999+ goto error_brelse;
49985000
49995001 /*
50005002 * need to update group_info->bb_free and bitmap
@@ -5031,8 +5033,9 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
50315033 err = ret;
50325034
50335035 error_return:
5034- brelse(bitmap_bh);
50355036 ext4_std_error(sb, err);
5037+error_brelse:
5038+ brelse(bitmap_bh);
50365039 return err;
50375040 }
50385041
@@ -5108,7 +5111,7 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
51085111
51095112 ret = ext4_mb_load_buddy(sb, group, &e4b);
51105113 if (ret) {
5111- ext4_error(sb, "Error in loading buddy "
5114+ ext4_warning(sb, "Error in loading buddy "
51125115 "information for %u", group);
51135116 return ret;
51145117 }
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -684,6 +684,37 @@ void __ext4_warning_inode(const struct inode *inode, const char *function,
684684 va_end(args);
685685 }
686686
687+void __ext4_corrupted_block_group(struct super_block *sb, ext4_group_t group,
688+ unsigned int flags, const char *function,
689+ unsigned int line)
690+{
691+ struct ext4_sb_info *sbi = EXT4_SB(sb);
692+ struct ext4_group_info *grp = ext4_get_group_info(sb, group);
693+ struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL);
694+
695+ if (flags & EXT4_GROUP_INFO_BBITMAP_CORRUPT &&
696+ !EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) {
697+ percpu_counter_sub(&sbi->s_freeclusters_counter,
698+ grp->bb_free);
699+ set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
700+ &grp->bb_state);
701+ }
702+
703+ if (flags & EXT4_GROUP_INFO_IBITMAP_CORRUPT &&
704+ !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
705+ if (gdp) {
706+ int count;
707+
708+ count = ext4_free_inodes_count(sb, gdp);
709+ percpu_counter_sub(&sbi->s_freeinodes_counter,
710+ count);
711+ }
712+ set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT,
713+ &grp->bb_state);
714+ }
715+ save_error_info(sb, function, line);
716+}
717+
687718 void __ext4_grp_locked_error(const char *function, unsigned int line,
688719 struct super_block *sb, ext4_group_t grp,
689720 unsigned long ino, ext4_fsblk_t block,
Show on old repository browser