diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-07-29 16:13:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-07-29 16:13:45 -0400 |
commit | 3cfb6772d4cf3875d199f5a5a547cadaef7c1382 (patch) | |
tree | 0039b462e4e5e554dc5332426533bdccd09e95a8 | |
parent | 01cfb7937a9af2abb1136c7e89fbf3fd92952956 (diff) | |
parent | 5012284700775a4e6e3fbe7eac4c543c4874b559 (diff) |
Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 fixes from Ted Ts'o:
"Some miscellaneous ext4 fixes for 4.18; one fix is for a regression
introduced in 4.18-rc4.
Sorry for the late-breaking pull. I was originally going to wait for
the next merge window, but Eric Whitney found a regression introduced
in 4.18-rc4, so I decided to push out the regression plus the other
fixes now. (The other commits have been baking in linux-next since
early July)"
* tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
ext4: fix check to prevent initializing reserved inodes
ext4: check for allocation block validity with block group locked
ext4: fix inline data updates with checksums enabled
ext4: clear mmp sequence number when remounting read-only
ext4: fix false negatives *and* false positives in ext4_check_descriptors()
-rw-r--r-- | fs/ext4/balloc.c | 3 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 8 | ||||
-rw-r--r-- | fs/ext4/inline.c | 19 | ||||
-rw-r--r-- | fs/ext4/inode.c | 16 | ||||
-rw-r--r-- | fs/ext4/mmp.c | 7 | ||||
-rw-r--r-- | fs/ext4/super.c | 15 |
6 files changed, 35 insertions, 33 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index e68cefe08261..aa52d87985aa 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -368,6 +368,8 @@ static int ext4_validate_block_bitmap(struct super_block *sb, | |||
368 | return -EFSCORRUPTED; | 368 | return -EFSCORRUPTED; |
369 | 369 | ||
370 | ext4_lock_group(sb, block_group); | 370 | ext4_lock_group(sb, block_group); |
371 | if (buffer_verified(bh)) | ||
372 | goto verified; | ||
371 | if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group, | 373 | if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group, |
372 | desc, bh))) { | 374 | desc, bh))) { |
373 | ext4_unlock_group(sb, block_group); | 375 | ext4_unlock_group(sb, block_group); |
@@ -386,6 +388,7 @@ static int ext4_validate_block_bitmap(struct super_block *sb, | |||
386 | return -EFSCORRUPTED; | 388 | return -EFSCORRUPTED; |
387 | } | 389 | } |
388 | set_buffer_verified(bh); | 390 | set_buffer_verified(bh); |
391 | verified: | ||
389 | ext4_unlock_group(sb, block_group); | 392 | ext4_unlock_group(sb, block_group); |
390 | return 0; | 393 | return 0; |
391 | } | 394 | } |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index fb83750c1a14..f336cbc6e932 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -90,6 +90,8 @@ static int ext4_validate_inode_bitmap(struct super_block *sb, | |||
90 | return -EFSCORRUPTED; | 90 | return -EFSCORRUPTED; |
91 | 91 | ||
92 | ext4_lock_group(sb, block_group); | 92 | ext4_lock_group(sb, block_group); |
93 | if (buffer_verified(bh)) | ||
94 | goto verified; | ||
93 | blk = ext4_inode_bitmap(sb, desc); | 95 | blk = ext4_inode_bitmap(sb, desc); |
94 | if (!ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh, | 96 | if (!ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh, |
95 | EXT4_INODES_PER_GROUP(sb) / 8)) { | 97 | EXT4_INODES_PER_GROUP(sb) / 8)) { |
@@ -101,6 +103,7 @@ static int ext4_validate_inode_bitmap(struct super_block *sb, | |||
101 | return -EFSBADCRC; | 103 | return -EFSBADCRC; |
102 | } | 104 | } |
103 | set_buffer_verified(bh); | 105 | set_buffer_verified(bh); |
106 | verified: | ||
104 | ext4_unlock_group(sb, block_group); | 107 | ext4_unlock_group(sb, block_group); |
105 | return 0; | 108 | return 0; |
106 | } | 109 | } |
@@ -1385,7 +1388,10 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, | |||
1385 | ext4_itable_unused_count(sb, gdp)), | 1388 | ext4_itable_unused_count(sb, gdp)), |
1386 | sbi->s_inodes_per_block); | 1389 | sbi->s_inodes_per_block); |
1387 | 1390 | ||
1388 | if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group)) { | 1391 | if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group) || |
1392 | ((group == 0) && ((EXT4_INODES_PER_GROUP(sb) - | ||
1393 | ext4_itable_unused_count(sb, gdp)) < | ||
1394 | EXT4_FIRST_INO(sb)))) { | ||
1389 | ext4_error(sb, "Something is wrong with group %u: " | 1395 | ext4_error(sb, "Something is wrong with group %u: " |
1390 | "used itable blocks: %d; " | 1396 | "used itable blocks: %d; " |
1391 | "itable unused count: %u", | 1397 | "itable unused count: %u", |
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index e55a8bc870bd..3543fe80a3c4 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c | |||
@@ -682,6 +682,10 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, | |||
682 | goto convert; | 682 | goto convert; |
683 | } | 683 | } |
684 | 684 | ||
685 | ret = ext4_journal_get_write_access(handle, iloc.bh); | ||
686 | if (ret) | ||
687 | goto out; | ||
688 | |||
685 | flags |= AOP_FLAG_NOFS; | 689 | flags |= AOP_FLAG_NOFS; |
686 | 690 | ||
687 | page = grab_cache_page_write_begin(mapping, 0, flags); | 691 | page = grab_cache_page_write_begin(mapping, 0, flags); |
@@ -710,7 +714,7 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, | |||
710 | out_up_read: | 714 | out_up_read: |
711 | up_read(&EXT4_I(inode)->xattr_sem); | 715 | up_read(&EXT4_I(inode)->xattr_sem); |
712 | out: | 716 | out: |
713 | if (handle) | 717 | if (handle && (ret != 1)) |
714 | ext4_journal_stop(handle); | 718 | ext4_journal_stop(handle); |
715 | brelse(iloc.bh); | 719 | brelse(iloc.bh); |
716 | return ret; | 720 | return ret; |
@@ -752,6 +756,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, | |||
752 | 756 | ||
753 | ext4_write_unlock_xattr(inode, &no_expand); | 757 | ext4_write_unlock_xattr(inode, &no_expand); |
754 | brelse(iloc.bh); | 758 | brelse(iloc.bh); |
759 | mark_inode_dirty(inode); | ||
755 | out: | 760 | out: |
756 | return copied; | 761 | return copied; |
757 | } | 762 | } |
@@ -898,7 +903,6 @@ retry_journal: | |||
898 | goto out; | 903 | goto out; |
899 | } | 904 | } |
900 | 905 | ||
901 | |||
902 | page = grab_cache_page_write_begin(mapping, 0, flags); | 906 | page = grab_cache_page_write_begin(mapping, 0, flags); |
903 | if (!page) { | 907 | if (!page) { |
904 | ret = -ENOMEM; | 908 | ret = -ENOMEM; |
@@ -916,6 +920,9 @@ retry_journal: | |||
916 | if (ret < 0) | 920 | if (ret < 0) |
917 | goto out_release_page; | 921 | goto out_release_page; |
918 | } | 922 | } |
923 | ret = ext4_journal_get_write_access(handle, iloc.bh); | ||
924 | if (ret) | ||
925 | goto out_release_page; | ||
919 | 926 | ||
920 | up_read(&EXT4_I(inode)->xattr_sem); | 927 | up_read(&EXT4_I(inode)->xattr_sem); |
921 | *pagep = page; | 928 | *pagep = page; |
@@ -936,7 +943,6 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, | |||
936 | unsigned len, unsigned copied, | 943 | unsigned len, unsigned copied, |
937 | struct page *page) | 944 | struct page *page) |
938 | { | 945 | { |
939 | int i_size_changed = 0; | ||
940 | int ret; | 946 | int ret; |
941 | 947 | ||
942 | ret = ext4_write_inline_data_end(inode, pos, len, copied, page); | 948 | ret = ext4_write_inline_data_end(inode, pos, len, copied, page); |
@@ -954,10 +960,8 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, | |||
954 | * But it's important to update i_size while still holding page lock: | 960 | * But it's important to update i_size while still holding page lock: |
955 | * page writeout could otherwise come in and zero beyond i_size. | 961 | * page writeout could otherwise come in and zero beyond i_size. |
956 | */ | 962 | */ |
957 | if (pos+copied > inode->i_size) { | 963 | if (pos+copied > inode->i_size) |
958 | i_size_write(inode, pos+copied); | 964 | i_size_write(inode, pos+copied); |
959 | i_size_changed = 1; | ||
960 | } | ||
961 | unlock_page(page); | 965 | unlock_page(page); |
962 | put_page(page); | 966 | put_page(page); |
963 | 967 | ||
@@ -967,8 +971,7 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, | |||
967 | * ordering of page lock and transaction start for journaling | 971 | * ordering of page lock and transaction start for journaling |
968 | * filesystems. | 972 | * filesystems. |
969 | */ | 973 | */ |
970 | if (i_size_changed) | 974 | mark_inode_dirty(inode); |
971 | mark_inode_dirty(inode); | ||
972 | 975 | ||
973 | return copied; | 976 | return copied; |
974 | } | 977 | } |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 7d6c10017bdf..4efe77286ecd 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -1389,9 +1389,10 @@ static int ext4_write_end(struct file *file, | |||
1389 | loff_t old_size = inode->i_size; | 1389 | loff_t old_size = inode->i_size; |
1390 | int ret = 0, ret2; | 1390 | int ret = 0, ret2; |
1391 | int i_size_changed = 0; | 1391 | int i_size_changed = 0; |
1392 | int inline_data = ext4_has_inline_data(inode); | ||
1392 | 1393 | ||
1393 | trace_ext4_write_end(inode, pos, len, copied); | 1394 | trace_ext4_write_end(inode, pos, len, copied); |
1394 | if (ext4_has_inline_data(inode)) { | 1395 | if (inline_data) { |
1395 | ret = ext4_write_inline_data_end(inode, pos, len, | 1396 | ret = ext4_write_inline_data_end(inode, pos, len, |
1396 | copied, page); | 1397 | copied, page); |
1397 | if (ret < 0) { | 1398 | if (ret < 0) { |
@@ -1419,7 +1420,7 @@ static int ext4_write_end(struct file *file, | |||
1419 | * ordering of page lock and transaction start for journaling | 1420 | * ordering of page lock and transaction start for journaling |
1420 | * filesystems. | 1421 | * filesystems. |
1421 | */ | 1422 | */ |
1422 | if (i_size_changed) | 1423 | if (i_size_changed || inline_data) |
1423 | ext4_mark_inode_dirty(handle, inode); | 1424 | ext4_mark_inode_dirty(handle, inode); |
1424 | 1425 | ||
1425 | if (pos + len > inode->i_size && ext4_can_truncate(inode)) | 1426 | if (pos + len > inode->i_size && ext4_can_truncate(inode)) |
@@ -1493,6 +1494,7 @@ static int ext4_journalled_write_end(struct file *file, | |||
1493 | int partial = 0; | 1494 | int partial = 0; |
1494 | unsigned from, to; | 1495 | unsigned from, to; |
1495 | int size_changed = 0; | 1496 | int size_changed = 0; |
1497 | int inline_data = ext4_has_inline_data(inode); | ||
1496 | 1498 | ||
1497 | trace_ext4_journalled_write_end(inode, pos, len, copied); | 1499 | trace_ext4_journalled_write_end(inode, pos, len, copied); |
1498 | from = pos & (PAGE_SIZE - 1); | 1500 | from = pos & (PAGE_SIZE - 1); |
@@ -1500,7 +1502,7 @@ static int ext4_journalled_write_end(struct file *file, | |||
1500 | 1502 | ||
1501 | BUG_ON(!ext4_handle_valid(handle)); | 1503 | BUG_ON(!ext4_handle_valid(handle)); |
1502 | 1504 | ||
1503 | if (ext4_has_inline_data(inode)) { | 1505 | if (inline_data) { |
1504 | ret = ext4_write_inline_data_end(inode, pos, len, | 1506 | ret = ext4_write_inline_data_end(inode, pos, len, |
1505 | copied, page); | 1507 | copied, page); |
1506 | if (ret < 0) { | 1508 | if (ret < 0) { |
@@ -1531,7 +1533,7 @@ static int ext4_journalled_write_end(struct file *file, | |||
1531 | if (old_size < pos) | 1533 | if (old_size < pos) |
1532 | pagecache_isize_extended(inode, old_size, pos); | 1534 | pagecache_isize_extended(inode, old_size, pos); |
1533 | 1535 | ||
1534 | if (size_changed) { | 1536 | if (size_changed || inline_data) { |
1535 | ret2 = ext4_mark_inode_dirty(handle, inode); | 1537 | ret2 = ext4_mark_inode_dirty(handle, inode); |
1536 | if (!ret) | 1538 | if (!ret) |
1537 | ret = ret2; | 1539 | ret = ret2; |
@@ -2028,11 +2030,7 @@ static int __ext4_journalled_writepage(struct page *page, | |||
2028 | } | 2030 | } |
2029 | 2031 | ||
2030 | if (inline_data) { | 2032 | if (inline_data) { |
2031 | BUFFER_TRACE(inode_bh, "get write access"); | 2033 | ret = ext4_mark_inode_dirty(handle, inode); |
2032 | ret = ext4_journal_get_write_access(handle, inode_bh); | ||
2033 | |||
2034 | err = ext4_handle_dirty_metadata(handle, inode, inode_bh); | ||
2035 | |||
2036 | } else { | 2034 | } else { |
2037 | ret = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, | 2035 | ret = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, |
2038 | do_journal_get_write_access); | 2036 | do_journal_get_write_access); |
diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c index 27b9a76a0dfa..638ad4743477 100644 --- a/fs/ext4/mmp.c +++ b/fs/ext4/mmp.c | |||
@@ -186,11 +186,8 @@ static int kmmpd(void *data) | |||
186 | goto exit_thread; | 186 | goto exit_thread; |
187 | } | 187 | } |
188 | 188 | ||
189 | if (sb_rdonly(sb)) { | 189 | if (sb_rdonly(sb)) |
190 | ext4_warning(sb, "kmmpd being stopped since filesystem " | 190 | break; |
191 | "has been remounted as readonly."); | ||
192 | goto exit_thread; | ||
193 | } | ||
194 | 191 | ||
195 | diff = jiffies - last_update_time; | 192 | diff = jiffies - last_update_time; |
196 | if (diff < mmp_update_interval * HZ) | 193 | if (diff < mmp_update_interval * HZ) |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index ba2396a7bd04..b7f7922061be 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -2342,7 +2342,7 @@ static int ext4_check_descriptors(struct super_block *sb, | |||
2342 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 2342 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
2343 | ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); | 2343 | ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); |
2344 | ext4_fsblk_t last_block; | 2344 | ext4_fsblk_t last_block; |
2345 | ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0) + 1; | 2345 | ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0); |
2346 | ext4_fsblk_t block_bitmap; | 2346 | ext4_fsblk_t block_bitmap; |
2347 | ext4_fsblk_t inode_bitmap; | 2347 | ext4_fsblk_t inode_bitmap; |
2348 | ext4_fsblk_t inode_table; | 2348 | ext4_fsblk_t inode_table; |
@@ -3141,14 +3141,8 @@ static ext4_group_t ext4_has_uninit_itable(struct super_block *sb) | |||
3141 | if (!gdp) | 3141 | if (!gdp) |
3142 | continue; | 3142 | continue; |
3143 | 3143 | ||
3144 | if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)) | 3144 | if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) |
3145 | continue; | ||
3146 | if (group != 0) | ||
3147 | break; | 3145 | break; |
3148 | ext4_error(sb, "Inode table for bg 0 marked as " | ||
3149 | "needing zeroing"); | ||
3150 | if (sb_rdonly(sb)) | ||
3151 | return ngroups; | ||
3152 | } | 3146 | } |
3153 | 3147 | ||
3154 | return group; | 3148 | return group; |
@@ -4085,14 +4079,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
4085 | goto failed_mount2; | 4079 | goto failed_mount2; |
4086 | } | 4080 | } |
4087 | } | 4081 | } |
4082 | sbi->s_gdb_count = db_count; | ||
4088 | if (!ext4_check_descriptors(sb, logical_sb_block, &first_not_zeroed)) { | 4083 | if (!ext4_check_descriptors(sb, logical_sb_block, &first_not_zeroed)) { |
4089 | ext4_msg(sb, KERN_ERR, "group descriptors corrupted!"); | 4084 | ext4_msg(sb, KERN_ERR, "group descriptors corrupted!"); |
4090 | ret = -EFSCORRUPTED; | 4085 | ret = -EFSCORRUPTED; |
4091 | goto failed_mount2; | 4086 | goto failed_mount2; |
4092 | } | 4087 | } |
4093 | 4088 | ||
4094 | sbi->s_gdb_count = db_count; | ||
4095 | |||
4096 | timer_setup(&sbi->s_err_report, print_daily_error_info, 0); | 4089 | timer_setup(&sbi->s_err_report, print_daily_error_info, 0); |
4097 | 4090 | ||
4098 | /* Register extent status tree shrinker */ | 4091 | /* Register extent status tree shrinker */ |
@@ -5213,6 +5206,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
5213 | 5206 | ||
5214 | if (sbi->s_journal) | 5207 | if (sbi->s_journal) |
5215 | ext4_mark_recovery_complete(sb, es); | 5208 | ext4_mark_recovery_complete(sb, es); |
5209 | if (sbi->s_mmp_tsk) | ||
5210 | kthread_stop(sbi->s_mmp_tsk); | ||
5216 | } else { | 5211 | } else { |
5217 | /* Make sure we can mount this feature set readwrite */ | 5212 | /* Make sure we can mount this feature set readwrite */ |
5218 | if (ext4_has_feature_readonly(sb) || | 5213 | if (ext4_has_feature_readonly(sb) || |