aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2010-10-27 21:30:13 -0400
committerJonas ABERG <jonas.aberg@stericsson.com>2011-04-01 13:23:00 +0200
commitdbc6bcb1b89ad92b865917369c0c16c46fa48f31 (patch)
tree6ab33da32f350236da76eb66d5b4ce2e597cb099 /fs
parent434b87f67d6e8a7efbd241ae0e9e596c39488cd7 (diff)
ext4: fix kernel oops if the journal superblock has a non-zero j_errno
Commit 84061e0 fixed an accounting bug only to introduce the possibility of a kernel OOPS if the journal has a non-zero j_errno field indicating that the file system had detected a fs inconsistency. After the journal replay, if the journal superblock indicates that the file system has an error, this indication is transfered to the file system and then ext4_commit_super() is called to write this to the disk. But since the percpu counters are now initialized after the journal replay, the call to ext4_commit_super() will cause a kernel oops since it needs to use the percpu counters the ext4 superblock structure. The fix is to skip setting the ext4 free block and free inode fields if the percpu counter has not been set. Thanks to Ken Sumrall for reporting and analyzing the root causes of this bug. Addresses-Google-Bug: #3054080 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Change-Id: I06bab931da53a1b5ba6c0c381ddc612dcf82a0a1 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/19488 Tested-by: Piotr TOMASZEWSKI <piotr.tomaszewski@stericsson.com> Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/super.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index a45ced96b04..31423f7a98c 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3388,9 +3388,12 @@ static int ext4_commit_super(struct super_block *sb, int sync)
cpu_to_le64(EXT4_SB(sb)->s_kbytes_written +
((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
EXT4_SB(sb)->s_sectors_written_start) >> 1));
- ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
+ if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeblocks_counter))
+ ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
&EXT4_SB(sb)->s_freeblocks_counter));
- es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive(
+ if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter))
+ es->s_free_inodes_count =
+ cpu_to_le32(percpu_counter_sum_positive(
&EXT4_SB(sb)->s_freeinodes_counter));
sb->s_dirt = 0;
BUFFER_TRACE(sbh, "marking dirty");