Skip to content

Commit

Permalink
Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/tytso/ext4

Pull ext4 bugfixes from Ted Ts'o:
 "More bug fixes for ext4 -- most importantly, a fix for a bug
  introduced in 3.15 that can end up triggering a file system corruption
  error after a journal replay.

  It shouldn't lead to any actual data corruption, but it is scary and
  can force file systems to be remounted read-only, etc"

* tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: fix potential null pointer dereference in ext4_free_inode
  ext4: fix a potential deadlock in __ext4_es_shrink()
  ext4: revert commit which was causing fs corruption after journal replays
  ext4: disable synchronous transaction batching if max_batch_time==0
  ext4: clarify ext4_error message in ext4_mb_generate_buddy_error()
  ext4: clarify error count warning messages
  ext4: fix unjournalled bg descriptor while initializing inode bitmap
  • Loading branch information
Linus Torvalds committed Jul 13, 2014
2 parents 502fde1 + bf40c92 commit 18b34d9
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 45 deletions.
4 changes: 2 additions & 2 deletions fs/ext4/extents_status.c
Original file line number Diff line number Diff line change
Expand Up @@ -966,10 +966,10 @@ static int __ext4_es_shrink(struct ext4_sb_info *sbi, int nr_to_scan,
continue;
}

if (ei->i_es_lru_nr == 0 || ei == locked_ei)
if (ei->i_es_lru_nr == 0 || ei == locked_ei ||
!write_trylock(&ei->i_es_lock))
continue;

write_lock(&ei->i_es_lock);
shrunk = __es_try_to_reclaim_extents(ei, nr_to_scan);
if (ei->i_es_lru_nr == 0)
list_del_init(&ei->i_es_lru);
Expand Down
16 changes: 8 additions & 8 deletions fs/ext4/ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
fatal = err;
} else {
ext4_error(sb, "bit already cleared for inode %lu", ino);
if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
if (gdp && !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
int count;
count = ext4_free_inodes_count(sb, gdp);
percpu_counter_sub(&sbi->s_freeinodes_counter,
Expand Down Expand Up @@ -874,6 +874,13 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
goto out;
}

BUFFER_TRACE(group_desc_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, group_desc_bh);
if (err) {
ext4_std_error(sb, err);
goto out;
}

/* We may have to initialize the block bitmap if it isn't already */
if (ext4_has_group_desc_csum(sb) &&
gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
Expand Down Expand Up @@ -910,13 +917,6 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
}
}

BUFFER_TRACE(group_desc_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, group_desc_bh);
if (err) {
ext4_std_error(sb, err);
goto out;
}

/* Update the relevant bg descriptor fields */
if (ext4_has_group_desc_csum(sb)) {
int free;
Expand Down
4 changes: 2 additions & 2 deletions fs/ext4/mballoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -752,8 +752,8 @@ void ext4_mb_generate_buddy(struct super_block *sb,

if (free != grp->bb_free) {
ext4_grp_locked_error(sb, group, 0, 0,
"%u clusters in bitmap, %u in gd; "
"block bitmap corrupt.",
"block bitmap and bg descriptor "
"inconsistent: %u vs %u free clusters",
free, grp->bb_free);
/*
* If we intend to continue, we consider group descriptor
Expand Down
60 changes: 28 additions & 32 deletions fs/ext4/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -1525,8 +1525,6 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
arg = JBD2_DEFAULT_MAX_COMMIT_AGE;
sbi->s_commit_interval = HZ * arg;
} else if (token == Opt_max_batch_time) {
if (arg == 0)
arg = EXT4_DEF_MAX_BATCH_TIME;
sbi->s_max_batch_time = arg;
} else if (token == Opt_min_batch_time) {
sbi->s_min_batch_time = arg;
Expand Down Expand Up @@ -2809,10 +2807,11 @@ static void print_daily_error_info(unsigned long arg)
es = sbi->s_es;

if (es->s_error_count)
ext4_msg(sb, KERN_NOTICE, "error count: %u",
/* fsck newer than v1.41.13 is needed to clean this condition. */
ext4_msg(sb, KERN_NOTICE, "error count since last fsck: %u",
le32_to_cpu(es->s_error_count));
if (es->s_first_error_time) {
printk(KERN_NOTICE "EXT4-fs (%s): initial error at %u: %.*s:%d",
printk(KERN_NOTICE "EXT4-fs (%s): initial error at time %u: %.*s:%d",
sb->s_id, le32_to_cpu(es->s_first_error_time),
(int) sizeof(es->s_first_error_func),
es->s_first_error_func,
Expand All @@ -2826,7 +2825,7 @@ static void print_daily_error_info(unsigned long arg)
printk("\n");
}
if (es->s_last_error_time) {
printk(KERN_NOTICE "EXT4-fs (%s): last error at %u: %.*s:%d",
printk(KERN_NOTICE "EXT4-fs (%s): last error at time %u: %.*s:%d",
sb->s_id, le32_to_cpu(es->s_last_error_time),
(int) sizeof(es->s_last_error_func),
es->s_last_error_func,
Expand Down Expand Up @@ -3880,38 +3879,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
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)) {
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_fill_flex_info(sb)) {
ext4_msg(sb, KERN_ERR,
"unable to initialize "
"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));
spin_lock_init(&sbi->s_next_gen_lock);

Expand Down Expand Up @@ -3946,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_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_xattr = ext4_xattr_handlers;
#ifdef CONFIG_QUOTA
Expand Down Expand Up @@ -4135,13 +4123,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
if (err) {
ext4_msg(sb, KERN_ERR, "failed to reserve %llu clusters for "
"reserved pool", ext4_calculate_resv_clusters(sb));
goto failed_mount5;
goto failed_mount4a;
}

err = ext4_setup_system_zone(sb);
if (err) {
ext4_msg(sb, KERN_ERR, "failed to initialize system "
"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;
}

Expand Down Expand Up @@ -4218,8 +4214,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
failed_mount7:
ext4_unregister_li_request(sb);
failed_mount6:
ext4_release_system_zone(sb);
ext4_mb_release(sb);
failed_mount5:
ext4_ext_release(sb);
ext4_release_system_zone(sb);
failed_mount4a:
dput(sb->s_root);
sb->s_root = NULL;
failed_mount4:
Expand All @@ -4243,14 +4242,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
percpu_counter_destroy(&sbi->s_extent_cache_cnt);
if (sbi->s_mmp_tsk)
kthread_stop(sbi->s_mmp_tsk);
failed_mount2a:
ext4_mb_release(sb);
failed_mount2:
for (i = 0; i < db_count; i++)
brelse(sbi->s_group_desc[i]);
ext4_kvfree(sbi->s_group_desc);
failed_mount:
ext4_ext_release(sb);
if (sbi->s_chksum_driver)
crypto_free_shash(sbi->s_chksum_driver);
if (sbi->s_proc) {
Expand Down
5 changes: 4 additions & 1 deletion fs/jbd2/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -1588,9 +1588,12 @@ int jbd2_journal_stop(handle_t *handle)
* to perform a synchronous write. We do this to detect the
* case where a single process is doing a stream of sync
* writes. No point in waiting for joiners in that case.
*
* Setting max_batch_time to 0 disables this completely.
*/
pid = current->pid;
if (handle->h_sync && journal->j_last_sync_writer != pid) {
if (handle->h_sync && journal->j_last_sync_writer != pid &&
journal->j_max_batch_time) {
u64 commit_time, trans_time;

journal->j_last_sync_writer = pid;
Expand Down

0 comments on commit 18b34d9

Please sign in to comment.