Commit f9ae9cf5 authored by Theodore Ts'o's avatar Theodore Ts'o

ext4: revert commit which was causing fs corruption after journal replays

Commit 00764937 ("ext4: initialize multi-block allocator before
checking block descriptors") causes the block group descriptor's count
of the number of free blocks to become inconsistent with the number of
free blocks in the allocation bitmap.  This is a harmless form of fs
corruption, but it causes the kernel to potentially remount the file
system read-only, or to panic, depending on the file systems's error
behavior.

Thanks to Eric Whitney for his tireless work to reproduce and to find
the guilty commit.

Fixes: 00764937 ("ext4: initialize multi-block allocator before checking block descriptors"

Cc: stable@vger.kernel.org  # 3.15
Reported-by: default avatarDavid Jander <david@protonic.nl>
Reported-by: default avatarMatteo Croce <technoboy85@gmail.com>
Tested-by: default avatarEric Whitney <enwlinux@gmail.com>
Suggested-by: default avatarEric Whitney <enwlinux@gmail.com>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 5dd21424
...@@ -3879,38 +3879,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -3879,38 +3879,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
goto failed_mount2; goto failed_mount2;
} }
} }
/*
* set up enough so that it can read an inode,
* and create new inode for buddy allocator
*/
sbi->s_gdb_count = db_count;
if (!test_opt(sb, NOLOAD) &&
EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL))
sb->s_op = &ext4_sops;
else
sb->s_op = &ext4_nojournal_sops;
ext4_ext_init(sb);
err = ext4_mb_init(sb);
if (err) {
ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)",
err);
goto failed_mount2;
}
if (!ext4_check_descriptors(sb, &first_not_zeroed)) { if (!ext4_check_descriptors(sb, &first_not_zeroed)) {
ext4_msg(sb, KERN_ERR, "group descriptors corrupted!"); ext4_msg(sb, KERN_ERR, "group descriptors corrupted!");
goto failed_mount2a; goto failed_mount2;
} }
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
if (!ext4_fill_flex_info(sb)) { if (!ext4_fill_flex_info(sb)) {
ext4_msg(sb, KERN_ERR, ext4_msg(sb, KERN_ERR,
"unable to initialize " "unable to initialize "
"flex_bg meta info!"); "flex_bg meta info!");
goto failed_mount2a; goto failed_mount2;
} }
sbi->s_gdb_count = db_count;
get_random_bytes(&sbi->s_next_generation, sizeof(u32)); get_random_bytes(&sbi->s_next_generation, sizeof(u32));
spin_lock_init(&sbi->s_next_gen_lock); spin_lock_init(&sbi->s_next_gen_lock);
...@@ -3945,6 +3926,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -3945,6 +3926,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
sbi->s_stripe = ext4_get_stripe_size(sbi); sbi->s_stripe = ext4_get_stripe_size(sbi);
sbi->s_extent_max_zeroout_kb = 32; sbi->s_extent_max_zeroout_kb = 32;
/*
* set up enough so that it can read an inode
*/
if (!test_opt(sb, NOLOAD) &&
EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL))
sb->s_op = &ext4_sops;
else
sb->s_op = &ext4_nojournal_sops;
sb->s_export_op = &ext4_export_ops; sb->s_export_op = &ext4_export_ops;
sb->s_xattr = ext4_xattr_handlers; sb->s_xattr = ext4_xattr_handlers;
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA
...@@ -4134,13 +4123,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -4134,13 +4123,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
if (err) { if (err) {
ext4_msg(sb, KERN_ERR, "failed to reserve %llu clusters for " ext4_msg(sb, KERN_ERR, "failed to reserve %llu clusters for "
"reserved pool", ext4_calculate_resv_clusters(sb)); "reserved pool", ext4_calculate_resv_clusters(sb));
goto failed_mount5; goto failed_mount4a;
} }
err = ext4_setup_system_zone(sb); err = ext4_setup_system_zone(sb);
if (err) { if (err) {
ext4_msg(sb, KERN_ERR, "failed to initialize system " ext4_msg(sb, KERN_ERR, "failed to initialize system "
"zone (%d)", err); "zone (%d)", err);
goto failed_mount4a;
}
ext4_ext_init(sb);
err = ext4_mb_init(sb);
if (err) {
ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)",
err);
goto failed_mount5; goto failed_mount5;
} }
...@@ -4217,8 +4214,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -4217,8 +4214,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
failed_mount7: failed_mount7:
ext4_unregister_li_request(sb); ext4_unregister_li_request(sb);
failed_mount6: failed_mount6:
ext4_release_system_zone(sb); ext4_mb_release(sb);
failed_mount5: failed_mount5:
ext4_ext_release(sb);
ext4_release_system_zone(sb);
failed_mount4a:
dput(sb->s_root); dput(sb->s_root);
sb->s_root = NULL; sb->s_root = NULL;
failed_mount4: failed_mount4:
...@@ -4242,14 +4242,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -4242,14 +4242,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
percpu_counter_destroy(&sbi->s_extent_cache_cnt); percpu_counter_destroy(&sbi->s_extent_cache_cnt);
if (sbi->s_mmp_tsk) if (sbi->s_mmp_tsk)
kthread_stop(sbi->s_mmp_tsk); kthread_stop(sbi->s_mmp_tsk);
failed_mount2a:
ext4_mb_release(sb);
failed_mount2: failed_mount2:
for (i = 0; i < db_count; i++) for (i = 0; i < db_count; i++)
brelse(sbi->s_group_desc[i]); brelse(sbi->s_group_desc[i]);
ext4_kvfree(sbi->s_group_desc); ext4_kvfree(sbi->s_group_desc);
failed_mount: failed_mount:
ext4_ext_release(sb);
if (sbi->s_chksum_driver) if (sbi->s_chksum_driver)
crypto_free_shash(sbi->s_chksum_driver); crypto_free_shash(sbi->s_chksum_driver);
if (sbi->s_proc) { if (sbi->s_proc) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment