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 ...
Unified · Split
| @@ -9619,7 +9619,12 @@ F: include/linux/ext2* · 9618 unmodified lines | |||
| 9619 | 9619 | ||
| 9620 | EXT4 FILE SYSTEM | 9620 | EXT4 FILE SYSTEM |
| 9621 | M: "Theodore Ts'o" <tytso@mit.edu> | 9621 | M: "Theodore Ts'o" <tytso@mit.edu> |
| 9622 | M: Andreas Dilger <adilger.kernel@dilger.ca> | 9622 | R: Andreas Dilger <adilger.kernel@dilger.ca> |
| 9623 | R: Baokun Li <libaokun@linux.alibaba.com> | ||
| 9624 | R: Jan Kara <jack@suse.cz> | ||
| 9625 | R: Ojaswin Mujoo <ojaswin@linux.ibm.com> | ||
| 9626 | R: Ritesh Harjani (IBM) <ritesh.list@gmail.com> | ||
| 9627 | R: Zhang Yi <yi.zhang@huawei.com> | ||
| 9623 | L: linux-ext4@vger.kernel.org | 9628 | L: linux-ext4@vger.kernel.org |
| 9624 | S: Maintained | 9629 | S: Maintained |
| 9625 | W: http://ext4.wiki.kernel.org | 9630 | W: http://ext4.wiki.kernel.org |
| @@ -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 | ||
| 15 | ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o | 15 | ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o |
| 16 | ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o | 16 | ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o |
| 17 | ext4-inode-test-objs += inode-test.o | 17 | ext4-test-objs += inode-test.o mballoc-test.o \ |
| 18 | obj-$(CONFIG_EXT4_KUNIT_TESTS) += ext4-inode-test.o | 18 | extents-test.o |
| 19 | obj-$(CONFIG_EXT4_KUNIT_TESTS) += ext4-test.o | ||
| 19 | ext4-$(CONFIG_FS_VERITY) += verity.o | 20 | ext4-$(CONFIG_FS_VERITY) += verity.o |
| 20 | ext4-$(CONFIG_FS_ENCRYPTION) += crypto.o | 21 | ext4-$(CONFIG_FS_ENCRYPTION) += crypto.o |
| @@ -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, |
| @@ -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 | |||
| 3944 | extern int ext4_block_write_begin(handle_t *handle, struct folio *folio, | 3945 | extern 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 */ |
| @@ -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 | ||
| 267 | extern int __ext4_ext_dirty(const char *where, unsigned int line, | ||
| 268 | handle_t *handle, struct inode *inode, | ||
| 269 | struct ext4_ext_path *path); | ||
| 270 | extern int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex); | ||
| 271 | #if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS) | ||
| 272 | extern int ext4_ext_space_root_idx_test(struct inode *inode, int check); | ||
| 273 | extern 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 | ||
| @@ -142,8 +142,10 @@ static struct file_system_type ext_fs_type = { · 141 unmodified lines | |||
| 142 | 142 | ||
| 143 | static void extents_kunit_exit(struct kunit *test) | 143 | static 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); |
| @@ -184,9 +184,9 @@ static int ext4_ext_get_access(handle_t *handle, struct inode *inode, · 183 unmodified lines | |||
| 184 | * - ENOMEM | 184 | * - ENOMEM |
| 185 | * - EIO | 185 | * - EIO |
| 186 | */ | 186 | */ |
| 187 | static int __ext4_ext_dirty(const char *where, unsigned int line, | 187 | int __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 */ |
| 3147 | static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex) | 3162 | int 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 | |||
| 3265 | fix_extent_len: | 3290 | fix_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_TESTS | 6270 | #if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS) |
| 6242 | #include "extents-test.c" | 6271 | int ext4_ext_space_root_idx_test(struct inode *inode, int check) |
| 6272 | { | ||
| 6273 | return ext4_ext_space_root_idx(inode, check); | ||
| 6274 | } | ||
| 6275 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_ext_space_root_idx_test); | ||
| 6276 | |||
| 6277 | struct 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 | } | ||
| 6285 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_split_convert_extents_test); | ||
| 6286 | |||
| 6287 | EXPORT_SYMBOL_FOR_EXT4_TEST(__ext4_ext_dirty); | ||
| 6288 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_ext_zeroout); | ||
| 6289 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_register_shrinker); | ||
| 6290 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_unregister_shrinker); | ||
| 6291 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_map_create_blocks); | ||
| 6292 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_init_tree); | ||
| 6293 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_lookup_extent); | ||
| 6294 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_insert_extent); | ||
| 6295 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_ext_insert_extent); | ||
| 6296 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_find_extent); | ||
| 6297 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_issue_zeroout); | ||
| 6298 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_map_query_blocks); | ||
| 6243 | #endif | 6299 | #endif |
| @@ -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); |
| 1647 | out_brelse: | ||
| 1645 | brelse(iloc.bh); | 1648 | brelse(iloc.bh); |
| 1646 | out: | 1649 | out: |
| 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 | /* |
| @@ -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 | ||
| @@ -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)) |
| @@ -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); |
| @@ -128,6 +128,8 @@ void ext4_inode_csum_set(struct inode *inode, struct ext4_inode *raw, · 127 unmodified lines | |||
| 128 | static inline int ext4_begin_ordered_truncate(struct inode *inode, | 128 | static 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 for | 135 | * 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 no | 137 | * 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, |
| @@ -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 | ||
| 12 | struct mbt_grp_ctx { | 13 | struct 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 | else | 339 | 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 | ||
| 815 | static void | 816 | static 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 100000 | 893 | #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 | ||
| 942 | static const struct mbt_ext4_block_layout mbt_test_layouts[] = { | 943 | static const struct mbt_ext4_block_layout mbt_test_layouts[] = { |
| @@ -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); |
| 3582 | err_freesgi: | 3588 | err_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_data | 3898 | */ |
| 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 0x0001 | 4085 | #define EXT4_MB_BITMAP_MARKED_CHECK 0x0001 |
| 4086 | #define EXT4_MB_SYNC_UPDATE 0x0002 | 4086 | #define EXT4_MB_SYNC_UPDATE 0x0002 |
| 4087 | static int | 4087 | int |
| 4088 | ext4_mb_mark_context(handle_t *handle, struct super_block *sb, bool state, | 4088 | ext4_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_TESTS | 7191 | #if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS) |
| 7192 | #include "mballoc-test.c" | 7192 | void mb_clear_bits_test(void *bm, int cur, int len) |
| 7193 | { | ||
| 7194 | mb_clear_bits(bm, cur, len); | ||
| 7195 | } | ||
| 7196 | EXPORT_SYMBOL_FOR_EXT4_TEST(mb_clear_bits_test); | ||
| 7197 | |||
| 7198 | ext4_fsblk_t | ||
| 7199 | ext4_mb_new_blocks_simple_test(struct ext4_allocation_request *ar, | ||
| 7200 | int *errp) | ||
| 7201 | { | ||
| 7202 | return ext4_mb_new_blocks_simple(ar, errp); | ||
| 7203 | } | ||
| 7204 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_new_blocks_simple_test); | ||
| 7205 | |||
| 7206 | int mb_find_next_zero_bit_test(void *addr, int max, int start) | ||
| 7207 | { | ||
| 7208 | return mb_find_next_zero_bit(addr, max, start); | ||
| 7209 | } | ||
| 7210 | EXPORT_SYMBOL_FOR_EXT4_TEST(mb_find_next_zero_bit_test); | ||
| 7211 | |||
| 7212 | int mb_find_next_bit_test(void *addr, int max, int start) | ||
| 7213 | { | ||
| 7214 | return mb_find_next_bit(addr, max, start); | ||
| 7215 | } | ||
| 7216 | EXPORT_SYMBOL_FOR_EXT4_TEST(mb_find_next_bit_test); | ||
| 7217 | |||
| 7218 | void mb_clear_bit_test(int bit, void *addr) | ||
| 7219 | { | ||
| 7220 | mb_clear_bit(bit, addr); | ||
| 7221 | } | ||
| 7222 | EXPORT_SYMBOL_FOR_EXT4_TEST(mb_clear_bit_test); | ||
| 7223 | |||
| 7224 | int mb_test_bit_test(int bit, void *addr) | ||
| 7225 | { | ||
| 7226 | return mb_test_bit(bit, addr); | ||
| 7227 | } | ||
| 7228 | EXPORT_SYMBOL_FOR_EXT4_TEST(mb_test_bit_test); | ||
| 7229 | |||
| 7230 | int 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 | } | ||
| 7235 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_mark_diskspace_used_test); | ||
| 7236 | |||
| 7237 | int mb_mark_used_test(struct ext4_buddy *e4b, struct ext4_free_extent *ex) | ||
| 7238 | { | ||
| 7239 | return mb_mark_used(e4b, ex); | ||
| 7240 | } | ||
| 7241 | EXPORT_SYMBOL_FOR_EXT4_TEST(mb_mark_used_test); | ||
| 7242 | |||
| 7243 | void 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 | } | ||
| 7249 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_generate_buddy_test); | ||
| 7250 | |||
| 7251 | int 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 | } | ||
| 7256 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_load_buddy_test); | ||
| 7257 | |||
| 7258 | void ext4_mb_unload_buddy_test(struct ext4_buddy *e4b) | ||
| 7259 | { | ||
| 7260 | ext4_mb_unload_buddy(e4b); | ||
| 7261 | } | ||
| 7262 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_unload_buddy_test); | ||
| 7263 | |||
| 7264 | void 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 | } | ||
| 7269 | EXPORT_SYMBOL_FOR_EXT4_TEST(mb_free_blocks_test); | ||
| 7270 | |||
| 7271 | void 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 | } | ||
| 7276 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_free_blocks_simple_test); | ||
| 7277 | |||
| 7278 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_wait_block_bitmap); | ||
| 7279 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_init); | ||
| 7280 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_get_group_desc); | ||
| 7281 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_count_free_clusters); | ||
| 7282 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_get_group_info); | ||
| 7283 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_free_group_clusters_set); | ||
| 7284 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_release); | ||
| 7285 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_read_block_bitmap_nowait); | ||
| 7286 | EXPORT_SYMBOL_FOR_EXT4_TEST(mb_set_bits); | ||
| 7287 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_fc_init_inode); | ||
| 7288 | EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_mark_context); | ||
| 7193 | #endif | 7289 | #endif |
| @@ -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 | ||
| 273 | extern 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) | ||
| 279 | extern void mb_clear_bits_test(void *bm, int cur, int len); | ||
| 280 | extern ext4_fsblk_t | ||
| 281 | ext4_mb_new_blocks_simple_test(struct ext4_allocation_request *ar, | ||
| 282 | int *errp); | ||
| 283 | extern int mb_find_next_zero_bit_test(void *addr, int max, int start); | ||
| 284 | extern int mb_find_next_bit_test(void *addr, int max, int start); | ||
| 285 | extern void mb_clear_bit_test(int bit, void *addr); | ||
| 286 | extern int mb_test_bit_test(int bit, void *addr); | ||
| 287 | extern int | ||
| 288 | ext4_mb_mark_diskspace_used_test(struct ext4_allocation_context *ac, | ||
| 289 | handle_t *handle); | ||
| 290 | extern int mb_mark_used_test(struct ext4_buddy *e4b, | ||
| 291 | struct ext4_free_extent *ex); | ||
| 292 | extern 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); | ||
| 295 | extern int ext4_mb_load_buddy_test(struct super_block *sb, | ||
| 296 | ext4_group_t group, struct ext4_buddy *e4b); | ||
| 297 | extern void ext4_mb_unload_buddy_test(struct ext4_buddy *e4b); | ||
| 298 | extern void mb_free_blocks_test(struct inode *inode, | ||
| 299 | struct ext4_buddy *e4b, int first, int count); | ||
| 300 | extern void ext4_free_blocks_simple_test(struct inode *inode, | ||
| 301 | ext4_fsblk_t block, unsigned long count); | ||
| 302 | #endif | ||
| 273 | #endif | 303 | #endif |
| @@ -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 | ||
| @@ -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 | ||
| 1265 | static void ext4_flex_groups_free(struct ext4_sb_info *sbi) | 1263 | static 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 | ||
| 1280 | static void ext4_put_super(struct super_block *sb) | 1276 | static 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); |
| @@ -597,7 +597,10 @@ static const struct kobj_type ext4_feat_ktype = { · 596 unmodified lines | |||
| 597 | 597 | ||
| 598 | void ext4_notify_error_sysfs(struct ext4_sb_info *sbi) | 598 | void 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 | ||
| 603 | static struct kobject *ext4_root; | 606 | static 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 | ||
| 650 | int __init ext4_init_sysfs(void) | 658 | int __init ext4_init_sysfs(void) |
| @@ -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 out | 342 | * We need to make sure that any blocks that were recently written out |