Commit 7f93cff90fa9be6ed45f6189e136153d1d8631b0

Authored by Theodore Ts'o
1 parent 72f84e6560

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>

Showing 2 changed files with 15 additions and 2 deletions Side-by-side Diff

... ... @@ -3964,9 +3964,12 @@
3964 3964 else
3965 3965 es->s_kbytes_written =
3966 3966 cpu_to_le64(EXT4_SB(sb)->s_kbytes_written);
3967   - ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
  3967 + if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeblocks_counter))
  3968 + ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
3968 3969 &EXT4_SB(sb)->s_freeblocks_counter));
3969   - es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive(
  3970 + if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter))
  3971 + es->s_free_inodes_count =
  3972 + cpu_to_le32(percpu_counter_sum_positive(
3970 3973 &EXT4_SB(sb)->s_freeinodes_counter));
3971 3974 sb->s_dirt = 0;
3972 3975 BUFFER_TRACE(sbh, "marking dirty");
include/linux/percpu_counter.h
... ... @@ -78,6 +78,11 @@
78 78 return 1;
79 79 }
80 80  
  81 +static inline int percpu_counter_initialized(struct percpu_counter *fbc)
  82 +{
  83 + return (fbc->counters != NULL);
  84 +}
  85 +
81 86 #else
82 87  
83 88 struct percpu_counter {
... ... @@ -141,6 +146,11 @@
141 146 static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
142 147 {
143 148 return percpu_counter_read(fbc);
  149 +}
  150 +
  151 +static inline int percpu_counter_initialized(struct percpu_counter *fbc)
  152 +{
  153 + return 1;
144 154 }
145 155  
146 156 #endif /* CONFIG_SMP */