History

Merge tag 'ext4_for_linus-7.0-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4

Pull ext4 fixes from Ted Ts'o: - Update the MAINTAINERS file to add reviewers for the ext4 file system - Add a test issue an ext4 warning (not a WARN_ON) if there are still dirty pages attached to an evicted inode. - Fix a number of Syzkaller issues - Fix memory leaks on error paths - Replace some BUG and WARN with EFSCORRUPTED reporting - Fix a potential crash when disabling discard via remount followed by an immediate unmount. (Found by Sashiko) - Fix a corner case which could lead to allocating blocks for an indirect-mapped inode block numbers > 2**32 - Fix a race when reallocating a freed inode that could result in a deadlock - Fix a user-after-free in update_super_work when racing with umount - Fix build issues when trying to build ext4's kunit tests as a module - Fix a bug where ext4_split_extent_zeroout() could fail to pass back an error from ext4_ext_dirty() - Avoid allocating blocks from a corrupted block group in ext4_mb_find_by_goal() - Fix a percpu_counters list corruption BUG triggered by an ext4 extents kunit - Fix a potetial crash caused by the fast commit flush path potentially accessing the jinode structure before it is fully initialized - Fix fsync(2) in no-journal mode to make sure the dirtied inode is write to storage - Fix a bug when in no-journal mode, when ext4 tries to avoid using recently deleted inodes, if lazy itable initialization is enabled, can lead to an unitialized inode getting skipped and triggering an e2fsck complaint - Fix journal credit calculation when setting an xattr when both the encryption and ea_inode feeatures are enabled - Fix corner cases which could result in stale xarray tags after writeback - Fix generic/475 failures caused by ENOSPC errors while creating a symlink when the system crashes resulting to a file system inconsistency when replaying the fast commit journal * tag 'ext4_for_linus-7.0-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (27 commits) ext4: always drain queued discard work in ext4_mb_release() ext4: handle wraparound when searching for blocks for indirect mapped blocks ext4: skip split extent recovery on corruption ext4: fix iloc.bh leak in ext4_fc_replay_inode() error paths ext4: fix deadlock on inode reallocation ext4: fix use-after-free in update_super_work when racing with umount ext4: fix the might_sleep() warnings in kvfree() ext4: reject mount if bigalloc with s_first_data_block != 0 ext4: fix extents-test.c is not compiled when EXT4_KUNIT_TESTS=M ext4: fix mballoc-test.c is not compiled when EXT4_KUNIT_TESTS=M ext4: introduce EXPORT_SYMBOL_FOR_EXT4_TEST() helper jbd2: gracefully abort on checkpointing state corruptions ext4: avoid infinite loops caused by residual data ext4: validate p_idx bounds in ext4_ext_correct_indexes ext4: test if inode's all dirty pages are submitted to disk ext4: minor fix for ext4_split_extent_zeroout() ext4: avoid allocate block from corrupted group in ext4_mb_find_by_goal() ext4: kunit: extents-test: lix percpu_counters list corruption ext4: publish jinode after initialization ext4: replace BUG_ON with proper error handling in ext4_read_inline_folio ...

Linus Torvalds committed 7 months ago

Commit 241d4ca2 parents b51ad67 9ee29d219 files · +455 −115Browse files

Unified · Split

19 files
  1. MAINTAINERS +6 −1
  2. fs/ext4/Makefile +3 −2
  3. fs/ext4/crypto.c +8 −1
  4. fs/ext4/ext4.h +6 −0
  5. fs/ext4/ext4_extents.h +12 −0
  6. fs/ext4/extents-test.c +7 −5
  7. fs/ext4/extents.c +68 −12
  8. fs/ext4/fast_commit.c +10 −7
  9. fs/ext4/fsync.c +14 −2
  10. fs/ext4/ialloc.c +6 −0
  11. fs/ext4/inline.c +9 −1
  12. fs/ext4/inode.c +60 −15
  13. fs/ext4/mballoc-test.c +41 −40
  14. fs/ext4/mballoc.c +114 −18
  15. fs/ext4/mballoc.h +30 −0
  16. fs/ext4/page-io.c +8 −2
  17. fs/ext4/super.c +31 −6
  18. fs/ext4/sysfs.c +9 −1
  19. fs/jbd2/checkpoint.c +13 −2
MAINTAINERS+6−1
@@ -9619,7 +9619,12 @@ F: include/linux/ext2* · 9618 unmodified lines
9619 9619
9620EXT4 FILE SYSTEM9620EXT4 FILE SYSTEM
9621M: "Theodore Ts'o" <tytso@mit.edu>9621M: "Theodore Ts'o" <tytso@mit.edu>
9622M: Andreas Dilger <adilger.kernel@dilger.ca>9622R: Andreas Dilger <adilger.kernel@dilger.ca>
9623R: Baokun Li <libaokun@linux.alibaba.com>
9624R: Jan Kara <jack@suse.cz>
9625R: Ojaswin Mujoo <ojaswin@linux.ibm.com>
9626R: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
9627R: Zhang Yi <yi.zhang@huawei.com>
9623L: linux-ext4@vger.kernel.org9628L: linux-ext4@vger.kernel.org
9624S: Maintained9629S: Maintained
9625W: http://ext4.wiki.kernel.org9630W: http://ext4.wiki.kernel.org
fs/ext4/Makefile+3−2
@@ -14,7 +14,8 @@ ext4-y := balloc.o bitmap.o block_validity.o dir.o ext4_jbd2.o extents.o \ · 13 unmodified lines
14 14
15ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o15ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
16ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o16ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
17ext4-inode-test-objs += inode-test.o17ext4-test-objs += inode-test.o mballoc-test.o \
18obj-$(CONFIG_EXT4_KUNIT_TESTS) += ext4-inode-test.o18 extents-test.o
19obj-$(CONFIG_EXT4_KUNIT_TESTS) += ext4-test.o
19ext4-$(CONFIG_FS_VERITY) += verity.o20ext4-$(CONFIG_FS_VERITY) += verity.o
20ext4-$(CONFIG_FS_ENCRYPTION) += crypto.o21ext4-$(CONFIG_FS_ENCRYPTION) += crypto.o
fs/ext4/crypto.c+8−1
@@ -163,10 +163,17 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len, · 162 unmodified lines
163 */163 */
164 164
165 if (handle) {165 if (handle) {
166 /*
167 * Since the inode is new it is ok to pass the
168 * XATTR_CREATE flag. This is necessary to match the
169 * remaining journal credits check in the set_handle
170 * function with the credits allocated for the new
171 * inode.
172 */
166 res = ext4_xattr_set_handle(handle, inode,173 res = ext4_xattr_set_handle(handle, inode,
167 EXT4_XATTR_INDEX_ENCRYPTION,174 EXT4_XATTR_INDEX_ENCRYPTION,
168 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,175 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
169 ctx, len, 0);176 ctx, len, XATTR_CREATE);
170 if (!res) {177 if (!res) {
171 ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);178 ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
172 ext4_clear_inode_state(inode,179 ext4_clear_inode_state(inode,
fs/ext4/ext4.h+6−0
@@ -1570,6 +1570,7 @@ struct ext4_sb_info { · 1569 unmodified lines
1570 struct proc_dir_entry *s_proc;1570 struct proc_dir_entry *s_proc;
1571 struct kobject s_kobj;1571 struct kobject s_kobj;
1572 struct completion s_kobj_unregister;1572 struct completion s_kobj_unregister;
1573 struct mutex s_error_notify_mutex; /* protects sysfs_notify vs kobject_del */
1573 struct super_block *s_sb;1574 struct super_block *s_sb;
1574 struct buffer_head *s_mmp_bh;1575 struct buffer_head *s_mmp_bh;
1575 1576
@@ -3944,6 +3945,11 @@ static inline bool ext4_inode_can_atomic_write(struct inode *inode) · 2368 unmodified lines
3944extern int ext4_block_write_begin(handle_t *handle, struct folio *folio,3945extern int ext4_block_write_begin(handle_t *handle, struct folio *folio,
3945 loff_t pos, unsigned len,3946 loff_t pos, unsigned len,
3946 get_block_t *get_block);3947 get_block_t *get_block);
3948
3949#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
3950#define EXPORT_SYMBOL_FOR_EXT4_TEST(sym) \
3951 EXPORT_SYMBOL_FOR_MODULES(sym, "ext4-test")
3952#endif
3947#endif /* __KERNEL__ */3953#endif /* __KERNEL__ */
3948 3954
3949#endif /* _EXT4_H */3955#endif /* _EXT4_H */
fs/ext4/ext4_extents.h+12−0
@@ -264,5 +264,17 @@ static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix, · 263 unmodified lines
264 0xffff);264 0xffff);
265}265}
266 266
267extern int __ext4_ext_dirty(const char *where, unsigned int line,
268 handle_t *handle, struct inode *inode,
269 struct ext4_ext_path *path);
270extern int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex);
271#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
272extern int ext4_ext_space_root_idx_test(struct inode *inode, int check);
273extern struct ext4_ext_path *ext4_split_convert_extents_test(
274 handle_t *handle, struct inode *inode,
275 struct ext4_map_blocks *map,
276 struct ext4_ext_path *path,
277 int flags, unsigned int *allocated);
278#endif
267#endif /* _EXT4_EXTENTS */279#endif /* _EXT4_EXTENTS */
268 280
fs/ext4/extents-test.c+7−5
@@ -142,8 +142,10 @@ static struct file_system_type ext_fs_type = { · 141 unmodified lines
142 142
143static void extents_kunit_exit(struct kunit *test)143static void extents_kunit_exit(struct kunit *test)
144{144{
145 struct ext4_sb_info *sbi = k_ctx.k_ei->vfs_inode.i_sb->s_fs_info;145 struct super_block *sb = k_ctx.k_ei->vfs_inode.i_sb;
146 struct ext4_sb_info *sbi = sb->s_fs_info;
146 147
148 ext4_es_unregister_shrinker(sbi);
147 kfree(sbi);149 kfree(sbi);
148 kfree(k_ctx.k_ei);150 kfree(k_ctx.k_ei);
149 kfree(k_ctx.k_data);151 kfree(k_ctx.k_data);
@@ -280,8 +282,8 @@ static int extents_kunit_init(struct kunit *test) · 130 unmodified lines
280 eh->eh_depth = 0;282 eh->eh_depth = 0;
281 eh->eh_entries = cpu_to_le16(1);283 eh->eh_entries = cpu_to_le16(1);
282 eh->eh_magic = EXT4_EXT_MAGIC;284 eh->eh_magic = EXT4_EXT_MAGIC;
283 eh->eh_max =285 eh->eh_max = cpu_to_le16(ext4_ext_space_root_idx_test(
284 cpu_to_le16(ext4_ext_space_root_idx(&k_ctx.k_ei->vfs_inode, 0));286 &k_ctx.k_ei->vfs_inode, 0));
285 eh->eh_generation = 0;287 eh->eh_generation = 0;
286 288
287 /*289 /*
@@ -384,8 +386,8 @@ static void test_split_convert(struct kunit *test) · 96 unmodified lines
384 386
385 switch (param->type) {387 switch (param->type) {
386 case TEST_SPLIT_CONVERT:388 case TEST_SPLIT_CONVERT:
387 path = ext4_split_convert_extents(NULL, inode, &map, path,389 path = ext4_split_convert_extents_test(NULL, inode, &map,
388 param->split_flags, NULL);390 path, param->split_flags, NULL);
389 break;391 break;
390 case TEST_CREATE_BLOCKS:392 case TEST_CREATE_BLOCKS:
391 ext4_map_create_blocks_helper(test, inode, &map, param->split_flags);393 ext4_map_create_blocks_helper(test, inode, &map, param->split_flags);
fs/ext4/extents.c+68−12
@@ -184,9 +184,9 @@ static int ext4_ext_get_access(handle_t *handle, struct inode *inode, · 183 unmodified lines
184 * - ENOMEM184 * - ENOMEM
185 * - EIO185 * - EIO
186 */186 */
187static int __ext4_ext_dirty(const char *where, unsigned int line,187int __ext4_ext_dirty(const char *where, unsigned int line,
188 handle_t *handle, struct inode *inode,188 handle_t *handle, struct inode *inode,
189 struct ext4_ext_path *path)189 struct ext4_ext_path *path)
190{190{
191 int err;191 int err;
192 192
@@ -1736,6 +1736,13 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode, · 1543 unmodified lines
1736 err = ext4_ext_get_access(handle, inode, path + k);1736 err = ext4_ext_get_access(handle, inode, path + k);
1737 if (err)1737 if (err)
1738 return err;1738 return err;
1739 if (unlikely(path[k].p_idx > EXT_LAST_INDEX(path[k].p_hdr))) {
1740 EXT4_ERROR_INODE(inode,
1741 "path[%d].p_idx %p > EXT_LAST_INDEX %p",
1742 k, path[k].p_idx,
1743 EXT_LAST_INDEX(path[k].p_hdr));
1744 return -EFSCORRUPTED;
1745 }
1739 path[k].p_idx->ei_block = border;1746 path[k].p_idx->ei_block = border;
1740 err = ext4_ext_dirty(handle, inode, path + k);1747 err = ext4_ext_dirty(handle, inode, path + k);
1741 if (err)1748 if (err)
@@ -1748,6 +1755,14 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode, · 6 unmodified lines
1748 err = ext4_ext_get_access(handle, inode, path + k);1755 err = ext4_ext_get_access(handle, inode, path + k);
1749 if (err)1756 if (err)
1750 goto clean;1757 goto clean;
1758 if (unlikely(path[k].p_idx > EXT_LAST_INDEX(path[k].p_hdr))) {
1759 EXT4_ERROR_INODE(inode,
1760 "path[%d].p_idx %p > EXT_LAST_INDEX %p",
1761 k, path[k].p_idx,
1762 EXT_LAST_INDEX(path[k].p_hdr));
1763 err = -EFSCORRUPTED;
1764 goto clean;
1765 }
1751 path[k].p_idx->ei_block = border;1766 path[k].p_idx->ei_block = border;
1752 err = ext4_ext_dirty(handle, inode, path + k);1767 err = ext4_ext_dirty(handle, inode, path + k);
1753 if (err)1768 if (err)
@@ -3144,7 +3159,7 @@ static void ext4_zeroout_es(struct inode *inode, struct ext4_extent *ex) · 1390 unmodified lines
3144}3159}
3145 3160
3146/* FIXME!! we need to try to merge to left or right after zero-out */3161/* FIXME!! we need to try to merge to left or right after zero-out */
3147static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)3162int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
3148{3163{
3149 ext4_fsblk_t ee_pblock;3164 ext4_fsblk_t ee_pblock;
3150 unsigned int ee_len;3165 unsigned int ee_len;
@@ -3239,6 +3254,9 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, · 88 unmodified lines
3239 3254
3240 insert_err = PTR_ERR(path);3255 insert_err = PTR_ERR(path);
3241 err = 0;3256 err = 0;
3257 if (insert_err != -ENOSPC && insert_err != -EDQUOT &&
3258 insert_err != -ENOMEM)
3259 goto out_path;
3242 3260
3243 /*3261 /*
3244 * Get a new path to try to zeroout or fix the extent length.3262 * Get a new path to try to zeroout or fix the extent length.
@@ -3255,13 +3273,20 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, · 10 unmodified lines
3255 goto out_path;3273 goto out_path;
3256 }3274 }
3257 3275
3276 depth = ext_depth(inode);
3277 ex = path[depth].p_ext;
3278 if (!ex) {
3279 EXT4_ERROR_INODE(inode,
3280 "bad extent address lblock: %lu, depth: %d pblock %llu",
3281 (unsigned long)ee_block, depth, path[depth].p_block);
3282 err = -EFSCORRUPTED;
3283 goto out;
3284 }
3285
3258 err = ext4_ext_get_access(handle, inode, path + depth);3286 err = ext4_ext_get_access(handle, inode, path + depth);
3259 if (err)3287 if (err)
3260 goto out;3288 goto out;
3261 3289
3262 depth = ext_depth(inode);
3263 ex = path[depth].p_ext;
3264
3265fix_extent_len:3290fix_extent_len:
3266 ex->ee_len = orig_ex.ee_len;3291 ex->ee_len = orig_ex.ee_len;
3267 err = ext4_ext_dirty(handle, inode, path + path->p_depth);3292 err = ext4_ext_dirty(handle, inode, path + path->p_depth);
@@ -3363,7 +3388,7 @@ static int ext4_split_extent_zeroout(handle_t *handle, struct inode *inode, · 95 unmodified lines
3363 3388
3364 ext4_ext_mark_initialized(ex);3389 ext4_ext_mark_initialized(ex);
3365 3390
3366 ext4_ext_dirty(handle, inode, path + depth);3391 err = ext4_ext_dirty(handle, inode, path + depth);
3367 if (err)3392 if (err)
3368 return err;3393 return err;
3369 3394
@@ -4457,9 +4482,13 @@ got_allocated_blocks: · 1087 unmodified lines
4457 path = ext4_ext_insert_extent(handle, inode, path, &newex, flags);4482 path = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
4458 if (IS_ERR(path)) {4483 if (IS_ERR(path)) {
4459 err = PTR_ERR(path);4484 err = PTR_ERR(path);
4460 if (allocated_clusters) {4485 /*
4486 * Gracefully handle out of space conditions. If the filesystem
4487 * is inconsistent, we'll just leak allocated blocks to avoid
4488 * causing even more damage.
4489 */
4490 if (allocated_clusters && (err == -EDQUOT || err == -ENOSPC)) {
4461 int fb_flags = 0;4491 int fb_flags = 0;
4462
4463 /*4492 /*
4464 * free data blocks we just allocated.4493 * free data blocks we just allocated.
4465 * not a good idea to call discard here directly,4494 * not a good idea to call discard here directly,
@@ -6238,6 +6267,33 @@ out: · 1772 unmodified lines
6238 return 0;6267 return 0;
6239}6268}
6240 6269
6241#ifdef CONFIG_EXT4_KUNIT_TESTS6270#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
6242#include "extents-test.c"6271int ext4_ext_space_root_idx_test(struct inode *inode, int check)
6272{
6273 return ext4_ext_space_root_idx(inode, check);
6274}
6275EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_ext_space_root_idx_test);
6276
6277struct ext4_ext_path *ext4_split_convert_extents_test(handle_t *handle,
6278 struct inode *inode, struct ext4_map_blocks *map,
6279 struct ext4_ext_path *path, int flags,
6280 unsigned int *allocated)
6281{
6282 return ext4_split_convert_extents(handle, inode, map, path,
6283 flags, allocated);
6284}
6285EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_split_convert_extents_test);
6286
6287EXPORT_SYMBOL_FOR_EXT4_TEST(__ext4_ext_dirty);
6288EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_ext_zeroout);
6289EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_register_shrinker);
6290EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_unregister_shrinker);
6291EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_map_create_blocks);
6292EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_init_tree);
6293EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_lookup_extent);
6294EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_insert_extent);
6295EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_ext_insert_extent);
6296EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_find_extent);
6297EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_issue_zeroout);
6298EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_map_query_blocks);
6243#endif6299#endif
fs/ext4/fast_commit.c+10−7
@@ -975,13 +975,13 @@ static int ext4_fc_flush_data(journal_t *journal) · 974 unmodified lines
975 int ret = 0;975 int ret = 0;
976 976
977 list_for_each_entry(ei, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) {977 list_for_each_entry(ei, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) {
978 ret = jbd2_submit_inode_data(journal, ei->jinode);978 ret = jbd2_submit_inode_data(journal, READ_ONCE(ei->jinode));
979 if (ret)979 if (ret)
980 return ret;980 return ret;
981 }981 }
982 982
983 list_for_each_entry(ei, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) {983 list_for_each_entry(ei, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) {
984 ret = jbd2_wait_inode_data(journal, ei->jinode);984 ret = jbd2_wait_inode_data(journal, READ_ONCE(ei->jinode));
985 if (ret)985 if (ret)
986 return ret;986 return ret;
987 }987 }
@@ -1613,19 +1613,21 @@ static int ext4_fc_replay_inode(struct super_block *sb, · 625 unmodified lines
1613 /* Immediately update the inode on disk. */1613 /* Immediately update the inode on disk. */
1614 ret = ext4_handle_dirty_metadata(NULL, NULL, iloc.bh);1614 ret = ext4_handle_dirty_metadata(NULL, NULL, iloc.bh);
1615 if (ret)1615 if (ret)
1616 goto out;1616 goto out_brelse;
1617 ret = sync_dirty_buffer(iloc.bh);1617 ret = sync_dirty_buffer(iloc.bh);
1618 if (ret)1618 if (ret)
1619 goto out;1619 goto out_brelse;
1620 ret = ext4_mark_inode_used(sb, ino);1620 ret = ext4_mark_inode_used(sb, ino);
1621 if (ret)1621 if (ret)
1622 goto out;1622 goto out_brelse;
1623 1623
1624 /* Given that we just wrote the inode on disk, this SHOULD succeed. */1624 /* Given that we just wrote the inode on disk, this SHOULD succeed. */
1625 inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL);1625 inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL);
1626 if (IS_ERR(inode)) {1626 if (IS_ERR(inode)) {
1627 ext4_debug("Inode not found.");1627 ext4_debug("Inode not found.");
1628 return -EFSCORRUPTED;1628 inode = NULL;
1629 ret = -EFSCORRUPTED;
1630 goto out_brelse;
1629 }1631 }
1630 1632
1631 /*1633 /*
@@ -1642,13 +1644,14 @@ static int ext4_fc_replay_inode(struct super_block *sb, · 10 unmodified lines
1642 ext4_inode_csum_set(inode, ext4_raw_inode(&iloc), EXT4_I(inode));1644 ext4_inode_csum_set(inode, ext4_raw_inode(&iloc), EXT4_I(inode));
1643 ret = ext4_handle_dirty_metadata(NULL, NULL, iloc.bh);1645 ret = ext4_handle_dirty_metadata(NULL, NULL, iloc.bh);
1644 sync_dirty_buffer(iloc.bh);1646 sync_dirty_buffer(iloc.bh);
1647out_brelse:
1645 brelse(iloc.bh);1648 brelse(iloc.bh);
1646out:1649out:
1647 iput(inode);1650 iput(inode);
1648 if (!ret)1651 if (!ret)
1649 blkdev_issue_flush(sb->s_bdev);1652 blkdev_issue_flush(sb->s_bdev);
1650 1653
1651 return 0;1654 return ret;
1652}1655}
1653 1656
1654/*1657/*
fs/ext4/fsync.c+14−2
@@ -83,11 +83,23 @@ static int ext4_fsync_nojournal(struct file *file, loff_t start, loff_t end, · 82 unmodified lines
83 int datasync, bool *needs_barrier)83 int datasync, bool *needs_barrier)
84{84{
85 struct inode *inode = file->f_inode;85 struct inode *inode = file->f_inode;
86 struct writeback_control wbc = {
87 .sync_mode = WB_SYNC_ALL,
88 .nr_to_write = 0,
89 };
86 int ret;90 int ret;
87 91
88 ret = generic_buffers_fsync_noflush(file, start, end, datasync);92 ret = generic_buffers_fsync_noflush(file, start, end, datasync);
89 if (!ret)93 if (ret)
90 ret = ext4_sync_parent(inode);94 return ret;
95
96 /* Force writeout of inode table buffer to disk */
97 ret = ext4_write_inode(inode, &wbc);
98 if (ret)
99 return ret;
100
101 ret = ext4_sync_parent(inode);
102
91 if (test_opt(inode->i_sb, BARRIER))103 if (test_opt(inode->i_sb, BARRIER))
92 *needs_barrier = true;104 *needs_barrier = true;
93 105
fs/ext4/ialloc.c+6−0
@@ -686,6 +686,12 @@ static int recently_deleted(struct super_block *sb, ext4_group_t group, int ino) · 685 unmodified lines
686 if (unlikely(!gdp))686 if (unlikely(!gdp))
687 return 0;687 return 0;
688 688
689 /* Inode was never used in this filesystem? */
690 if (ext4_has_group_desc_csum(sb) &&
691 (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
692 ino >= EXT4_INODES_PER_GROUP(sb) - ext4_itable_unused_count(sb, gdp)))
693 return 0;
694
689 bh = sb_find_get_block(sb, ext4_inode_table(sb, gdp) +695 bh = sb_find_get_block(sb, ext4_inode_table(sb, gdp) +
690 (ino / inodes_per_block));696 (ino / inodes_per_block));
691 if (!bh || !buffer_uptodate(bh))697 if (!bh || !buffer_uptodate(bh))
fs/ext4/inline.c+9−1
@@ -522,7 +522,15 @@ static int ext4_read_inline_folio(struct inode *inode, struct folio *folio) · 521 unmodified lines
522 goto out;522 goto out;
523 523
524 len = min_t(size_t, ext4_get_inline_size(inode), i_size_read(inode));524 len = min_t(size_t, ext4_get_inline_size(inode), i_size_read(inode));
525 BUG_ON(len > PAGE_SIZE);525
526 if (len > PAGE_SIZE) {
527 ext4_error_inode(inode, __func__, __LINE__, 0,
528 "inline size %zu exceeds PAGE_SIZE", len);
529 ret = -EFSCORRUPTED;
530 brelse(iloc.bh);
531 goto out;
532 }
533
526 kaddr = kmap_local_folio(folio, 0);534 kaddr = kmap_local_folio(folio, 0);
527 ret = ext4_read_inline_data(inode, kaddr, len, &iloc);535 ret = ext4_read_inline_data(inode, kaddr, len, &iloc);
528 kaddr = folio_zero_tail(folio, len, kaddr + len);536 kaddr = folio_zero_tail(folio, len, kaddr + len);
fs/ext4/inode.c+60−15
@@ -128,6 +128,8 @@ void ext4_inode_csum_set(struct inode *inode, struct ext4_inode *raw, · 127 unmodified lines
128static inline int ext4_begin_ordered_truncate(struct inode *inode,128static inline int ext4_begin_ordered_truncate(struct inode *inode,
129 loff_t new_size)129 loff_t new_size)
130{130{
131 struct jbd2_inode *jinode = READ_ONCE(EXT4_I(inode)->jinode);
132
131 trace_ext4_begin_ordered_truncate(inode, new_size);133 trace_ext4_begin_ordered_truncate(inode, new_size);
132 /*134 /*
133 * If jinode is zero, then we never opened the file for135 * If jinode is zero, then we never opened the file for
@@ -135,10 +137,10 @@ static inline int ext4_begin_ordered_truncate(struct inode *inode, · 1 unmodified line
135 * jbd2_journal_begin_ordered_truncate() since there's no137 * jbd2_journal_begin_ordered_truncate() since there's no
136 * outstanding writes we need to flush.138 * outstanding writes we need to flush.
137 */139 */
138 if (!EXT4_I(inode)->jinode)140 if (!jinode)
139 return 0;141 return 0;
140 return jbd2_journal_begin_ordered_truncate(EXT4_JOURNAL(inode),142 return jbd2_journal_begin_ordered_truncate(EXT4_JOURNAL(inode),
141 EXT4_I(inode)->jinode,143 jinode,
142 new_size);144 new_size);
143}145}
144 146
@@ -184,6 +186,14 @@ void ext4_evict_inode(struct inode *inode) · 39 unmodified lines
184 if (EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)186 if (EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)
185 ext4_evict_ea_inode(inode);187 ext4_evict_ea_inode(inode);
186 if (inode->i_nlink) {188 if (inode->i_nlink) {
189 /*
190 * If there's dirty page will lead to data loss, user
191 * could see stale data.
192 */
193 if (unlikely(!ext4_emergency_state(inode->i_sb) &&
194 mapping_tagged(&inode->i_data, PAGECACHE_TAG_DIRTY)))
195 ext4_warning_inode(inode, "data will be lost");
196
187 truncate_inode_pages_final(&inode->i_data);197 truncate_inode_pages_final(&inode->i_data);
188 198
189 goto no_delete;199 goto no_delete;
@@ -4451,8 +4461,13 @@ int ext4_inode_attach_jinode(struct inode *inode) · 4261 unmodified lines
4451 spin_unlock(&inode->i_lock);4461 spin_unlock(&inode->i_lock);
4452 return -ENOMEM;4462 return -ENOMEM;
4453 }4463 }
4454 ei->jinode = jinode;4464 jbd2_journal_init_jbd_inode(jinode, inode);
4455 jbd2_journal_init_jbd_inode(ei->jinode, inode);4465 /*
4466 * Publish ->jinode only after it is fully initialized so that
4467 * readers never observe a partially initialized jbd2_inode.
4468 */
4469 smp_wmb();
4470 WRITE_ONCE(ei->jinode, jinode);
4456 jinode = NULL;4471 jinode = NULL;
4457 }4472 }
4458 spin_unlock(&inode->i_lock);4473 spin_unlock(&inode->i_lock);
@@ -5401,18 +5416,36 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, · 942 unmodified lines
5401 inode->i_op = &ext4_encrypted_symlink_inode_operations;5416 inode->i_op = &ext4_encrypted_symlink_inode_operations;
5402 } else if (ext4_inode_is_fast_symlink(inode)) {5417 } else if (ext4_inode_is_fast_symlink(inode)) {
5403 inode->i_op = &ext4_fast_symlink_inode_operations;5418 inode->i_op = &ext4_fast_symlink_inode_operations;
5404 if (inode->i_size == 0 ||5419
5405 inode->i_size >= sizeof(ei->i_data) ||5420 /*
5406 strnlen((char *)ei->i_data, inode->i_size + 1) !=5421 * Orphan cleanup can see inodes with i_size == 0
5407 inode->i_size) {5422 * and i_data uninitialized. Skip size checks in
5408 ext4_error_inode(inode, function, line, 0,5423 * that case. This is safe because the first thing
5409 "invalid fast symlink length %llu",5424 * ext4_evict_inode() does for fast symlinks is
5410 (unsigned long long)inode->i_size);5425 * clearing of i_data and i_size.
5411 ret = -EFSCORRUPTED;5426 */
5412 goto bad_inode;5427 if ((EXT4_SB(sb)->s_mount_state & EXT4_ORPHAN_FS)) {
5428 if (inode->i_nlink != 0) {
5429 ext4_error_inode(inode, function, line, 0,
5430 "invalid orphan symlink nlink %d",
5431 inode->i_nlink);
5432 ret = -EFSCORRUPTED;
5433 goto bad_inode;
5434 }
5435 } else {
5436 if (inode->i_size == 0 ||
5437 inode->i_size >= sizeof(ei->i_data) ||
5438 strnlen((char *)ei->i_data, inode->i_size + 1) !=
5439 inode->i_size) {
5440 ext4_error_inode(inode, function, line, 0,
5441 "invalid fast symlink length %llu",
5442 (unsigned long long)inode->i_size);
5443 ret = -EFSCORRUPTED;
5444 goto bad_inode;
5445 }
5446 inode_set_cached_link(inode, (char *)ei->i_data,
5447 inode->i_size);
5413 }5448 }
5414 inode_set_cached_link(inode, (char *)ei->i_data,
5415 inode->i_size);
5416 } else {5449 } else {
5417 inode->i_op = &ext4_symlink_inode_operations;5450 inode->i_op = &ext4_symlink_inode_operations;
5418 }5451 }
@@ -5849,6 +5882,18 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry, · 430 unmodified lines
5849 if (attr->ia_size == inode->i_size)5882 if (attr->ia_size == inode->i_size)
5850 inc_ivers = false;5883 inc_ivers = false;
5851 5884
5885 /*
5886 * If file has inline data but new size exceeds inline capacity,
5887 * convert to extent-based storage first to prevent inconsistent
5888 * state (inline flag set but size exceeds inline capacity).
5889 */
5890 if (ext4_has_inline_data(inode) &&
5891 attr->ia_size > EXT4_I(inode)->i_inline_size) {
5892 error = ext4_convert_inline_data(inode);
5893 if (error)
5894 goto err_out;
5895 }
5896
5852 if (shrink) {5897 if (shrink) {
5853 if (ext4_should_order_data(inode)) {5898 if (ext4_should_order_data(inode)) {
5854 error = ext4_begin_ordered_truncate(inode,5899 error = ext4_begin_ordered_truncate(inode,
fs/ext4/mballoc-test.c+41−40
@@ -8,6 +8,7 @@ · 7 unmodified lines
8#include <linux/random.h>8#include <linux/random.h>
9 9
10#include "ext4.h"10#include "ext4.h"
11#include "mballoc.h"
11 12
12struct mbt_grp_ctx {13struct mbt_grp_ctx {
13 struct buffer_head bitmap_bh;14 struct buffer_head bitmap_bh;
@@ -336,7 +337,7 @@ ext4_mb_mark_context_stub(handle_t *handle, struct super_block *sb, bool state, · 322 unmodified lines
336 if (state)337 if (state)
337 mb_set_bits(bitmap_bh->b_data, blkoff, len);338 mb_set_bits(bitmap_bh->b_data, blkoff, len);
338 else339 else
339 mb_clear_bits(bitmap_bh->b_data, blkoff, len);340 mb_clear_bits_test(bitmap_bh->b_data, blkoff, len);
340 341
341 return 0;342 return 0;
342}343}
@@ -413,14 +414,14 @@ static void test_new_blocks_simple(struct kunit *test) · 70 unmodified lines
413 414
414 /* get block at goal */415 /* get block at goal */
415 ar.goal = ext4_group_first_block_no(sb, goal_group);416 ar.goal = ext4_group_first_block_no(sb, goal_group);
416 found = ext4_mb_new_blocks_simple(&ar, &err);417 found = ext4_mb_new_blocks_simple_test(&ar, &err);
417 KUNIT_ASSERT_EQ_MSG(test, ar.goal, found,418 KUNIT_ASSERT_EQ_MSG(test, ar.goal, found,
418 "failed to alloc block at goal, expected %llu found %llu",419 "failed to alloc block at goal, expected %llu found %llu",
419 ar.goal, found);420 ar.goal, found);
420 421
421 /* get block after goal in goal group */422 /* get block after goal in goal group */
422 ar.goal = ext4_group_first_block_no(sb, goal_group);423 ar.goal = ext4_group_first_block_no(sb, goal_group);
423 found = ext4_mb_new_blocks_simple(&ar, &err);424 found = ext4_mb_new_blocks_simple_test(&ar, &err);
424 KUNIT_ASSERT_EQ_MSG(test, ar.goal + EXT4_C2B(sbi, 1), found,425 KUNIT_ASSERT_EQ_MSG(test, ar.goal + EXT4_C2B(sbi, 1), found,
425 "failed to alloc block after goal in goal group, expected %llu found %llu",426 "failed to alloc block after goal in goal group, expected %llu found %llu",
426 ar.goal + 1, found);427 ar.goal + 1, found);
@@ -428,7 +429,7 @@ static void test_new_blocks_simple(struct kunit *test) · 1 unmodified line
428 /* get block after goal group */429 /* get block after goal group */
429 mbt_ctx_mark_used(sb, goal_group, 0, EXT4_CLUSTERS_PER_GROUP(sb));430 mbt_ctx_mark_used(sb, goal_group, 0, EXT4_CLUSTERS_PER_GROUP(sb));
430 ar.goal = ext4_group_first_block_no(sb, goal_group);431 ar.goal = ext4_group_first_block_no(sb, goal_group);
431 found = ext4_mb_new_blocks_simple(&ar, &err);432 found = ext4_mb_new_blocks_simple_test(&ar, &err);
432 KUNIT_ASSERT_EQ_MSG(test,433 KUNIT_ASSERT_EQ_MSG(test,
433 ext4_group_first_block_no(sb, goal_group + 1), found,434 ext4_group_first_block_no(sb, goal_group + 1), found,
434 "failed to alloc block after goal group, expected %llu found %llu",435 "failed to alloc block after goal group, expected %llu found %llu",
@@ -438,7 +439,7 @@ static void test_new_blocks_simple(struct kunit *test) · 3 unmodified lines
438 for (i = goal_group; i < ext4_get_groups_count(sb); i++)439 for (i = goal_group; i < ext4_get_groups_count(sb); i++)
439 mbt_ctx_mark_used(sb, i, 0, EXT4_CLUSTERS_PER_GROUP(sb));440 mbt_ctx_mark_used(sb, i, 0, EXT4_CLUSTERS_PER_GROUP(sb));
440 ar.goal = ext4_group_first_block_no(sb, goal_group);441 ar.goal = ext4_group_first_block_no(sb, goal_group);
441 found = ext4_mb_new_blocks_simple(&ar, &err);442 found = ext4_mb_new_blocks_simple_test(&ar, &err);
442 KUNIT_ASSERT_EQ_MSG(test,443 KUNIT_ASSERT_EQ_MSG(test,
443 ext4_group_first_block_no(sb, 0) + EXT4_C2B(sbi, 1), found,444 ext4_group_first_block_no(sb, 0) + EXT4_C2B(sbi, 1), found,
444 "failed to alloc block before goal group, expected %llu found %llu",445 "failed to alloc block before goal group, expected %llu found %llu",
@@ -448,7 +449,7 @@ static void test_new_blocks_simple(struct kunit *test) · 3 unmodified lines
448 for (i = 0; i < ext4_get_groups_count(sb); i++)449 for (i = 0; i < ext4_get_groups_count(sb); i++)
449 mbt_ctx_mark_used(sb, i, 0, EXT4_CLUSTERS_PER_GROUP(sb));450 mbt_ctx_mark_used(sb, i, 0, EXT4_CLUSTERS_PER_GROUP(sb));
450 ar.goal = ext4_group_first_block_no(sb, goal_group);451 ar.goal = ext4_group_first_block_no(sb, goal_group);
451 found = ext4_mb_new_blocks_simple(&ar, &err);452 found = ext4_mb_new_blocks_simple_test(&ar, &err);
452 KUNIT_ASSERT_NE_MSG(test, err, 0,453 KUNIT_ASSERT_NE_MSG(test, err, 0,
453 "unexpectedly get block when no block is available");454 "unexpectedly get block when no block is available");
454}455}
@@ -492,16 +493,16 @@ validate_free_blocks_simple(struct kunit *test, struct super_block *sb, · 37 unmodified lines
492 continue;493 continue;
493 494
494 bitmap = mbt_ctx_bitmap(sb, i);495 bitmap = mbt_ctx_bitmap(sb, i);
495 bit = mb_find_next_zero_bit(bitmap, max, 0);496 bit = mb_find_next_zero_bit_test(bitmap, max, 0);
496 KUNIT_ASSERT_EQ_MSG(test, bit, max,497 KUNIT_ASSERT_EQ_MSG(test, bit, max,
497 "free block on unexpected group %d", i);498 "free block on unexpected group %d", i);
498 }499 }
499 500
500 bitmap = mbt_ctx_bitmap(sb, goal_group);501 bitmap = mbt_ctx_bitmap(sb, goal_group);
501 bit = mb_find_next_zero_bit(bitmap, max, 0);502 bit = mb_find_next_zero_bit_test(bitmap, max, 0);
502 KUNIT_ASSERT_EQ(test, bit, start);503 KUNIT_ASSERT_EQ(test, bit, start);
503 504
504 bit = mb_find_next_bit(bitmap, max, bit + 1);505 bit = mb_find_next_bit_test(bitmap, max, bit + 1);
505 KUNIT_ASSERT_EQ(test, bit, start + len);506 KUNIT_ASSERT_EQ(test, bit, start + len);
506}507}
507 508
@@ -524,7 +525,7 @@ test_free_blocks_simple_range(struct kunit *test, ext4_group_t goal_group, · 16 unmodified lines
524 525
525 block = ext4_group_first_block_no(sb, goal_group) +526 block = ext4_group_first_block_no(sb, goal_group) +
526 EXT4_C2B(sbi, start);527 EXT4_C2B(sbi, start);
527 ext4_free_blocks_simple(inode, block, len);528 ext4_free_blocks_simple_test(inode, block, len);
528 validate_free_blocks_simple(test, sb, goal_group, start, len);529 validate_free_blocks_simple(test, sb, goal_group, start, len);
529 mbt_ctx_mark_used(sb, goal_group, 0, EXT4_CLUSTERS_PER_GROUP(sb));530 mbt_ctx_mark_used(sb, goal_group, 0, EXT4_CLUSTERS_PER_GROUP(sb));
530}531}
@@ -566,15 +567,15 @@ test_mark_diskspace_used_range(struct kunit *test, · 35 unmodified lines
566 567
567 bitmap = mbt_ctx_bitmap(sb, TEST_GOAL_GROUP);568 bitmap = mbt_ctx_bitmap(sb, TEST_GOAL_GROUP);
568 memset(bitmap, 0, sb->s_blocksize);569 memset(bitmap, 0, sb->s_blocksize);
569 ret = ext4_mb_mark_diskspace_used(ac, NULL);570 ret = ext4_mb_mark_diskspace_used_test(ac, NULL);
570 KUNIT_ASSERT_EQ(test, ret, 0);571 KUNIT_ASSERT_EQ(test, ret, 0);
571 572
572 max = EXT4_CLUSTERS_PER_GROUP(sb);573 max = EXT4_CLUSTERS_PER_GROUP(sb);
573 i = mb_find_next_bit(bitmap, max, 0);574 i = mb_find_next_bit_test(bitmap, max, 0);
574 KUNIT_ASSERT_EQ(test, i, start);575 KUNIT_ASSERT_EQ(test, i, start);
575 i = mb_find_next_zero_bit(bitmap, max, i + 1);576 i = mb_find_next_zero_bit_test(bitmap, max, i + 1);
576 KUNIT_ASSERT_EQ(test, i, start + len);577 KUNIT_ASSERT_EQ(test, i, start + len);
577 i = mb_find_next_bit(bitmap, max, i + 1);578 i = mb_find_next_bit_test(bitmap, max, i + 1);
578 KUNIT_ASSERT_EQ(test, max, i);579 KUNIT_ASSERT_EQ(test, max, i);
579}580}
580 581
@@ -617,54 +618,54 @@ static void mbt_generate_buddy(struct super_block *sb, void *buddy, · 36 unmodified lines
617 max = EXT4_CLUSTERS_PER_GROUP(sb);618 max = EXT4_CLUSTERS_PER_GROUP(sb);
618 bb_h = buddy + sbi->s_mb_offsets[1];619 bb_h = buddy + sbi->s_mb_offsets[1];
619 620
620 off = mb_find_next_zero_bit(bb, max, 0);621 off = mb_find_next_zero_bit_test(bb, max, 0);
621 grp->bb_first_free = off;622 grp->bb_first_free = off;
622 while (off < max) {623 while (off < max) {
623 grp->bb_counters[0]++;624 grp->bb_counters[0]++;
624 grp->bb_free++;625 grp->bb_free++;
625 626
626 if (!(off & 1) && !mb_test_bit(off + 1, bb)) {627 if (!(off & 1) && !mb_test_bit_test(off + 1, bb)) {
627 grp->bb_free++;628 grp->bb_free++;
628 grp->bb_counters[0]--;629 grp->bb_counters[0]--;
629 mb_clear_bit(off >> 1, bb_h);630 mb_clear_bit_test(off >> 1, bb_h);
630 grp->bb_counters[1]++;631 grp->bb_counters[1]++;
631 grp->bb_largest_free_order = 1;632 grp->bb_largest_free_order = 1;
632 off++;633 off++;
633 }634 }
634 635
635 off = mb_find_next_zero_bit(bb, max, off + 1);636 off = mb_find_next_zero_bit_test(bb, max, off + 1);
636 }637 }
637 638
638 for (order = 1; order < MB_NUM_ORDERS(sb) - 1; order++) {639 for (order = 1; order < MB_NUM_ORDERS(sb) - 1; order++) {
639 bb = buddy + sbi->s_mb_offsets[order];640 bb = buddy + sbi->s_mb_offsets[order];
640 bb_h = buddy + sbi->s_mb_offsets[order + 1];641 bb_h = buddy + sbi->s_mb_offsets[order + 1];
641 max = max >> 1;642 max = max >> 1;
642 off = mb_find_next_zero_bit(bb, max, 0);643 off = mb_find_next_zero_bit_test(bb, max, 0);
643 644
644 while (off < max) {645 while (off < max) {
645 if (!(off & 1) && !mb_test_bit(off + 1, bb)) {646 if (!(off & 1) && !mb_test_bit_test(off + 1, bb)) {
646 mb_set_bits(bb, off, 2);647 mb_set_bits(bb, off, 2);
647 grp->bb_counters[order] -= 2;648 grp->bb_counters[order] -= 2;
648 mb_clear_bit(off >> 1, bb_h);649 mb_clear_bit_test(off >> 1, bb_h);
649 grp->bb_counters[order + 1]++;650 grp->bb_counters[order + 1]++;
650 grp->bb_largest_free_order = order + 1;651 grp->bb_largest_free_order = order + 1;
651 off++;652 off++;
652 }653 }
653 654
654 off = mb_find_next_zero_bit(bb, max, off + 1);655 off = mb_find_next_zero_bit_test(bb, max, off + 1);
655 }656 }
656 }657 }
657 658
658 max = EXT4_CLUSTERS_PER_GROUP(sb);659 max = EXT4_CLUSTERS_PER_GROUP(sb);
659 off = mb_find_next_zero_bit(bitmap, max, 0);660 off = mb_find_next_zero_bit_test(bitmap, max, 0);
660 while (off < max) {661 while (off < max) {
661 grp->bb_fragments++;662 grp->bb_fragments++;
662 663
663 off = mb_find_next_bit(bitmap, max, off + 1);664 off = mb_find_next_bit_test(bitmap, max, off + 1);
664 if (off + 1 >= max)665 if (off + 1 >= max)
665 break;666 break;
666 667
667 off = mb_find_next_zero_bit(bitmap, max, off + 1);668 off = mb_find_next_zero_bit_test(bitmap, max, off + 1);
668 }669 }
669}670}
670 671
@@ -706,7 +707,7 @@ do_test_generate_buddy(struct kunit *test, struct super_block *sb, void *bitmap, · 35 unmodified lines
706 /* needed by validation in ext4_mb_generate_buddy */707 /* needed by validation in ext4_mb_generate_buddy */
707 ext4_grp->bb_free = mbt_grp->bb_free;708 ext4_grp->bb_free = mbt_grp->bb_free;
708 memset(ext4_buddy, 0xff, sb->s_blocksize);709 memset(ext4_buddy, 0xff, sb->s_blocksize);
709 ext4_mb_generate_buddy(sb, ext4_buddy, bitmap, TEST_GOAL_GROUP,710 ext4_mb_generate_buddy_test(sb, ext4_buddy, bitmap, TEST_GOAL_GROUP,
710 ext4_grp);711 ext4_grp);
711 712
712 KUNIT_ASSERT_EQ(test, memcmp(mbt_buddy, ext4_buddy, sb->s_blocksize),713 KUNIT_ASSERT_EQ(test, memcmp(mbt_buddy, ext4_buddy, sb->s_blocksize),
@@ -760,7 +761,7 @@ test_mb_mark_used_range(struct kunit *test, struct ext4_buddy *e4b, · 47 unmodified lines
760 ex.fe_group = TEST_GOAL_GROUP;761 ex.fe_group = TEST_GOAL_GROUP;
761 762
762 ext4_lock_group(sb, TEST_GOAL_GROUP);763 ext4_lock_group(sb, TEST_GOAL_GROUP);
763 mb_mark_used(e4b, &ex);764 mb_mark_used_test(e4b, &ex);
764 ext4_unlock_group(sb, TEST_GOAL_GROUP);765 ext4_unlock_group(sb, TEST_GOAL_GROUP);
765 766
766 mb_set_bits(bitmap, start, len);767 mb_set_bits(bitmap, start, len);
@@ -769,7 +770,7 @@ test_mb_mark_used_range(struct kunit *test, struct ext4_buddy *e4b, · 2 unmodified lines
769 memset(buddy, 0xff, sb->s_blocksize);770 memset(buddy, 0xff, sb->s_blocksize);
770 for (i = 0; i < MB_NUM_ORDERS(sb); i++)771 for (i = 0; i < MB_NUM_ORDERS(sb); i++)
771 grp->bb_counters[i] = 0;772 grp->bb_counters[i] = 0;
772 ext4_mb_generate_buddy(sb, buddy, bitmap, 0, grp);773 ext4_mb_generate_buddy_test(sb, buddy, bitmap, 0, grp);
773 774
774 KUNIT_ASSERT_EQ(test, memcmp(buddy, e4b->bd_buddy, sb->s_blocksize),775 KUNIT_ASSERT_EQ(test, memcmp(buddy, e4b->bd_buddy, sb->s_blocksize),
775 0);776 0);
@@ -798,7 +799,7 @@ static void test_mb_mark_used(struct kunit *test) · 22 unmodified lines
798 bb_counters[MB_NUM_ORDERS(sb)]), GFP_KERNEL);799 bb_counters[MB_NUM_ORDERS(sb)]), GFP_KERNEL);
799 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, grp);800 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, grp);
800 801
801 ret = ext4_mb_load_buddy(sb, TEST_GOAL_GROUP, &e4b);802 ret = ext4_mb_load_buddy_test(sb, TEST_GOAL_GROUP, &e4b);
802 KUNIT_ASSERT_EQ(test, ret, 0);803 KUNIT_ASSERT_EQ(test, ret, 0);
803 804
804 grp->bb_free = EXT4_CLUSTERS_PER_GROUP(sb);805 grp->bb_free = EXT4_CLUSTERS_PER_GROUP(sb);
@@ -809,7 +810,7 @@ static void test_mb_mark_used(struct kunit *test) · 4 unmodified lines
809 test_mb_mark_used_range(test, &e4b, ranges[i].start,810 test_mb_mark_used_range(test, &e4b, ranges[i].start,
810 ranges[i].len, bitmap, buddy, grp);811 ranges[i].len, bitmap, buddy, grp);
811 812
812 ext4_mb_unload_buddy(&e4b);813 ext4_mb_unload_buddy_test(&e4b);
813}814}
814 815
815static void816static void
@@ -825,16 +826,16 @@ test_mb_free_blocks_range(struct kunit *test, struct ext4_buddy *e4b, · 9 unmodified lines
825 return;826 return;
826 827
827 ext4_lock_group(sb, e4b->bd_group);828 ext4_lock_group(sb, e4b->bd_group);
828 mb_free_blocks(NULL, e4b, start, len);829 mb_free_blocks_test(NULL, e4b, start, len);
829 ext4_unlock_group(sb, e4b->bd_group);830 ext4_unlock_group(sb, e4b->bd_group);
830 831
831 mb_clear_bits(bitmap, start, len);832 mb_clear_bits_test(bitmap, start, len);
832 /* bypass bb_free validatoin in ext4_mb_generate_buddy */833 /* bypass bb_free validatoin in ext4_mb_generate_buddy */
833 grp->bb_free += len;834 grp->bb_free += len;
834 memset(buddy, 0xff, sb->s_blocksize);835 memset(buddy, 0xff, sb->s_blocksize);
835 for (i = 0; i < MB_NUM_ORDERS(sb); i++)836 for (i = 0; i < MB_NUM_ORDERS(sb); i++)
836 grp->bb_counters[i] = 0;837 grp->bb_counters[i] = 0;
837 ext4_mb_generate_buddy(sb, buddy, bitmap, 0, grp);838 ext4_mb_generate_buddy_test(sb, buddy, bitmap, 0, grp);
838 839
839 KUNIT_ASSERT_EQ(test, memcmp(buddy, e4b->bd_buddy, sb->s_blocksize),840 KUNIT_ASSERT_EQ(test, memcmp(buddy, e4b->bd_buddy, sb->s_blocksize),
840 0);841 0);
@@ -865,7 +866,7 @@ static void test_mb_free_blocks(struct kunit *test) · 24 unmodified lines
865 bb_counters[MB_NUM_ORDERS(sb)]), GFP_KERNEL);866 bb_counters[MB_NUM_ORDERS(sb)]), GFP_KERNEL);
866 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, grp);867 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, grp);
867 868
868 ret = ext4_mb_load_buddy(sb, TEST_GOAL_GROUP, &e4b);869 ret = ext4_mb_load_buddy_test(sb, TEST_GOAL_GROUP, &e4b);
869 KUNIT_ASSERT_EQ(test, ret, 0);870 KUNIT_ASSERT_EQ(test, ret, 0);
870 871
871 ex.fe_start = 0;872 ex.fe_start = 0;
@@ -873,7 +874,7 @@ static void test_mb_free_blocks(struct kunit *test) · 1 unmodified line
873 ex.fe_group = TEST_GOAL_GROUP;874 ex.fe_group = TEST_GOAL_GROUP;
874 875
875 ext4_lock_group(sb, TEST_GOAL_GROUP);876 ext4_lock_group(sb, TEST_GOAL_GROUP);
876 mb_mark_used(&e4b, &ex);877 mb_mark_used_test(&e4b, &ex);
877 ext4_unlock_group(sb, TEST_GOAL_GROUP);878 ext4_unlock_group(sb, TEST_GOAL_GROUP);
878 879
879 grp->bb_free = 0;880 grp->bb_free = 0;
@@ -886,7 +887,7 @@ static void test_mb_free_blocks(struct kunit *test) · 6 unmodified lines
886 test_mb_free_blocks_range(test, &e4b, ranges[i].start,887 test_mb_free_blocks_range(test, &e4b, ranges[i].start,
887 ranges[i].len, bitmap, buddy, grp);888 ranges[i].len, bitmap, buddy, grp);
888 889
889 ext4_mb_unload_buddy(&e4b);890 ext4_mb_unload_buddy_test(&e4b);
890}891}
891 892
892#define COUNT_FOR_ESTIMATE 100000893#define COUNT_FOR_ESTIMATE 100000
@@ -904,7 +905,7 @@ static void test_mb_mark_used_cost(struct kunit *test) · 11 unmodified lines
904 if (sb->s_blocksize > PAGE_SIZE)905 if (sb->s_blocksize > PAGE_SIZE)
905 kunit_skip(test, "blocksize exceeds pagesize");906 kunit_skip(test, "blocksize exceeds pagesize");
906 907
907 ret = ext4_mb_load_buddy(sb, TEST_GOAL_GROUP, &e4b);908 ret = ext4_mb_load_buddy_test(sb, TEST_GOAL_GROUP, &e4b);
908 KUNIT_ASSERT_EQ(test, ret, 0);909 KUNIT_ASSERT_EQ(test, ret, 0);
909 910
910 ex.fe_group = TEST_GOAL_GROUP;911 ex.fe_group = TEST_GOAL_GROUP;
@@ -918,7 +919,7 @@ static void test_mb_mark_used_cost(struct kunit *test) · 7 unmodified lines
918 ex.fe_start = ranges[i].start;919 ex.fe_start = ranges[i].start;
919 ex.fe_len = ranges[i].len;920 ex.fe_len = ranges[i].len;
920 ext4_lock_group(sb, TEST_GOAL_GROUP);921 ext4_lock_group(sb, TEST_GOAL_GROUP);
921 mb_mark_used(&e4b, &ex);922 mb_mark_used_test(&e4b, &ex);
922 ext4_unlock_group(sb, TEST_GOAL_GROUP);923 ext4_unlock_group(sb, TEST_GOAL_GROUP);
923 }924 }
924 end = jiffies;925 end = jiffies;
@@ -929,14 +930,14 @@ static void test_mb_mark_used_cost(struct kunit *test) · 4 unmodified lines
929 continue;930 continue;
930 931
931 ext4_lock_group(sb, TEST_GOAL_GROUP);932 ext4_lock_group(sb, TEST_GOAL_GROUP);
932 mb_free_blocks(NULL, &e4b, ranges[i].start,933 mb_free_blocks_test(NULL, &e4b, ranges[i].start,
933 ranges[i].len);934 ranges[i].len);
934 ext4_unlock_group(sb, TEST_GOAL_GROUP);935 ext4_unlock_group(sb, TEST_GOAL_GROUP);
935 }936 }
936 }937 }
937 938
938 kunit_info(test, "costed jiffies %lu\n", all);939 kunit_info(test, "costed jiffies %lu\n", all);
939 ext4_mb_unload_buddy(&e4b);940 ext4_mb_unload_buddy_test(&e4b);
940}941}
941 942
942static const struct mbt_ext4_block_layout mbt_test_layouts[] = {943static const struct mbt_ext4_block_layout mbt_test_layouts[] = {
fs/ext4/mballoc.c+114−18
@@ -1199,6 +1199,8 @@ static int ext4_mb_scan_groups(struct ext4_allocation_context *ac) · 1198 unmodified lines
1199 1199
1200 /* searching for the right group start from the goal value specified */1200 /* searching for the right group start from the goal value specified */
1201 start = ac->ac_g_ex.fe_group;1201 start = ac->ac_g_ex.fe_group;
1202 if (start >= ngroups)
1203 start = 0;
1202 ac->ac_prefetch_grp = start;1204 ac->ac_prefetch_grp = start;
1203 ac->ac_prefetch_nr = 0;1205 ac->ac_prefetch_nr = 0;
1204 1206
@@ -2443,8 +2445,12 @@ int ext4_mb_find_by_goal(struct ext4_allocation_context *ac, · 1238 unmodified lines
2443 return 0;2445 return 0;
2444 2446
2445 err = ext4_mb_load_buddy(ac->ac_sb, group, e4b);2447 err = ext4_mb_load_buddy(ac->ac_sb, group, e4b);
2446 if (err)2448 if (err) {
2449 if (EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info) &&
2450 !(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY))
2451 return 0;
2447 return err;2452 return err;
2453 }
2448 2454
2449 ext4_lock_group(ac->ac_sb, group);2455 ext4_lock_group(ac->ac_sb, group);
2450 if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info)))2456 if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info)))
@@ -3580,9 +3586,7 @@ err_freebuddy: · 1129 unmodified lines
3580 rcu_read_unlock();3586 rcu_read_unlock();
3581 iput(sbi->s_buddy_cache);3587 iput(sbi->s_buddy_cache);
3582err_freesgi:3588err_freesgi:
3583 rcu_read_lock();3589 kvfree(rcu_access_pointer(sbi->s_group_info));
3584 kvfree(rcu_dereference(sbi->s_group_info));
3585 rcu_read_unlock();
3586 return -ENOMEM;3590 return -ENOMEM;
3587}3591}
3588 3592
@@ -3889,15 +3893,14 @@ void ext4_mb_release(struct super_block *sb) · 300 unmodified lines
3889 struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits);3893 struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits);
3890 int count;3894 int count;
3891 3895
3892 if (test_opt(sb, DISCARD)) {3896 /*
3893 /*3897 * wait the discard work to drain all of ext4_free_data
3894 * wait the discard work to drain all of ext4_free_data3898 */
3895 */3899 flush_work(&sbi->s_discard_work);
3896 flush_work(&sbi->s_discard_work);3900 WARN_ON_ONCE(!list_empty(&sbi->s_discard_list));
3897 WARN_ON_ONCE(!list_empty(&sbi->s_discard_list));
3898 }
3899 3901
3900 if (sbi->s_group_info) {3902 group_info = rcu_access_pointer(sbi->s_group_info);
3903 if (group_info) {
3901 for (i = 0; i < ngroups; i++) {3904 for (i = 0; i < ngroups; i++) {
3902 cond_resched();3905 cond_resched();
3903 grinfo = ext4_get_group_info(sb, i);3906 grinfo = ext4_get_group_info(sb, i);
@@ -3915,12 +3918,9 @@ void ext4_mb_release(struct super_block *sb) · 11 unmodified lines
3915 num_meta_group_infos = (ngroups +3918 num_meta_group_infos = (ngroups +
3916 EXT4_DESC_PER_BLOCK(sb) - 1) >>3919 EXT4_DESC_PER_BLOCK(sb) - 1) >>
3917 EXT4_DESC_PER_BLOCK_BITS(sb);3920 EXT4_DESC_PER_BLOCK_BITS(sb);
3918 rcu_read_lock();
3919 group_info = rcu_dereference(sbi->s_group_info);
3920 for (i = 0; i < num_meta_group_infos; i++)3921 for (i = 0; i < num_meta_group_infos; i++)
3921 kfree(group_info[i]);3922 kfree(group_info[i]);
3922 kvfree(group_info);3923 kvfree(group_info);
3923 rcu_read_unlock();
3924 }3924 }
3925 ext4_mb_avg_fragment_size_destroy(sbi);3925 ext4_mb_avg_fragment_size_destroy(sbi);
3926 ext4_mb_largest_free_orders_destroy(sbi);3926 ext4_mb_largest_free_orders_destroy(sbi);
@@ -4084,7 +4084,7 @@ void ext4_exit_mballoc(void) · 157 unmodified lines
4084 4084
4085#define EXT4_MB_BITMAP_MARKED_CHECK 0x00014085#define EXT4_MB_BITMAP_MARKED_CHECK 0x0001
4086#define EXT4_MB_SYNC_UPDATE 0x00024086#define EXT4_MB_SYNC_UPDATE 0x0002
4087static int4087int
4088ext4_mb_mark_context(handle_t *handle, struct super_block *sb, bool state,4088ext4_mb_mark_context(handle_t *handle, struct super_block *sb, bool state,
4089 ext4_group_t group, ext4_grpblk_t blkoff,4089 ext4_group_t group, ext4_grpblk_t blkoff,
4090 ext4_grpblk_t len, int flags, ext4_grpblk_t *ret_changed)4090 ext4_grpblk_t len, int flags, ext4_grpblk_t *ret_changed)
@@ -7188,6 +7188,102 @@ out_unload: · 3097 unmodified lines
7188 return error;7188 return error;
7189}7189}
7190 7190
7191#ifdef CONFIG_EXT4_KUNIT_TESTS7191#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
7192#include "mballoc-test.c"7192void mb_clear_bits_test(void *bm, int cur, int len)
7193{
7194 mb_clear_bits(bm, cur, len);
7195}
7196EXPORT_SYMBOL_FOR_EXT4_TEST(mb_clear_bits_test);
7197
7198ext4_fsblk_t
7199ext4_mb_new_blocks_simple_test(struct ext4_allocation_request *ar,
7200 int *errp)
7201{
7202 return ext4_mb_new_blocks_simple(ar, errp);
7203}
7204EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_new_blocks_simple_test);
7205
7206int mb_find_next_zero_bit_test(void *addr, int max, int start)
7207{
7208 return mb_find_next_zero_bit(addr, max, start);
7209}
7210EXPORT_SYMBOL_FOR_EXT4_TEST(mb_find_next_zero_bit_test);
7211
7212int mb_find_next_bit_test(void *addr, int max, int start)
7213{
7214 return mb_find_next_bit(addr, max, start);
7215}
7216EXPORT_SYMBOL_FOR_EXT4_TEST(mb_find_next_bit_test);
7217
7218void mb_clear_bit_test(int bit, void *addr)
7219{
7220 mb_clear_bit(bit, addr);
7221}
7222EXPORT_SYMBOL_FOR_EXT4_TEST(mb_clear_bit_test);
7223
7224int mb_test_bit_test(int bit, void *addr)
7225{
7226 return mb_test_bit(bit, addr);
7227}
7228EXPORT_SYMBOL_FOR_EXT4_TEST(mb_test_bit_test);
7229
7230int ext4_mb_mark_diskspace_used_test(struct ext4_allocation_context *ac,
7231 handle_t *handle)
7232{
7233 return ext4_mb_mark_diskspace_used(ac, handle);
7234}
7235EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_mark_diskspace_used_test);
7236
7237int mb_mark_used_test(struct ext4_buddy *e4b, struct ext4_free_extent *ex)
7238{
7239 return mb_mark_used(e4b, ex);
7240}
7241EXPORT_SYMBOL_FOR_EXT4_TEST(mb_mark_used_test);
7242
7243void ext4_mb_generate_buddy_test(struct super_block *sb, void *buddy,
7244 void *bitmap, ext4_group_t group,
7245 struct ext4_group_info *grp)
7246{
7247 ext4_mb_generate_buddy(sb, buddy, bitmap, group, grp);
7248}
7249EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_generate_buddy_test);
7250
7251int ext4_mb_load_buddy_test(struct super_block *sb, ext4_group_t group,
7252 struct ext4_buddy *e4b)
7253{
7254 return ext4_mb_load_buddy(sb, group, e4b);
7255}
7256EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_load_buddy_test);
7257
7258void ext4_mb_unload_buddy_test(struct ext4_buddy *e4b)
7259{
7260 ext4_mb_unload_buddy(e4b);
7261}
7262EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_unload_buddy_test);
7263
7264void mb_free_blocks_test(struct inode *inode, struct ext4_buddy *e4b,
7265 int first, int count)
7266{
7267 mb_free_blocks(inode, e4b, first, count);
7268}
7269EXPORT_SYMBOL_FOR_EXT4_TEST(mb_free_blocks_test);
7270
7271void ext4_free_blocks_simple_test(struct inode *inode, ext4_fsblk_t block,
7272 unsigned long count)
7273{
7274 return ext4_free_blocks_simple(inode, block, count);
7275}
7276EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_free_blocks_simple_test);
7277
7278EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_wait_block_bitmap);
7279EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_init);
7280EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_get_group_desc);
7281EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_count_free_clusters);
7282EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_get_group_info);
7283EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_free_group_clusters_set);
7284EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_release);
7285EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_read_block_bitmap_nowait);
7286EXPORT_SYMBOL_FOR_EXT4_TEST(mb_set_bits);
7287EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_fc_init_inode);
7288EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_mark_context);
7193#endif7289#endif
fs/ext4/mballoc.h+30−0
@@ -270,4 +270,34 @@ ext4_mballoc_query_range( · 269 unmodified lines
270 ext4_mballoc_query_range_fn formatter,270 ext4_mballoc_query_range_fn formatter,
271 void *priv);271 void *priv);
272 272
273extern int ext4_mb_mark_context(handle_t *handle,
274 struct super_block *sb, bool state,
275 ext4_group_t group, ext4_grpblk_t blkoff,
276 ext4_grpblk_t len, int flags,
277 ext4_grpblk_t *ret_changed);
278#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
279extern void mb_clear_bits_test(void *bm, int cur, int len);
280extern ext4_fsblk_t
281ext4_mb_new_blocks_simple_test(struct ext4_allocation_request *ar,
282 int *errp);
283extern int mb_find_next_zero_bit_test(void *addr, int max, int start);
284extern int mb_find_next_bit_test(void *addr, int max, int start);
285extern void mb_clear_bit_test(int bit, void *addr);
286extern int mb_test_bit_test(int bit, void *addr);
287extern int
288ext4_mb_mark_diskspace_used_test(struct ext4_allocation_context *ac,
289 handle_t *handle);
290extern int mb_mark_used_test(struct ext4_buddy *e4b,
291 struct ext4_free_extent *ex);
292extern void ext4_mb_generate_buddy_test(struct super_block *sb,
293 void *buddy, void *bitmap, ext4_group_t group,
294 struct ext4_group_info *grp);
295extern int ext4_mb_load_buddy_test(struct super_block *sb,
296 ext4_group_t group, struct ext4_buddy *e4b);
297extern void ext4_mb_unload_buddy_test(struct ext4_buddy *e4b);
298extern void mb_free_blocks_test(struct inode *inode,
299 struct ext4_buddy *e4b, int first, int count);
300extern void ext4_free_blocks_simple_test(struct inode *inode,
301 ext4_fsblk_t block, unsigned long count);
302#endif
273#endif303#endif
fs/ext4/page-io.c+8−2
@@ -524,9 +524,15 @@ int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio, · 523 unmodified lines
524 nr_to_submit++;524 nr_to_submit++;
525 } while ((bh = bh->b_this_page) != head);525 } while ((bh = bh->b_this_page) != head);
526 526
527 /* Nothing to submit? Just unlock the folio... */527 if (!nr_to_submit) {
528 if (!nr_to_submit)528 /*
529 * We have nothing to submit. Just cycle the folio through
530 * writeback state to properly update xarray tags.
531 */
532 __folio_start_writeback(folio, keep_towrite);
533 folio_end_writeback(folio);
529 return 0;534 return 0;
535 }
530 536
531 bh = head = folio_buffers(folio);537 bh = head = folio_buffers(folio);
532 538
fs/ext4/super.c+31−6
@@ -1254,12 +1254,10 @@ static void ext4_group_desc_free(struct ext4_sb_info *sbi) · 1253 unmodified lines
1254 struct buffer_head **group_desc;1254 struct buffer_head **group_desc;
1255 int i;1255 int i;
1256 1256
1257 rcu_read_lock();1257 group_desc = rcu_access_pointer(sbi->s_group_desc);
1258 group_desc = rcu_dereference(sbi->s_group_desc);
1259 for (i = 0; i < sbi->s_gdb_count; i++)1258 for (i = 0; i < sbi->s_gdb_count; i++)
1260 brelse(group_desc[i]);1259 brelse(group_desc[i]);
1261 kvfree(group_desc);1260 kvfree(group_desc);
1262 rcu_read_unlock();
1263}1261}
1264 1262
1265static void ext4_flex_groups_free(struct ext4_sb_info *sbi)1263static void ext4_flex_groups_free(struct ext4_sb_info *sbi)
@@ -1267,14 +1265,12 @@ static void ext4_flex_groups_free(struct ext4_sb_info *sbi) · 1 unmodified line
1267 struct flex_groups **flex_groups;1265 struct flex_groups **flex_groups;
1268 int i;1266 int i;
1269 1267
1270 rcu_read_lock();1268 flex_groups = rcu_access_pointer(sbi->s_flex_groups);
1271 flex_groups = rcu_dereference(sbi->s_flex_groups);
1272 if (flex_groups) {1269 if (flex_groups) {
1273 for (i = 0; i < sbi->s_flex_groups_allocated; i++)1270 for (i = 0; i < sbi->s_flex_groups_allocated; i++)
1274 kvfree(flex_groups[i]);1271 kvfree(flex_groups[i]);
1275 kvfree(flex_groups);1272 kvfree(flex_groups);
1276 }1273 }
1277 rcu_read_unlock();
1278}1274}
1279 1275
1280static void ext4_put_super(struct super_block *sb)1276static void ext4_put_super(struct super_block *sb)
@@ -1527,6 +1523,27 @@ void ext4_clear_inode(struct inode *inode) · 246 unmodified lines
1527 invalidate_inode_buffers(inode);1523 invalidate_inode_buffers(inode);
1528 clear_inode(inode);1524 clear_inode(inode);
1529 ext4_discard_preallocations(inode);1525 ext4_discard_preallocations(inode);
1526 /*
1527 * We must remove the inode from the hash before ext4_free_inode()
1528 * clears the bit in inode bitmap as otherwise another process reusing
1529 * the inode will block in insert_inode_hash() waiting for inode
1530 * eviction to complete while holding transaction handle open, but
1531 * ext4_evict_inode() still running for that inode could block waiting
1532 * for transaction commit if the inode is marked as IS_SYNC => deadlock.
1533 *
1534 * Removing the inode from the hash here is safe. There are two cases
1535 * to consider:
1536 * 1) The inode still has references to it (i_nlink > 0). In that case
1537 * we are keeping the inode and once we remove the inode from the hash,
1538 * iget() can create the new inode structure for the same inode number
1539 * and we are fine with that as all IO on behalf of the inode is
1540 * finished.
1541 * 2) We are deleting the inode (i_nlink == 0). In that case inode
1542 * number cannot be reused until ext4_free_inode() clears the bit in
1543 * the inode bitmap, at which point all IO is done and reuse is fine
1544 * again.
1545 */
1546 remove_inode_hash(inode);
1530 ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);1547 ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
1531 dquot_drop(inode);1548 dquot_drop(inode);
1532 if (EXT4_I(inode)->jinode) {1549 if (EXT4_I(inode)->jinode) {
@@ -3633,6 +3650,13 @@ int ext4_feature_set_ok(struct super_block *sb, int readonly) · 2100 unmodified lines
3633 "extents feature\n");3650 "extents feature\n");
3634 return 0;3651 return 0;
3635 }3652 }
3653 if (ext4_has_feature_bigalloc(sb) &&
3654 le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) {
3655 ext4_msg(sb, KERN_WARNING,
3656 "bad geometry: bigalloc file system with non-zero "
3657 "first_data_block\n");
3658 return 0;
3659 }
3636 3660
3637#if !IS_ENABLED(CONFIG_QUOTA) || !IS_ENABLED(CONFIG_QFMT_V2)3661#if !IS_ENABLED(CONFIG_QUOTA) || !IS_ENABLED(CONFIG_QFMT_V2)
3638 if (!readonly && (ext4_has_feature_quota(sb) ||3662 if (!readonly && (ext4_has_feature_quota(sb) ||
@@ -5403,6 +5427,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) · 1764 unmodified lines
5403 5427
5404 timer_setup(&sbi->s_err_report, print_daily_error_info, 0);5428 timer_setup(&sbi->s_err_report, print_daily_error_info, 0);
5405 spin_lock_init(&sbi->s_error_lock);5429 spin_lock_init(&sbi->s_error_lock);
5430 mutex_init(&sbi->s_error_notify_mutex);
5406 INIT_WORK(&sbi->s_sb_upd_work, update_super_work);5431 INIT_WORK(&sbi->s_sb_upd_work, update_super_work);
5407 5432
5408 err = ext4_group_desc_init(sb, es, logical_sb_block, &first_not_zeroed);5433 err = ext4_group_desc_init(sb, es, logical_sb_block, &first_not_zeroed);
fs/ext4/sysfs.c+9−1
@@ -597,7 +597,10 @@ static const struct kobj_type ext4_feat_ktype = { · 596 unmodified lines
597 597
598void ext4_notify_error_sysfs(struct ext4_sb_info *sbi)598void ext4_notify_error_sysfs(struct ext4_sb_info *sbi)
599{599{
600 sysfs_notify(&sbi->s_kobj, NULL, "errors_count");600 mutex_lock(&sbi->s_error_notify_mutex);
601 if (sbi->s_kobj.state_in_sysfs)
602 sysfs_notify(&sbi->s_kobj, NULL, "errors_count");
603 mutex_unlock(&sbi->s_error_notify_mutex);
601}604}
602 605
603static struct kobject *ext4_root;606static struct kobject *ext4_root;
@@ -610,8 +613,10 @@ int ext4_register_sysfs(struct super_block *sb) · 6 unmodified lines
610 int err;613 int err;
611 614
612 init_completion(&sbi->s_kobj_unregister);615 init_completion(&sbi->s_kobj_unregister);
616 mutex_lock(&sbi->s_error_notify_mutex);
613 err = kobject_init_and_add(&sbi->s_kobj, &ext4_sb_ktype, ext4_root,617 err = kobject_init_and_add(&sbi->s_kobj, &ext4_sb_ktype, ext4_root,
614 "%s", sb->s_id);618 "%s", sb->s_id);
619 mutex_unlock(&sbi->s_error_notify_mutex);
615 if (err) {620 if (err) {
616 kobject_put(&sbi->s_kobj);621 kobject_put(&sbi->s_kobj);
617 wait_for_completion(&sbi->s_kobj_unregister);622 wait_for_completion(&sbi->s_kobj_unregister);
@@ -644,7 +649,10 @@ void ext4_unregister_sysfs(struct super_block *sb) · 26 unmodified lines
644 649
645 if (sbi->s_proc)650 if (sbi->s_proc)
646 remove_proc_subtree(sb->s_id, ext4_proc_root);651 remove_proc_subtree(sb->s_id, ext4_proc_root);
652
653 mutex_lock(&sbi->s_error_notify_mutex);
647 kobject_del(&sbi->s_kobj);654 kobject_del(&sbi->s_kobj);
655 mutex_unlock(&sbi->s_error_notify_mutex);
648}656}
649 657
650int __init ext4_init_sysfs(void)658int __init ext4_init_sysfs(void)
fs/jbd2/checkpoint.c+13−2
@@ -267,7 +267,15 @@ restart: · 266 unmodified lines
267 */267 */
268 BUFFER_TRACE(bh, "queue");268 BUFFER_TRACE(bh, "queue");
269 get_bh(bh);269 get_bh(bh);
270 J_ASSERT_BH(bh, !buffer_jwrite(bh));270 if (WARN_ON_ONCE(buffer_jwrite(bh))) {
271 put_bh(bh); /* drop the ref we just took */
272 spin_unlock(&journal->j_list_lock);
273 /* Clean up any previously batched buffers */
274 if (batch_count)
275 __flush_batch(journal, &batch_count);
276 jbd2_journal_abort(journal, -EFSCORRUPTED);
277 return -EFSCORRUPTED;
278 }
271 journal->j_chkpt_bhs[batch_count++] = bh;279 journal->j_chkpt_bhs[batch_count++] = bh;
272 transaction->t_chp_stats.cs_written++;280 transaction->t_chp_stats.cs_written++;
273 transaction->t_checkpoint_list = jh->b_cpnext;281 transaction->t_checkpoint_list = jh->b_cpnext;
@@ -325,7 +333,10 @@ int jbd2_cleanup_journal_tail(journal_t *journal) · 51 unmodified lines
325 333
326 if (!jbd2_journal_get_log_tail(journal, &first_tid, &blocknr))334 if (!jbd2_journal_get_log_tail(journal, &first_tid, &blocknr))
327 return 1;335 return 1;
328 J_ASSERT(blocknr != 0);336 if (WARN_ON_ONCE(blocknr == 0)) {
337 jbd2_journal_abort(journal, -EFSCORRUPTED);
338 return -EFSCORRUPTED;
339 }
329 340
330 /*341 /*
331 * We need to make sure that any blocks that were recently written out342 * We need to make sure that any blocks that were recently written out

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t