| From 4274f516d4bc50648a4d97e4f67ecbd7b65cde4a Mon Sep 17 00:00:00 2001 |
| From: Theodore Ts'o <tytso@mit.edu> |
| Date: Sat, 1 Sep 2018 14:42:14 -0400 |
| Subject: ext4: recalucate superblock checksum after updating free blocks/inodes |
| |
| From: Theodore Ts'o <tytso@mit.edu> |
| |
| commit 4274f516d4bc50648a4d97e4f67ecbd7b65cde4a upstream. |
| |
| When mounting the superblock, ext4_fill_super() calculates the free |
| blocks and free inodes and stores them in the superblock. It's not |
| strictly necessary, since we don't use them any more, but it's nice to |
| keep them roughly aligned to reality. |
| |
| Since it's not critical for file system correctness, the code doesn't |
| call ext4_commit_super(). The problem is that it's in |
| ext4_commit_super() that we recalculate the superblock checksum. So |
| if we're not going to call ext4_commit_super(), we need to call |
| ext4_superblock_csum_set() to make sure the superblock checksum is |
| consistent. |
| |
| Most of the time, this doesn't matter, since we end up calling |
| ext4_commit_super() very soon thereafter, and definitely by the time |
| the file system is unmounted. However, it doesn't work in this |
| sequence: |
| |
| mke2fs -Fq -t ext4 /dev/vdc 128M |
| mount /dev/vdc /vdc |
| cp xfstests/git-versions /vdc |
| godown /vdc |
| umount /vdc |
| mount /dev/vdc |
| tune2fs -l /dev/vdc |
| |
| With this commit, the "tune2fs -l" no longer fails. |
| |
| Reported-by: Chengguang Xu <cgxu519@gmx.com> |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/ext4/super.c | 2 ++ |
| 1 file changed, 2 insertions(+) |
| |
| --- a/fs/ext4/super.c |
| +++ b/fs/ext4/super.c |
| @@ -4311,11 +4311,13 @@ no_journal: |
| block = ext4_count_free_clusters(sb); |
| ext4_free_blocks_count_set(sbi->s_es, |
| EXT4_C2B(sbi, block)); |
| + ext4_superblock_csum_set(sb); |
| err = percpu_counter_init(&sbi->s_freeclusters_counter, block, |
| GFP_KERNEL); |
| if (!err) { |
| unsigned long freei = ext4_count_free_inodes(sb); |
| sbi->s_es->s_free_inodes_count = cpu_to_le32(freei); |
| + ext4_superblock_csum_set(sb); |
| err = percpu_counter_init(&sbi->s_freeinodes_counter, freei, |
| GFP_KERNEL); |
| } |