* Re: [PATCH 05/42] bdev: Drop pointless invalidate_inode_buffers() call
From: Christoph Hellwig @ 2026-03-27 6:20 UTC (permalink / raw)
To: Jan Kara
Cc: linux-fsdevel, linux-block, Christian Brauner, Al Viro,
linux-ext4, Ted Tso, Tigran A. Aivazian, David Sterba,
OGAWA Hirofumi, Muchun Song, Oscar Salvador, David Hildenbrand,
linux-mm, linux-aio, Benjamin LaHaise
In-Reply-To: <20260326095354.16340-47-jack@suse.cz>
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply
* Re: [PATCH] ext4: avoid allocate block from corrupted group in ext4_mb_find_by_goal()
From: Theodore Ts'o @ 2026-03-27 4:06 UTC (permalink / raw)
To: adilger.kernel, linux-ext4, Ye Bin; +Cc: Theodore Ts'o, jack
In-Reply-To: <20260302134619.3145520-1-yebin@huaweicloud.com>
On Mon, 02 Mar 2026 21:46:19 +0800, Ye Bin wrote:
> There's issue as follows:
> ...
> EXT4-fs (mmcblk0p1): Delayed block allocation failed for inode 206 at logical offset 0 with max blocks 1 with error 117
> EXT4-fs (mmcblk0p1): This should not happen!! Data will be lost
>
> EXT4-fs (mmcblk0p1): Delayed block allocation failed for inode 206 at logical offset 0 with max blocks 1 with error 117
> EXT4-fs (mmcblk0p1): This should not happen!! Data will be lost
>
> [...]
Applied, thanks!
[1/1] ext4: avoid allocate block from corrupted group in ext4_mb_find_by_goal()
commit: 4a1e038b056fca4a9644de1af8009c4980e158e3
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* Re: [PATCH -next v3] ext4: test if inode's all dirty pages are submitted to disk
From: Theodore Ts'o @ 2026-03-27 4:06 UTC (permalink / raw)
To: adilger.kernel, linux-ext4, Ye Bin; +Cc: Theodore Ts'o, jack
In-Reply-To: <20260303012242.3206465-1-yebin@huaweicloud.com>
On Tue, 03 Mar 2026 09:22:42 +0800, Ye Bin wrote:
> The commit aa373cf55099 ("writeback: stop background/kupdate works from
> livelocking other works") introduced an issue where unmounting a filesystem
> in a multi-logical-partition scenario could lead to batch file data loss.
> This problem was not fixed until the commit d92109891f21 ("fs/writeback:
> bail out if there is no more inodes for IO and queued once"). It took
> considerable time to identify the root cause. Additionally, in actual
> production environments, we frequently encountered file data loss after
> normal system reboots. Therefore, we are adding a check in the inode
> release flow to verify whether all dirty pages have been flushed to disk,
> in order to determine whether the data loss is caused by a logic issue in
> the filesystem code.
>
> [...]
Applied, thanks!
[1/1] ext4: test if inode's all dirty pages are submitted to disk
commit: 7d7ddac60e99f0506ad0dc6ce9138e0c8f9cee94
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* Re: [PATCH v5] ext4: avoid infinite loops caused by residual data
From: Theodore Ts'o @ 2026-03-27 4:06 UTC (permalink / raw)
To: jack, Edward Adam Davis
Cc: Theodore Ts'o, brauner, linux-ext4, linux-fsdevel,
linux-kernel, syzbot+1659aaaaa8d9d11265d7, syzkaller-bugs, viro
In-Reply-To: <tencent_43696283A68450B761D76866C6F360E36705@qq.com>
On Fri, 06 Mar 2026 09:31:58 +0800, Edward Adam Davis wrote:
> On the mkdir/mknod path, when mapping logical blocks to physical blocks,
> if inserting a new extent into the extent tree fails (in this example,
> because the file system disabled the huge file feature when marking the
> inode as dirty), ext4_ext_map_blocks() only calls ext4_free_blocks() to
> reclaim the physical block without deleting the corresponding data in
> the extent tree. This causes subsequent mkdir operations to reference
> the previously reclaimed physical block number again, even though this
> physical block is already being used by the xattr block. Therefore, a
> situation arises where both the directory and xattr are using the same
> buffer head block in memory simultaneously.
>
> [...]
Applied, thanks!
[1/1] ext4: avoid infinite loops caused by residual data
commit: 86709d389530941e5816505e3c12c757ceca374d
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* Re: [PATCH] ext4: validate p_idx bounds in ext4_ext_correct_indexes
From: Theodore Ts'o @ 2026-03-27 4:06 UTC (permalink / raw)
To: adilger.kernel, tejas bharambe
Cc: Theodore Ts'o, linux-ext4, linux-kernel
In-Reply-To: <JH0PR06MB66326016F9B6AD24097D232B897CA@JH0PR06MB6632.apcprd06.prod.outlook.com>
On Wed, 04 Mar 2026 07:32:08 +0000, tejas bharambe wrote:
> ext4_ext_correct_indexes() walks up the extent tree correcting
> index entries when the first extent in a leaf is modified. Before
> accessing path[k].p_idx->ei_block, there is no validation that
> p_idx falls within the valid range of index entries for that
> level.
>
> If the on-disk extent header contains a corrupted or crafted
> eh_entries value, p_idx can point past the end of the allocated
> buffer, causing a slab-out-of-bounds read.
>
> [...]
Applied, thanks!
[1/1] ext4: validate p_idx bounds in ext4_ext_correct_indexes
commit: a32da9c8bcceb70a5ced2f74c7551d300c541455
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* Re: [PATCH v2] ext4: Minor fix for ext4_split_extent_zeroout()
From: Theodore Ts'o @ 2026-03-27 4:06 UTC (permalink / raw)
To: linux-ext4, Ojaswin Mujoo
Cc: Theodore Ts'o, Dan Carpenter, Ritesh Harjani (IBM)
In-Reply-To: <20260302143811.605174-1-ojaswin@linux.ibm.com>
On Mon, 02 Mar 2026 20:08:11 +0530, Ojaswin Mujoo wrote:
> We missed storing the error which triggerd smatch warning:
>
> fs/ext4/extents.c:3369 ext4_split_extent_zeroout()
> warn: duplicate zero check 'err' (previous on line 3363)
>
> fs/ext4/extents.c
> 3361
> 3362 err = ext4_ext_get_access(handle, inode, path + depth);
> 3363 if (err)
> 3364 return err;
> 3365
> 3366 ext4_ext_mark_initialized(ex);
> 3367
> 3368 ext4_ext_dirty(handle, inode, path + depth);
> --> 3369 if (err)
> 3370 return err;
> 3371
> 3372 return 0;
> 3373 }
>
> [...]
Applied, thanks!
[1/1] ext4: Minor fix for ext4_split_extent_zeroout()
commit: 8c187915636da75f6223055d9933444cfa0cde83
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* [PATCH next] ext4: Fix diagnostic printf formats
From: david.laight.linux @ 2026-03-26 20:18 UTC (permalink / raw)
To: Theodore Ts'o, Andreas Dilger, linux-ext4, linux-kernel
Cc: David Laight, Masami Hiramatsu, Petr Mladek, Rasmus Villemoes,
Andy Shevchenko, Steven Rostedt, Sergey Senozhatsky,
Andrew Morton
From: David Laight <david.laight.linux@gmail.com>
The formats for non-terminated names should be "%.*s" not "%*.s".
The kernel currently treats "%*.s" as equivalent to "%*s" whereas
userspace requires it be equivalent to "%*.0s".
Neither is correct here.
Signed-off-by: David Laight <david.laight.linux@gmail.com>
---
fs/ext4/namei.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index c4b5e252af0e..7aaf5fbd4498 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -647,7 +647,7 @@ static struct stats dx_show_leaf(struct inode *dir,
/* Directory is not encrypted */
(void) ext4fs_dirhash(dir, de->name,
de->name_len, &h);
- printk("%*.s:(U)%x.%u ", len,
+ printk("%.*s:(U)%x.%u ", len,
name, h.hash,
(unsigned) ((char *) de
- base));
@@ -683,7 +683,7 @@ static struct stats dx_show_leaf(struct inode *dir,
(void) ext4fs_dirhash(dir,
de->name,
de->name_len, &h);
- printk("%*.s:(E)%x.%u ", len, name,
+ printk("%.*s:(E)%x.%u ", len, name,
h.hash, (unsigned) ((char *) de
- base));
fscrypt_fname_free_buffer(
@@ -694,7 +694,7 @@ static struct stats dx_show_leaf(struct inode *dir,
char *name = de->name;
(void) ext4fs_dirhash(dir, de->name,
de->name_len, &h);
- printk("%*.s:%x.%u ", len, name, h.hash,
+ printk("%.*s:%x.%u ", len, name, h.hash,
(unsigned) ((char *) de - base));
#endif
}
--
2.39.5
^ permalink raw reply related
* KASAN: slab-use-after-free Write in jbd2_journal_commit_transaction
From: Shuangpeng @ 2026-03-26 18:57 UTC (permalink / raw)
To: linux-ext4, linux-kernel; +Cc: jack, tytso
Hi Kernel Maintainers,
I hit the following KASAN report while testing current upstream kernel:
KASAN: slab-use-after-free in jbd2_journal_commit_transaction
on commit: bbeb83d3182abe0d245318e274e8531e5dd7a948 (Mar 24 2026)
The reproducer and .config files are here.
https://gist.github.com/shuangpengbai/032c84edf2505f7f74fb5757e1e6cd1d
The same reproducer sometimes also triggers a KASAN slab-out-of-bounds
report at the same site, which may indicate the same underlying bug.
I’m happy to test debug patches or provide additional information.
Reported-by: Shuangpeng Bai <shuangpeng.kernel@gmail.com>
[ 80.268862][ T8554] ==================================================================
[ 80.269678][ T8554] BUG: KASAN: slab-use-after-free in jbd2_journal_commit_transaction (./include/linux/instrumented.h:97 ./include/asm-generic/bitops/instrumented-atomic.h:42 ./include/linux/jbd2.h:320 fs/jbd2/commit.c:828)
[ 80.270623][ T8554] Write of size 8 at addr ffff8881687ee5e8 by task jbd2/loop0-4107/8554
[ 80.271460][ T8554]
[ 80.271710][ T8554] CPU: 1 UID: 0 PID: 8554 Comm: jbd2/loop0-4107 Not tainted 7.0.0-rc5-00051-gbbeb83d3182a #35 PR
[ 80.271719][ T8554] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
[ 80.271726][ T8554] Call Trace:
[ 80.271729][ T8554] <TASK>
[ 80.271732][ T8554] dump_stack_lvl (lib/dump_stack.c:122)
[ 80.271743][ T8554] print_report (mm/kasan/report.c:379 mm/kasan/report.c:482)
[ 80.271795][ T8554] kasan_report (mm/kasan/report.c:597)
[ 80.271813][ T8554] kasan_check_range (mm/kasan/generic.c:? mm/kasan/generic.c:200)
[ 80.271821][ T8554] jbd2_journal_commit_transaction (./include/linux/instrumented.h:97 ./include/asm-generic/bitops/instrumented-atomic.h:42 ./include/linux/jbd2.h:320 fs/jbd2/commit.c:828)
[ 80.271912][ T8554] kjournald2 (fs/jbd2/journal.c:202)
[ 80.271974][ T8554] kthread (kernel/kthread.c:437)
[ 80.271986][ T8554] ret_from_fork (arch/x86/kernel/process.c:164)
[ 80.272022][ T8554] ret_from_fork_asm (arch/x86/entry/entry_64.S:255)
[ 80.272034][ T8554] </TASK>
[ 80.272036][ T8554]
[ 80.292650][ T8554] Freed by task 8373 on cpu 1 at 42.645081s:
[ 80.293268][ T8554] kasan_save_track (mm/kasan/common.c:58 mm/kasan/common.c:78)
[ 80.293766][ T8554] kasan_save_free_info (mm/kasan/generic.c:587)
[ 80.294292][ T8554] __kasan_slab_free (mm/kasan/common.c:287)
[ 80.294796][ T8554] kfree (mm/slub.c:6165 mm/slub.c:6483)
[ 80.295206][ T8554] tomoyo_realpath_from_path (security/tomoyo/realpath.c:287)
[ 80.295789][ T8554] tomoyo_realpath_nofollow (security/tomoyo/realpath.c:304)
[ 80.296344][ T8554] tomoyo_find_next_domain (security/tomoyo/domain.c:731)
[ 80.296910][ T8554] tomoyo_bprm_check_security (security/tomoyo/tomoyo.c:102)
[ 80.297486][ T8554] security_bprm_check (security/security.c:795)
[ 80.298020][ T8554] bprm_execve (fs/exec.c:1655 fs/exec.c:1696 fs/exec.c:1748)
[ 80.298486][ T8554] do_execveat_common (fs/exec.c:1846)
[ 80.299019][ T8554] __x64_sys_execve (fs/exec.c:1930 fs/exec.c:1924 fs/exec.c:1924)
[ 80.299510][ T8554] do_syscall_64 (arch/x86/entry/syscall_64.c:?)
[ 80.299984][ T8554] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
[ 80.300597][ T8554]
[ 80.300847][ T8554] The buggy address belongs to the object at ffff8881687ee000
[ 80.300847][ T8554] which belongs to the cache kmalloc-4k of size 4096
[ 80.302261][ T8554] The buggy address is located 1512 bytes inside of
[ 80.302261][ T8554] freed 4096-byte region [ffff8881687ee000, ffff8881687ef000)
[ 80.303678][ T8554]
[ 80.303930][ T8554] The buggy address belongs to the physical page:
[ 80.304590][ T8554] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x1687e8
[ 80.305499][ T8554] head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
[ 80.306363][ T8554] flags: 0x17ff00000000040(head|node=0|zone=2|lastcpupid=0x7ff)
[ 80.307153][ T8554] page_type: f5(slab)
[ 80.307663][ T8554] raw: 017ff00000000040 ffff888100042140 dead000000000100 dead000000000122
[ 80.308538][ T8554] raw: 0000000000000000 0000000800040004 00000000f5000000 0000000000000000
[ 80.309414][ T8554] head: 017ff00000000040 ffff888100042140 dead000000000100 dead000000000122
[ 80.310296][ T8554] head: 0000000000000000 0000000800040004 00000000f5000000 0000000000000000
[ 80.311186][ T8554] head: 017ff00000000003 ffffea0005a1fa01 00000000ffffffff 00000000ffffffff
[ 80.312076][ T8554] head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008
[ 80.312957][ T8554] page dumped because: kasan: bad access detected
[ 80.313612][ T8554] page_owner tracks the page as allocated
[ 80.314196][ T8554] page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd2040(__GFP_IO|__GFP_NOWARN6
[ 80.316275][ T8554] post_alloc_hook (./include/linux/page_owner.h:? mm/page_alloc.c:1889)
[ 80.316774][ T8554] get_page_from_freelist (mm/page_alloc.c:? mm/page_alloc.c:3962)
[ 80.317348][ T8554] __alloc_frozen_pages_noprof (mm/page_alloc.c:5250)
[ 80.317952][ T8554] allocate_slab (mm/slub.c:3294 mm/slub.c:3481)
[ 80.318430][ T8554] refill_objects (mm/slub.c:7176)
[ 80.318935][ T8554] __pcs_replace_empty_main (mm/slub.c:? mm/slub.c:4615)
[ 80.319510][ T8554] __kmalloc_noprof (mm/slub.c:4718 mm/slub.c:4851 mm/slub.c:5259 mm/slub.c:5272)
[ 80.320017][ T8554] tomoyo_realpath_from_path (security/tomoyo/realpath.c:252)
[ 80.320591][ T8554] tomoyo_path_perm (security/tomoyo/file.c:151 security/tomoyo/file.c:827)
[ 80.321100][ T8554] security_inode_getattr (security/security.c:1870)
[ 80.321648][ T8554] __se_sys_newfstat (fs/stat.c:260 fs/stat.c:281 fs/stat.c:551 fs/stat.c:546)
[ 80.322157][ T8554] do_syscall_64 (arch/x86/entry/syscall_64.c:?)
[ 80.322632][ T8554] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
[ 80.323246][ T8554] page last free pid 1 tgid 1 stack trace:
[ 80.323852][ T8554] __free_frozen_pages (./include/linux/page_owner.h:? mm/page_alloc.c:1433 mm/page_alloc.c:2978)
[ 80.324384][ T8554] free_contig_range (mm/page_alloc.c:7373)
[ 80.324886][ T8554] destroy_args (mm/debug_vm_pgtable.c:995)
[ 80.325363][ T8554] debug_vm_pgtable (mm/debug_vm_pgtable.c:?)
[ 80.325870][ T8554] do_one_initcall (init/main.c:?)
[ 80.326370][ T8554] do_initcall_level (init/main.c:1443)
[ 80.326890][ T8554] do_initcalls (init/main.c:1457)
[ 80.327346][ T8554] kernel_init_freeable (init/main.c:1696)
[ 80.327888][ T8554] kernel_init (init/main.c:1584)
[ 80.328342][ T8554] ret_from_fork (arch/x86/kernel/process.c:164)
[ 80.328827][ T8554] ret_from_fork_asm (arch/x86/entry/entry_64.S:255)
[ 80.329327][ T8554]
[ 80.329577][ T8554] Memory state around the buggy address:
[ 80.330154][ T8554] ffff8881687ee480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 80.330981][ T8554] ffff8881687ee500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 80.331803][ T8554] >ffff8881687ee580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 80.332625][ T8554] ^
[ 80.333389][ T8554] ffff8881687ee600: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 80.334209][ T8554] ffff8881687ee680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 80.335033][ T8554] ==================================================================
Best,
Shuangpeng
^ permalink raw reply
* Re: [PATCH] ext4: Fix deadlock on inode reallocation
From: Jan Kara @ 2026-03-26 15:59 UTC (permalink / raw)
To: Ted Tso; +Cc: Jan Kara, linux-ext4, yi1.lai, stable, Mateusz Guzik
In-Reply-To: <CAGudoHF8zgjcKiHx75EwPmz5eTp_7yk+dh+ju4Ju2xZJqFJYvw@mail.gmail.com>
On Wed 25-03-26 22:07:20, Mateusz Guzik wrote:
> can this get any traction?
I've talked to Ted today and is currently picking up fixes into his tree so
we should get some action soon. Ted, here is one patch which needs either
fast-tracking to 7.0 or we need to revert a VFS change to avoid deadlocks
on ext4.
Honza
> master as-is contains a change which uncovered the ext4 problem.
> either the deadlock needs to be fixed in time for the release or the
> other change needs to get temporarily reverted.
>
> interested parties can find proposed revert here:
> https://lore.kernel.org/linux-fsdevel/20260316103306.1258289-1-mjguzik@gmail.com/
>
> On Fri, Mar 20, 2026 at 10:04 AM Jan Kara <jack@suse.cz> wrote:
> >
> > Currently there is a race in ext4 when reallocating freed inode
> > resulting in a deadlock:
> >
> > Task1 Task2
> > ext4_evict_inode()
> > handle = ext4_journal_start();
> > ...
> > if (IS_SYNC(inode))
> > handle->h_sync = 1;
> > ext4_free_inode()
> > ext4_new_inode()
> > handle = ext4_journal_start()
> > finds the bit in inode bitmap
> > already clear
> > insert_inode_locked()
> > waits for inode to be
> > removed from the hash.
> > ext4_journal_stop(handle)
> > jbd2_journal_stop(handle)
> > jbd2_log_wait_commit(journal, tid);
> > - deadlocks waiting for transaction handle Task2 holds
> >
> > Fix the problem by removing inode from the hash already in
> > ext4_clear_inode() by which time all IO for the inode is done so reuse
> > is already fine but we are still before possibly blocking on transaction
> > commit.
> >
> > Reported-by: "Lai, Yi" <yi1.lai@linux.intel.com>
> > Link: https://lore.kernel.org/all/abNvb2PcrKj1FBeC@ly-workstation
> > Fixes: 88ec797c4680 ("fs: make insert_inode_locked() wait for inode destruction")
> > CC: stable@vger.kernel.org
> > Signed-off-by: Jan Kara <jack@suse.cz>
> > ---
> > fs/ext4/super.c | 21 +++++++++++++++++++++
> > 1 file changed, 21 insertions(+)
> >
> > Ted, this is a regression recently introduced by VFS changes in
> > insert_inode_locked() but I think it's best fixed in ext4. If you agree, it
> > would be nice to merge this so that it makes it to 7.0 release. Thanks!
> >
> > diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> > index 43f680c750ae..b8122d24c083 100644
> > --- a/fs/ext4/super.c
> > +++ b/fs/ext4/super.c
> > @@ -1527,6 +1527,27 @@ void ext4_clear_inode(struct inode *inode)
> > invalidate_inode_buffers(inode);
> > clear_inode(inode);
> > ext4_discard_preallocations(inode);
> > + /*
> > + * We must remove the inode from the hash before ext4_free_inode()
> > + * clears the bit in inode bitmap as otherwise another process reusing
> > + * the inode will block in insert_inode_hash() waiting for inode
> > + * eviction to complete while holding transaction handle open, but
> > + * ext4_evict_inode() still running for that inode could block waiting
> > + * for transaction commit if the inode is marked as IS_SYNC => deadlock.
> > + *
> > + * Removing the inode from the hash here is safe. There are two cases
> > + * to consider:
> > + * 1) The inode still has references to it (i_nlink > 0). In that case
> > + * we are keeping the inode and once we remove the inode from the hash,
> > + * iget() can create the new inode structure for the same inode number
> > + * and we are fine with that as all IO on behalf of the inode is
> > + * finished.
> > + * 2) We are deleting the inode (i_nlink == 0). In that case inode
> > + * number cannot be reused until ext4_free_inode() clears the bit in
> > + * the inode bitmap, at which point all IO is done and reuse is fine
> > + * again.
> > + */
> > + remove_inode_hash(inode);
> > ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
> > dquot_drop(inode);
> > if (EXT4_I(inode)->jinode) {
> > --
> > 2.51.0
> >
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply
* Re: [PATCH v3 0/42] fs: Move metadata bh tracking from address_space
From: Christian Brauner @ 2026-03-26 14:06 UTC (permalink / raw)
To: linux-fsdevel, Jan Kara
Cc: Christian Brauner, linux-block, Al Viro, linux-ext4, Ted Tso,
Tigran A. Aivazian, David Sterba, OGAWA Hirofumi, Muchun Song,
Oscar Salvador, David Hildenbrand, linux-mm, linux-aio,
Benjamin LaHaise
In-Reply-To: <20260326082428.31660-1-jack@suse.cz>
On Thu, 26 Mar 2026 10:53:54 +0100, Jan Kara wrote:
> here is a next revision of the patchset cleaning up buffer head metadata
> tracking and use of address_space's private_list and private_lock. Functionally
> this should be identical to v2, most of the changes were in improving
> changelogs, patch ordering, function names, etc. The patches have survived some
> testing with fstests and ltp however I didn't test AFFS and KVM guest_memfd
> changes so a help with testing those would be very welcome. Thanks.
>
> [...]
Fwiw, a fixup series on top would have sufficed this late in the cycle. :)
---
Applied to the vfs-7.1.bh.metadata branch of the vfs/vfs.git tree.
Patches in the vfs-7.1.bh.metadata branch should appear in linux-next soon.
Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.
It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.
Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.
tree: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: vfs-7.1.bh.metadata
[01/42] ext4: Use inode_has_buffers()
https://git.kernel.org/vfs/vfs/c/ab856368582b
[02/42] gfs2: Don't zero i_private_data
https://git.kernel.org/vfs/vfs/c/7e5ccdd88c5a
[03/42] ntfs3: Drop pointless sync_mapping_buffers() and invalidate_inode_buffers() calls
https://git.kernel.org/vfs/vfs/c/ddd6761f8777
[04/42] ocfs2: Drop pointless sync_mapping_buffers() calls
https://git.kernel.org/vfs/vfs/c/70450fcfd28a
[05/42] bdev: Drop pointless invalidate_inode_buffers() call
https://git.kernel.org/vfs/vfs/c/f9480ecf939d
[06/42] ufs: Drop pointless invalidate_mapping_buffers() call
https://git.kernel.org/vfs/vfs/c/09a23f3a0401
[07/42] exfat: Drop pointless invalidate_inode_buffers() call
https://git.kernel.org/vfs/vfs/c/2cbfeb4c8a43
[08/42] fs: Remove inode lock from __generic_file_fsync()
https://git.kernel.org/vfs/vfs/c/ba31a330b4c1
[09/42] udf: Switch to generic_buffers_fsync()
https://git.kernel.org/vfs/vfs/c/f3216337d96e
[10/42] minix: Switch to generic_buffers_fsync()
https://git.kernel.org/vfs/vfs/c/f3873f90b4c8
[11/42] bfs: Switch to generic_buffers_fsync()
https://git.kernel.org/vfs/vfs/c/235cddee8590
[12/42] fat: Switch to generic_buffers_fsync_noflush()
https://git.kernel.org/vfs/vfs/c/635aa2f67817
[13/42] fs: Drop sync_mapping_buffers() from __generic_file_fsync()
https://git.kernel.org/vfs/vfs/c/aec4fe7cce0c
[14/42] fs: Rename generic_file_fsync() to simple_fsync()
https://git.kernel.org/vfs/vfs/c/5f36c9ca3333
[15/42] fat: Sync and invalidate metadata buffers from fat_evict_inode()
https://git.kernel.org/vfs/vfs/c/63f1f4b6c9c8
[16/42] udf: Sync and invalidate metadata buffers from udf_evict_inode()
https://git.kernel.org/vfs/vfs/c/153e5960450a
[17/42] minix: Sync and invalidate metadata buffers from minix_evict_inode()
https://git.kernel.org/vfs/vfs/c/61aa62ddfb5d
[18/42] ext2: Sync and invalidate metadata buffers from ext2_evict_inode()
https://git.kernel.org/vfs/vfs/c/4211dc89c31c
[19/42] ext4: Sync and invalidate metadata buffers from ext4_evict_inode()
https://git.kernel.org/vfs/vfs/c/77ff1ff2f3c5
[20/42] bfs: Sync and invalidate metadata buffers from bfs_evict_inode()
https://git.kernel.org/vfs/vfs/c/4a7fd1823efc
[21/42] affs: Sync and invalidate metadata buffers from affs_evict_inode()
https://git.kernel.org/vfs/vfs/c/23dae9e189de
[22/42] fs: Ignore inode metadata buffers in inode_lru_isolate()
https://git.kernel.org/vfs/vfs/c/972b9dd4e418
[23/42] fs: Stop using i_private_data for metadata bh tracking
https://git.kernel.org/vfs/vfs/c/0f46a9e2743c
[24/42] hugetlbfs: Stop using i_private_data
https://git.kernel.org/vfs/vfs/c/2811f2a82faf
[25/42] aio: Stop using i_private_data and i_private_lock
https://git.kernel.org/vfs/vfs/c/3833d335d7be
[26/42] fs: Remove i_private_data
https://git.kernel.org/vfs/vfs/c/cd336f2e275d
[27/42] kvm: Use private inode list instead of i_private_list
https://git.kernel.org/vfs/vfs/c/d15c987d1226
[28/42] fs: Drop osync_buffers_list()
https://git.kernel.org/vfs/vfs/c/cae6b7a03c7e
[29/42] fs: Fold fsync_buffers_list() into sync_mapping_buffers()
https://git.kernel.org/vfs/vfs/c/8fed8176312b
[30/42] fs: Move metadata bhs tracking to a separate struct
https://git.kernel.org/vfs/vfs/c/521bea7cec8a
[31/42] fs: Make bhs point to mapping_metadata_bhs
https://git.kernel.org/vfs/vfs/c/c86f5d25514c
[32/42] fs: Switch inode_has_buffers() to take mapping_metadata_bhs
https://git.kernel.org/vfs/vfs/c/025c9af1a20c
[33/42] fs: Provide functions for handling mapping_metadata_bhs directly
https://git.kernel.org/vfs/vfs/c/a8c8122a3dac
[34/42] ext2: Track metadata bhs in fs-private inode part
https://git.kernel.org/vfs/vfs/c/b0439bbc29f0
[35/42] affs: Track metadata bhs in fs-private inode part
https://git.kernel.org/vfs/vfs/c/6874973e720f
[36/42] bfs: Track metadata bhs in fs-private inode part
https://git.kernel.org/vfs/vfs/c/b0806ac078e2
[37/42] fat: Track metadata bhs in fs-private inode part
https://git.kernel.org/vfs/vfs/c/439959848b40
[38/42] udf: Track metadata bhs in fs-private inode part
https://git.kernel.org/vfs/vfs/c/d0874a580a4b
[39/42] minix: Track metadata bhs in fs-private inode part
https://git.kernel.org/vfs/vfs/c/caaa184b4243
[40/42] ext4: Track metadata bhs in fs-private inode part
https://git.kernel.org/vfs/vfs/c/41189b49bcf1
[41/42] fs: Drop mapping_metadata_bhs from address space
https://git.kernel.org/vfs/vfs/c/cb6d109b9ccc
[42/42] fs: Drop i_private_list from address_space
https://git.kernel.org/vfs/vfs/c/f219798ce294
^ permalink raw reply
* Re: [RFC 1/1] ext4: fail fast on repeated metadata reads after IO failure
From: Diangang Li @ 2026-03-26 12:09 UTC (permalink / raw)
To: Matthew Wilcox, Andreas Dilger
Cc: Diangang Li, tytso, linux-ext4, linux-fsdevel, linux-kernel,
changfengnan
In-Reply-To: <acP5-v85CwUQZlMB@casper.infradead.org>
On 3/25/26 11:06 PM, Matthew Wilcox wrote:
> On Wed, Mar 25, 2026 at 04:15:42AM -0600, Andreas Dilger wrote:
>> On Mar 25, 2026, at 03:33, Diangang Li <diangangli@gmail.com> wrote:
>>>
>>> From: Diangang Li <lidiangang@bytedance.com>
>>>
>>> ext4 metadata reads serialize on BH_Lock (lock_buffer). If the read fails,
>>> the buffer remains !Uptodate. With concurrent callers, each waiter can
>>> retry the same failing read after the previous holder drops BH_Lock. This
>>> amplifies device retry latency and may trigger hung tasks.
>>>
>>> In the normal read path the block driver already performs its own retries.
>>> Once the retries keep failing, re-submitting the same metadata read from
>>> the filesystem just amplifies the latency by serializing waiters on
>>> BH_Lock.
>>>
>>> Remember read failures on buffer_head and fail fast for ext4 metadata reads
>>> once a buffer has already failed to read. Clear the flag on successful
>>> read/write completion so the buffer can recover. ext4 read-ahead uses
>>> ext4_read_bh_nowait(), so it does not set the failure flag and remains
>>> best-effort.
>>
>> Not that the patch is bad, but if the BH_Read_EIO flag is set on a buffer
>> and it prevents other tasks from reading that block again, how would the
>> buffer ever become Uptodate to clear the flag? There isn't enough state
>> in a 1-bit flag to have any kind of expiry and later retry.
>
> I've been thinking about this problem too, albeit from a folio read
> perspective, not from a buffer_head read perspective. You're quite
> right that one bit isn't enough. The solution I was considering but
> haven't implemented yet was to tell all the current waiters that
> the IO has failed, but not set any kind of permanent error flag.
>
> I was thinking about starting with this:
>
> +++ b/include/linux/wait_bit.h
> @@ -10,6 +10,7 @@
> struct wait_bit_key {
> unsigned long *flags;
> int bit_nr;
> + int error;
> unsigned long timeout;
> };
>
>
> and then adding/changing various APIs to allow an error to be passed in
> and noticed by the woken task.
>
> With this change, the thundering herd all wake up, see the error and
> return immediately instead of each submitting their own I/O. New reads
> will retry the read, but each will only be held up for a maximum of
> their own timeout.
Hi Matthew and all,
Thanks. The idea of waking the current waiters with an error makes a lot
of sense.
I’ve been considering a smaller change on the buffer_head side that
might get most of the benefit without touching the generic wait_bit
APIs. The idea is to tell whether taking BH_Lock required waiting. If we
had to wait, and the buffer is already marked with
buffer_read_io_error(), then just return -EIO and don’t submit another
read. If we got the lock without waiting, still submit the read. That
should stop the thundering herd from reissuing the same failing IO.
Another option is a simple retry window. After a read failure, don’t
retry for some period of time, and size that window by error type. For
persistent media errors (e.g. MEDIUM ERROR, repeated IO ERROR) the
window could be effectively infinite, while for transient cases (e.g.
few IO ERROR, BLK_STS_RESOURCE) it could be small.
Any opinions on these two approaches, or other ideas for this problem?
Thanks,
Diangang
^ permalink raw reply
* Re: [PATCH v2] ext4: do not check fast symlink during orphan recovery
From: Theodore Ts'o @ 2026-03-26 11:57 UTC (permalink / raw)
To: linux-ext4, Zhang Yi
Cc: Theodore Ts'o, linux-fsdevel, linux-kernel, adilger.kernel,
jack, ojaswin, ritesh.list, yi.zhang, yizhang089, libaokun1,
yangerkun, yukuai
In-Reply-To: <20260131091156.1733648-1-yi.zhang@huaweicloud.com>
On Sat, 31 Jan 2026 17:11:56 +0800, Zhang Yi wrote:
> Commit '5f920d5d6083 ("ext4: verify fast symlink length")' causes the
> generic/475 test to fail during orphan cleanup of zero-length symlinks.
>
> generic/475 84s ... _check_generic_filesystem: filesystem on /dev/vde is inconsistent
>
> The fsck reports are provided below:
>
> [...]
Applied, thanks!
[1/1] ext4: do not check fast symlink during orphan recovery
commit: 55baec0cc241121974e6655895ed0a5432c09059
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* Re: [PATCH v2] ext4: fix journal credit check when setting fscrypt context
From: Theodore Ts'o @ 2026-03-26 11:57 UTC (permalink / raw)
To: linux-kernel, linux-ext4, adilger.kernel, Simon Weber
Cc: Theodore Ts'o, tahsin, ebiggers, Anthony Durrer
In-Reply-To: <20260207100148.724275-4-simon.weber.39@gmail.com>
On Sat, 07 Feb 2026 10:53:03 +0100, Simon Weber wrote:
> Fix an issue arising when ext4 features has_journal, ea_inode, and encrypt
> are activated simultaneously, leading to ENOSPC when creating an encrypted
> file.
>
> Fix by passing XATTR_CREATE flag to xattr_set_handle function if a handle
> is specified, i.e., when the function is called in the control flow of
> creating a new inode. This aligns the number of jbd2 credits set_handle
> checks for with the number allocated for creating a new inode.
>
> [...]
Applied, thanks!
[1/1] ext4: fix journal credit check when setting fscrypt context
commit: cb8c10c17a8b339423cd950a04841c5b3287f346
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* Re: [PATCH v3] ext4: publish jinode after initialization
From: Theodore Ts'o @ 2026-03-26 11:57 UTC (permalink / raw)
To: Andreas Dilger, Jan Kara, linux-ext4, linux-kernel, Li Chen
Cc: Theodore Ts'o, stable
In-Reply-To: <20260225082617.147957-1-me@linux.beauty>
On Wed, 25 Feb 2026 16:26:16 +0800, Li Chen wrote:
> ext4_inode_attach_jinode() publishes ei->jinode to concurrent users.
> It used to set ei->jinode before jbd2_journal_init_jbd_inode(),
> allowing a reader to observe a non-NULL jinode with i_vfs_inode
> still unset.
>
> The fast commit flush path can then pass this jinode to
> jbd2_wait_inode_data(), which dereferences i_vfs_inode->i_mapping and
> may crash.
>
> [...]
Applied, thanks!
[1/1] ext4: publish jinode after initialization
commit: d4dfb4e294f762f0567c50ac6cd71ba02c976575
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* Re: [PATCH] ext4: replace BUG_ON with proper error handling in ext4_read_inline_folio
From: Theodore Ts'o @ 2026-03-26 11:57 UTC (permalink / raw)
To: Andreas Dilger, Yuto Ohnuki; +Cc: Theodore Ts'o, linux-ext4, linux-kernel
In-Reply-To: <20260223123345.14838-2-ytohnuki@amazon.com>
On Mon, 23 Feb 2026 12:33:46 +0000, Yuto Ohnuki wrote:
> Replace BUG_ON() with proper error handling when inline data size
> exceeds PAGE_SIZE. This prevents kernel panic and allows the system to
> continue running while properly reporting the filesystem corruption.
>
> The error is logged via ext4_error_inode(), the buffer head is released
> to prevent memory leak, and -EFSCORRUPTED is returned to indicate
> filesystem corruption.
>
> [...]
Applied, thanks!
[1/1] ext4: replace BUG_ON with proper error handling in ext4_read_inline_folio
commit: e8814f7f4646aa0bba3f9e9a446b07753e87117d
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* Re: [PATCH] ext4: Fix stale xarray tags after writeback
From: Theodore Ts'o @ 2026-03-26 11:57 UTC (permalink / raw)
To: Jan Kara; +Cc: Theodore Ts'o, linux-ext4, Gerald Yang
In-Reply-To: <20260205092223.21287-2-jack@suse.cz>
On Thu, 05 Feb 2026 10:22:24 +0100, Jan Kara wrote:
> There are cases where ext4_bio_write_page() gets called for a page which
> has no buffers to submit. This happens e.g. when the part of the file is
> actually a hole, when we cannot allocate blocks due to being called from
> jbd2, or in data=journal mode when checkpointing writes the buffers
> earlier. In these cases we just return from ext4_bio_write_page()
> however if the page didn't need redirtying, we will leave stale DIRTY
> and/or TOWRITE tags in xarray because those get cleared only in
> __folio_start_writeback(). As a result we can leave these tags set in
> mappings even after a final sync on filesystem that's getting remounted
> read-only or that's being frozen. Various assertions can then get upset
> when writeback is started on such filesystems (Gerald reported assertion
> in ext4_journal_check_start() firing).
>
> [...]
Applied, thanks!
[1/1] ext4: Fix stale xarray tags after writeback
commit: bc6874ab41809f210c3e966576374d0778e144ff
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* Re: [PATCH 0/2] ext4: nojournal mode fixes
From: Theodore Ts'o @ 2026-03-26 11:57 UTC (permalink / raw)
To: Jan Kara; +Cc: Theodore Ts'o, linux-ext4, Free Ekanayaka
In-Reply-To: <20260211140209.30337-1-jack@suse.cz>
On Mon, 16 Feb 2026 17:48:42 +0100, Jan Kara wrote:
> here are two ext4 fixes for nojournal mode. The first fix is fixing handling of
> uninitialized inodes in recently_deleted() used in nojournal mode which was
> leading to occasional fstests failures for me (which became much more likely
> after the second patch due to timing changes). The second patch fixes a bug in
> ext4_fsync() which was not properly writing out inode metadata in nojournal
> mode. It is kind of a band aid but proper solution is going to be rather
> intrusive and practically unbackportable so I think having it is worth it.
>
> [...]
Applied, thanks!
[1/2] ext4: Make recently_deleted() properly work with lazy itable initialization
commit: cec4673c65d709a0c0354c0a0bbbba5cb7508a9c
[2/2] ext4: Fix fsync(2) for nojournal mode
commit: 3a0fb9e501707760341b5f4562e0f8409bed126a
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* Re: [PATCH] ext4: kunit: extents-test: Fix percpu_counters list corruption
From: Theodore Ts'o @ 2026-03-26 11:57 UTC (permalink / raw)
To: linux-ext4, Ritesh Harjani (IBM); +Cc: Theodore Ts'o, Ojaswin Mujoo
In-Reply-To: <5bb9041471dab8ce870c191c19cbe4df57473be8.1772381213.git.ritesh.list@gmail.com>
On Sun, 01 Mar 2026 21:44:26 +0530, Ritesh Harjani (IBM) wrote:
> commit 82f80e2e3b23 ("ext4: add extent status cache support to kunit tests"),
> added ext4_es_register_shrinker() in extents_kunit_init() function but
> failed to add the unregister shrinker routine in extents_kunit_exit().
>
> This could cause the following percpu_counters list corruption bug.
>
> ok 1 split unwrit extent to 2 extents and convert 1st half writ
> slab kmalloc-4k start c0000002007ff000 pointer offset 1448 size 4096
> list_add corruption. next->prev should be prev (c000000004bc9e60), but was 0000000000000000. (next=c0000002007ff5a8).
> ------------[ cut here ]------------
> kernel BUG at lib/list_debug.c:29!
> cpu 0x2: Vector: 700 (Program Check) at [c000000241927a30]
> pc: c000000000f26ed0: __list_add_valid_or_report+0x120/0x164
> lr: c000000000f26ecc: __list_add_valid_or_report+0x11c/0x164
> sp: c000000241927cd0
> msr: 800000000282b033
> current = 0xc000000241215200
> paca = 0xc0000003fffff300 irqmask: 0x03 irq_happened: 0x09
> pid = 258, comm = kunit_try_catch
> kernel BUG at lib/list_debug.c:29!
> enter ? for help
> __percpu_counter_init_many+0x148/0x184
> ext4_es_register_shrinker+0x74/0x23c
> extents_kunit_init+0x100/0x308
> kunit_try_run_case+0x78/0x1f8
> kunit_generic_run_threadfn_adapter+0x40/0x70
> kthread+0x190/0x1a0
> start_kernel_thread+0x14/0x18
> 2:mon>
>
> [...]
Applied, thanks!
[1/1] ext4: kunit: extents-test: Fix percpu_counters list corruption
commit: bd7f1a0278d2d1fe88a734c3b8273c1a62db35cc
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* Re: [PATCH] ext4: convert inline data to extents when truncate exceeds inline size
From: Theodore Ts'o @ 2026-03-26 11:57 UTC (permalink / raw)
To: adilger.kernel, Deepanshu Kartikey
Cc: Theodore Ts'o, linux-ext4, linux-kernel,
syzbot+7de5fe447862fc37576f, Deepanshu Kartikey
In-Reply-To: <20260207043607.1175976-1-kartikey406@gmail.com>
On Sat, 07 Feb 2026 10:06:07 +0530, Deepanshu Kartikey wrote:
> Add a check in ext4_setattr() to convert files from inline data storage
> to extent-based storage when truncate() grows the file size beyond the
> inline capacity. This prevents the filesystem from entering an
> inconsistent state where the inline data flag is set but the file size
> exceeds what can be stored inline.
>
> Without this fix, the following sequence causes a kernel BUG_ON():
>
> [...]
Applied, thanks!
[1/1] ext4: convert inline data to extents when truncate exceeds inline size
commit: ea3ec364b624093c46426269a34cf7568af6d6cf
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply
* Re: [RFC 1/1] ext4: fail fast on repeated metadata reads after IO failure
From: Zhang Yi @ 2026-03-26 11:09 UTC (permalink / raw)
To: Diangang Li, Zhang Yi, Andreas Dilger, Diangang Li
Cc: tytso, linux-ext4, linux-fsdevel, linux-kernel, changfengnan
In-Reply-To: <aa1f5bb1-ffa0-4c85-a228-730593bd4ed0@bytedance.com>
On 3/26/2026 3:42 PM, Diangang Li wrote:
> Hi, Yi,
>
> Thanks. Yes, for existing metadata blocks ext4 is read-modify-write, so
> without a successful read (Uptodate) there is no write path to update
> that block.
>
> In the case we're seeing, the read keeps failing (repeated I/O errors on
> the same LBA), so the write never has a chance to run either. Given
> that, would it make sense (as Fengnan suggested) to treat persistent
> media errors (e.g. MEDIUM ERROR / IO ERROR) as non-retryable at the
> filesystem level, i.e. keep failing fast for that block? That would
> avoid the BH_Lock thundering herd and prevent hung tasks.
>
FYI, AFAICT, while this approach makes sense in theory, it actually
faces challenges in fault recovery. This is because these error codes
are not always reliable (especially BLK_STS_IOERR). In some scenarios
where reliability requirements are not very high, customers might not
immediately notice these errors due to transient faults on some storage
devices(such as some network storage scenarios), and these errors might
resolve themselves after a certain period of time. However, after this,
we have to perform some heavy-weight operations, such as stopping
services and remounting the file system, to recover our services. I
believe there will definitely be customers who will complain about
this.
Thanks,
Yi.
> Thanks,
> Diangang
>
> On 3/25/26 10:27 PM, Zhang Yi wrote:
>> Hi, Diangang,
>>
>> On 3/25/2026 7:13 PM, Diangang Li wrote:
>>> Hi Andreas,
>>>
>>> BH_Read_EIO is cleared on successful read or write.
>>
>> I think what Andreas means is, since you modified the ext4_read_bh()
>> interface, if the bh to be read already has the Read_EIO flag set, then
>> subsequent read operations through this interface will directly return
>> failure without issuing a read I/O. At the same time, because its state
>> is also not uptodate, for an existing block, a write request will not be
>> issued either. How can we clear this Read_EIO flag? IIRC, relying solely
>> on ext4_read_bh_nowait() doesn't seem sufficient to achieve this.
>>
>> Thanks,
>> Yi.
>>
>>>
>>> In practice bad blocks are typically repaired/remapped on write, so we
>>> expect recovery after a successful rewrite. If the block is never
>>> rewritten, repeatedly issuing the same failing read does not help.
>>>
>>> We clear the flag on successful reads so the buffer can recover
>>> immediately if the error was transient. Since read-ahead reads are not
>>> blocked, a later successful read-ahead will clear the flag and allow
>>> subsequent synchronous readers to proceed normally.
>>>
>>> Best,
>>> Diangang
>>>
>>> On 3/25/26 6:15 PM, Andreas Dilger wrote:
>>>> On Mar 25, 2026, at 03:33, Diangang Li <diangangli@gmail.com> wrote:
>>>>>
>>>>> From: Diangang Li <lidiangang@bytedance.com>
>>>>>
>>>>> ext4 metadata reads serialize on BH_Lock (lock_buffer). If the read
>>>>> fails,
>>>>> the buffer remains !Uptodate. With concurrent callers, each waiter can
>>>>> retry the same failing read after the previous holder drops BH_Lock.
>>>>> This
>>>>> amplifies device retry latency and may trigger hung tasks.
>>>>>
>>>>> In the normal read path the block driver already performs its own
>>>>> retries.
>>>>> Once the retries keep failing, re-submitting the same metadata read
>>>>> from
>>>>> the filesystem just amplifies the latency by serializing waiters on
>>>>> BH_Lock.
>>>>>
>>>>> Remember read failures on buffer_head and fail fast for ext4
>>>>> metadata reads
>>>>> once a buffer has already failed to read. Clear the flag on successful
>>>>> read/write completion so the buffer can recover. ext4 read-ahead uses
>>>>> ext4_read_bh_nowait(), so it does not set the failure flag and remains
>>>>> best-effort.
>>>>
>>>> Not that the patch is bad, but if the BH_Read_EIO flag is set on a
>>>> buffer
>>>> and it prevents other tasks from reading that block again, how would the
>>>> buffer ever become Uptodate to clear the flag? There isn't enough state
>>>> in a 1-bit flag to have any kind of expiry and later retry.
>>>>
>>>> Cheers, Andreas
>>>
>>
>
>
^ permalink raw reply
* [PATCH v3 11/11] ext4: zero post-EOF partial block before appending write
From: Zhang Yi @ 2026-03-26 11:10 UTC (permalink / raw)
To: linux-ext4
Cc: linux-fsdevel, linux-kernel, tytso, adilger.kernel, jack, ojaswin,
ritesh.list, libaokun, yi.zhang, yi.zhang, yizhang089, yangerkun,
yukuai
In-Reply-To: <20260326111054.907252-1-yi.zhang@huaweicloud.com>
From: Zhang Yi <yi.zhang@huawei.com>
In cases of appending write beyond EOF, ext4_zero_partial_blocks() is
called within ext4_*_write_end() to zero out the partial block beyond
EOF. This prevents exposing stale data that might be written through
mmap.
However, supporting only the regular buffered write path is
insufficient. It is also necessary to support the DAX path as well as
the upcoming iomap buffered write path. Therefore, move this operation
to ext4_write_checks().
In addition, this may introduce a race window in which a post-EOF
buffered write can race with an mmap write after the old EOF block has
been zeroed. As a result, the data in this block written by the
buffer-write and the data written by the mmap-write may be mixed.
However, this is safe because users should not rely on the result of the
race condition.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
---
fs/ext4/file.c | 17 +++++++++++++++++
fs/ext4/inode.c | 21 +++++++--------------
2 files changed, 24 insertions(+), 14 deletions(-)
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index f1dc5ce791a7..ec0d81bea07a 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -271,6 +271,8 @@ static ssize_t ext4_generic_write_checks(struct kiocb *iocb,
static ssize_t ext4_write_checks(struct kiocb *iocb, struct iov_iter *from)
{
+ struct inode *inode = file_inode(iocb->ki_filp);
+ loff_t old_size = i_size_read(inode);
ssize_t ret, count;
count = ext4_generic_write_checks(iocb, from);
@@ -280,6 +282,21 @@ static ssize_t ext4_write_checks(struct kiocb *iocb, struct iov_iter *from)
ret = file_modified(iocb->ki_filp);
if (ret)
return ret;
+
+ /*
+ * If the position is beyond the EOF, it is necessary to zero out the
+ * partial block that beyond the existing EOF, as it may contains
+ * stale data written through mmap.
+ */
+ if (iocb->ki_pos > old_size && !ext4_verity_in_progress(inode)) {
+ if (iocb->ki_flags & IOCB_NOWAIT)
+ return -EAGAIN;
+
+ ret = ext4_block_zero_eof(inode, old_size, iocb->ki_pos);
+ if (ret)
+ return ret;
+ }
+
return count;
}
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 5c54d5c6fdfe..d52cffdea635 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1456,10 +1456,9 @@ static int ext4_write_end(const struct kiocb *iocb,
folio_unlock(folio);
folio_put(folio);
- if (old_size < pos && !verity) {
+ if (old_size < pos && !verity)
pagecache_isize_extended(inode, old_size, pos);
- ext4_block_zero_eof(inode, old_size, pos);
- }
+
/*
* Don't mark the inode dirty under folio lock. First, it unnecessarily
* makes the holding time of folio lock longer. Second, it forces lock
@@ -1574,10 +1573,8 @@ static int ext4_journalled_write_end(const struct kiocb *iocb,
folio_unlock(folio);
folio_put(folio);
- if (old_size < pos && !verity) {
+ if (old_size < pos && !verity)
pagecache_isize_extended(inode, old_size, pos);
- ext4_block_zero_eof(inode, old_size, pos);
- }
if (size_changed) {
ret2 = ext4_mark_inode_dirty(handle, inode);
@@ -3196,7 +3193,7 @@ static int ext4_da_do_write_end(struct address_space *mapping,
struct inode *inode = mapping->host;
loff_t old_size = inode->i_size;
bool disksize_changed = false;
- loff_t new_i_size, zero_len = 0;
+ loff_t new_i_size;
handle_t *handle;
if (unlikely(!folio_buffers(folio))) {
@@ -3240,19 +3237,15 @@ static int ext4_da_do_write_end(struct address_space *mapping,
folio_unlock(folio);
folio_put(folio);
- if (pos > old_size) {
+ if (pos > old_size)
pagecache_isize_extended(inode, old_size, pos);
- zero_len = pos - old_size;
- }
- if (!disksize_changed && !zero_len)
+ if (!disksize_changed)
return copied;
- handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
+ handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
if (IS_ERR(handle))
return PTR_ERR(handle);
- if (zero_len)
- ext4_block_zero_eof(inode, old_size, pos);
ext4_mark_inode_dirty(handle, inode);
ext4_journal_stop(handle);
--
2.52.0
^ permalink raw reply related
* [PATCH v3 09/11] ext4: remove ctime/mtime update from ext4_alloc_file_blocks()
From: Zhang Yi @ 2026-03-26 11:10 UTC (permalink / raw)
To: linux-ext4
Cc: linux-fsdevel, linux-kernel, tytso, adilger.kernel, jack, ojaswin,
ritesh.list, libaokun, yi.zhang, yi.zhang, yizhang089, yangerkun,
yukuai
In-Reply-To: <20260326111054.907252-1-yi.zhang@huaweicloud.com>
From: Zhang Yi <yi.zhang@huawei.com>
The ctime and mtime update is already handled by file_modified() in
ext4_fallocate(), the caller of ext4_alloc_file_blocks(). So remove the
redundant calls to inode_set_ctime_current() and inode_set_mtime_to_ts()
in ext4_alloc_file_blocks().
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
---
fs/ext4/extents.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 002b1ec8cee2..4155a2e37070 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4623,13 +4623,10 @@ static int ext4_alloc_file_blocks(struct file *file, loff_t offset, loff_t len,
*/
retries = 0;
epos = EXT4_LBLK_TO_B(inode, map.m_lblk + ret);
- inode_set_ctime_current(inode);
if (new_size) {
if (epos > new_size)
epos = new_size;
- if (ext4_update_inode_size(inode, epos) & 0x1)
- inode_set_mtime_to_ts(inode,
- inode_get_ctime(inode));
+ ext4_update_inode_size(inode, epos);
if (epos > old_size)
pagecache_isize_extended(inode, old_size, epos);
}
--
2.52.0
^ permalink raw reply related
* [PATCH v3 07/11] ext4: pass allocate range as loff_t to ext4_alloc_file_blocks()
From: Zhang Yi @ 2026-03-26 11:10 UTC (permalink / raw)
To: linux-ext4
Cc: linux-fsdevel, linux-kernel, tytso, adilger.kernel, jack, ojaswin,
ritesh.list, libaokun, yi.zhang, yi.zhang, yizhang089, yangerkun,
yukuai
In-Reply-To: <20260326111054.907252-1-yi.zhang@huaweicloud.com>
From: Zhang Yi <yi.zhang@huawei.com>
Change ext4_alloc_file_blocks() to accept offset and len in byte
granularity instead of block granularity. This allows callers to pass
byte offsets and lengths directly, and this prepares for moving the
ext4_zero_partial_blocks() call from the while(len) loop for unaligned
append writes, where it only needs to be invoked once before doing block
allocation.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
---
fs/ext4/extents.c | 53 ++++++++++++++++++++---------------------------
1 file changed, 22 insertions(+), 31 deletions(-)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 753a0f3418a4..57a686b600d9 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4542,15 +4542,15 @@ int ext4_ext_truncate(handle_t *handle, struct inode *inode)
return err;
}
-static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
- ext4_lblk_t len, loff_t new_size,
- int flags)
+static int ext4_alloc_file_blocks(struct file *file, loff_t offset, loff_t len,
+ loff_t new_size, int flags)
{
struct inode *inode = file_inode(file);
handle_t *handle;
int ret = 0, ret2 = 0, ret3 = 0;
int retries = 0;
int depth = 0;
+ ext4_lblk_t len_lblk;
struct ext4_map_blocks map;
unsigned int credits;
loff_t epos, old_size = i_size_read(inode);
@@ -4558,14 +4558,14 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
bool alloc_zero = false;
BUG_ON(!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS));
- map.m_lblk = offset;
- map.m_len = len;
+ map.m_lblk = offset >> blkbits;
+ map.m_len = len_lblk = EXT4_MAX_BLOCKS(len, offset, blkbits);
/*
* Don't normalize the request if it can fit in one extent so
* that it doesn't get unnecessarily split into multiple
* extents.
*/
- if (len <= EXT_UNWRITTEN_MAX_LEN)
+ if (len_lblk <= EXT_UNWRITTEN_MAX_LEN)
flags |= EXT4_GET_BLOCKS_NO_NORMALIZE;
/*
@@ -4582,16 +4582,16 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
/*
* credits to insert 1 extent into extent tree
*/
- credits = ext4_chunk_trans_blocks(inode, len);
+ credits = ext4_chunk_trans_blocks(inode, len_lblk);
depth = ext_depth(inode);
retry:
- while (len) {
+ while (len_lblk) {
/*
* Recalculate credits when extent tree depth changes.
*/
if (depth != ext_depth(inode)) {
- credits = ext4_chunk_trans_blocks(inode, len);
+ credits = ext4_chunk_trans_blocks(inode, len_lblk);
depth = ext_depth(inode);
}
@@ -4648,7 +4648,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
}
map.m_lblk += ret;
- map.m_len = len = len - ret;
+ map.m_len = len_lblk = len_lblk - ret;
}
if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
goto retry;
@@ -4665,11 +4665,9 @@ static long ext4_zero_range(struct file *file, loff_t offset,
{
struct inode *inode = file_inode(file);
handle_t *handle = NULL;
- loff_t new_size = 0;
+ loff_t align_start, align_end, new_size = 0;
loff_t end = offset + len;
- ext4_lblk_t start_lblk, end_lblk;
unsigned int blocksize = i_blocksize(inode);
- unsigned int blkbits = inode->i_blkbits;
int ret, flags, credits;
trace_ext4_zero_range(inode, offset, len, mode);
@@ -4690,11 +4688,8 @@ static long ext4_zero_range(struct file *file, loff_t offset,
flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
/* Preallocate the range including the unaligned edges */
if (!IS_ALIGNED(offset | end, blocksize)) {
- ext4_lblk_t alloc_lblk = offset >> blkbits;
- ext4_lblk_t len_lblk = EXT4_MAX_BLOCKS(len, offset, blkbits);
-
- ret = ext4_alloc_file_blocks(file, alloc_lblk, len_lblk,
- new_size, flags);
+ ret = ext4_alloc_file_blocks(file, offset, len, new_size,
+ flags);
if (ret)
return ret;
}
@@ -4709,18 +4704,17 @@ static long ext4_zero_range(struct file *file, loff_t offset,
return ret;
/* Zero range excluding the unaligned edges */
- start_lblk = EXT4_B_TO_LBLK(inode, offset);
- end_lblk = end >> blkbits;
- if (end_lblk > start_lblk) {
- ext4_lblk_t zero_blks = end_lblk - start_lblk;
-
+ align_start = round_up(offset, blocksize);
+ align_end = round_down(end, blocksize);
+ if (align_end > align_start) {
if (mode & FALLOC_FL_WRITE_ZEROES)
flags = EXT4_GET_BLOCKS_CREATE_ZERO | EXT4_EX_NOCACHE;
else
flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
EXT4_EX_NOCACHE);
- ret = ext4_alloc_file_blocks(file, start_lblk, zero_blks,
- new_size, flags);
+ ret = ext4_alloc_file_blocks(file, align_start,
+ align_end - align_start, new_size,
+ flags);
if (ret)
return ret;
}
@@ -4768,15 +4762,11 @@ static long ext4_do_fallocate(struct file *file, loff_t offset,
struct inode *inode = file_inode(file);
loff_t end = offset + len;
loff_t new_size = 0;
- ext4_lblk_t start_lblk, len_lblk;
int ret;
trace_ext4_fallocate_enter(inode, offset, len, mode);
WARN_ON_ONCE(!inode_is_locked(inode));
- start_lblk = offset >> inode->i_blkbits;
- len_lblk = EXT4_MAX_BLOCKS(len, offset, inode->i_blkbits);
-
/* We only support preallocation for extent-based files only. */
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
ret = -EOPNOTSUPP;
@@ -4791,7 +4781,7 @@ static long ext4_do_fallocate(struct file *file, loff_t offset,
goto out;
}
- ret = ext4_alloc_file_blocks(file, start_lblk, len_lblk, new_size,
+ ret = ext4_alloc_file_blocks(file, offset, len, new_size,
EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT);
if (ret)
goto out;
@@ -4801,7 +4791,8 @@ static long ext4_do_fallocate(struct file *file, loff_t offset,
EXT4_I(inode)->i_sync_tid);
}
out:
- trace_ext4_fallocate_exit(inode, offset, len_lblk, ret);
+ trace_ext4_fallocate_exit(inode, offset,
+ EXT4_MAX_BLOCKS(len, offset, inode->i_blkbits), ret);
return ret;
}
--
2.52.0
^ permalink raw reply related
* [PATCH v3 08/11] ext4: move zero partial block range functions out of active handle
From: Zhang Yi @ 2026-03-26 11:10 UTC (permalink / raw)
To: linux-ext4
Cc: linux-fsdevel, linux-kernel, tytso, adilger.kernel, jack, ojaswin,
ritesh.list, libaokun, yi.zhang, yi.zhang, yizhang089, yangerkun,
yukuai
In-Reply-To: <20260326111054.907252-1-yi.zhang@huaweicloud.com>
From: Zhang Yi <yi.zhang@huawei.com>
Move ext4_block_zero_eof() and ext4_zero_partial_blocks() calls out of
the active handle context, making them independent operations, and also
add return value checks. This is safe because it still ensures data is
updated before metadata for data=ordered mode and data=journal mode
because we still zero data and ordering data before modifying the
metadata.
This change is required for iomap infrastructure conversion because the
iomap buffered I/O path does not use the same journal infrastructure for
partial block zeroing. The lock ordering of folio lock and starting
transactions is "folio lock -> transaction start", which is opposite of
the current path. Therefore, zeroing partial blocks cannot be performed
under the active handle.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
---
fs/ext4/extents.c | 32 +++++++++++++++-----------------
fs/ext4/inode.c | 47 ++++++++++++++++++++++++++---------------------
2 files changed, 41 insertions(+), 38 deletions(-)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 57a686b600d9..002b1ec8cee2 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4585,6 +4585,13 @@ static int ext4_alloc_file_blocks(struct file *file, loff_t offset, loff_t len,
credits = ext4_chunk_trans_blocks(inode, len_lblk);
depth = ext_depth(inode);
+ /* Zero to the end of the block containing i_size */
+ if (new_size > old_size) {
+ ret = ext4_block_zero_eof(inode, old_size, LLONG_MAX);
+ if (ret)
+ return ret;
+ }
+
retry:
while (len_lblk) {
/*
@@ -4623,10 +4630,8 @@ static int ext4_alloc_file_blocks(struct file *file, loff_t offset, loff_t len,
if (ext4_update_inode_size(inode, epos) & 0x1)
inode_set_mtime_to_ts(inode,
inode_get_ctime(inode));
- if (epos > old_size) {
+ if (epos > old_size)
pagecache_isize_extended(inode, old_size, epos);
- ext4_block_zero_eof(inode, old_size, epos);
- }
}
ret2 = ext4_mark_inode_dirty(handle, inode);
ext4_update_inode_fsync_trans(handle, inode, 1);
@@ -4668,7 +4673,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
loff_t align_start, align_end, new_size = 0;
loff_t end = offset + len;
unsigned int blocksize = i_blocksize(inode);
- int ret, flags, credits;
+ int ret, flags;
trace_ext4_zero_range(inode, offset, len, mode);
WARN_ON_ONCE(!inode_is_locked(inode));
@@ -4722,25 +4727,18 @@ static long ext4_zero_range(struct file *file, loff_t offset,
if (IS_ALIGNED(offset | end, blocksize))
return ret;
- /*
- * In worst case we have to writeout two nonadjacent unwritten
- * blocks and update the inode
- */
- credits = (2 * ext4_ext_index_trans_blocks(inode, 2)) + 1;
- if (ext4_should_journal_data(inode))
- credits += 2;
- handle = ext4_journal_start(inode, EXT4_HT_MISC, credits);
+ /* Zero out partial block at the edges of the range */
+ ret = ext4_zero_partial_blocks(inode, offset, len);
+ if (ret)
+ return ret;
+
+ handle = ext4_journal_start(inode, EXT4_HT_MISC, 1);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
ext4_std_error(inode->i_sb, ret);
return ret;
}
- /* Zero out partial block at the edges of the range */
- ret = ext4_zero_partial_blocks(inode, offset, len);
- if (ret)
- goto out_handle;
-
if (new_size)
ext4_update_inode_size(inode, new_size);
ret = ext4_mark_inode_dirty(handle, inode);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 94c8e8c3984f..5c54d5c6fdfe 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4442,8 +4442,12 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
if (ret)
return ret;
+ ret = ext4_zero_partial_blocks(inode, offset, length);
+ if (ret)
+ return ret;
+
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
- credits = ext4_chunk_trans_extent(inode, 2);
+ credits = ext4_chunk_trans_extent(inode, 0);
else
credits = ext4_blocks_for_truncate(inode);
handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
@@ -4453,10 +4457,6 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
return ret;
}
- ret = ext4_zero_partial_blocks(inode, offset, length);
- if (ret)
- goto out_handle;
-
/* If there are blocks to remove, do it */
start_lblk = EXT4_B_TO_LBLK(inode, offset);
end_lblk = end >> inode->i_blkbits;
@@ -4588,6 +4588,11 @@ int ext4_truncate(struct inode *inode)
err = ext4_inode_attach_jinode(inode);
if (err)
goto out_trace;
+
+ /* Zero to the end of the block containing i_size */
+ err = ext4_block_zero_eof(inode, inode->i_size, LLONG_MAX);
+ if (err)
+ goto out_trace;
}
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
@@ -4601,10 +4606,6 @@ int ext4_truncate(struct inode *inode)
goto out_trace;
}
- /* Zero to the end of the block containing i_size */
- if (inode->i_size & (inode->i_sb->s_blocksize - 1))
- ext4_block_zero_eof(inode, inode->i_size, LLONG_MAX);
-
/*
* We add the inode to the orphan list, so that if this
* truncate spans multiple transactions, and we crash, we will
@@ -5962,15 +5963,6 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
goto out_mmap_sem;
}
- handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
- if (IS_ERR(handle)) {
- error = PTR_ERR(handle);
- goto out_mmap_sem;
- }
- if (ext4_handle_valid(handle) && shrink) {
- error = ext4_orphan_add(handle, inode);
- orphan = 1;
- }
/*
* Update c/mtime and tail zero the EOF folio on
* truncate up. ext4_truncate() handles the shrink case
@@ -5979,9 +5971,22 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
if (!shrink) {
inode_set_mtime_to_ts(inode,
inode_set_ctime_current(inode));
- if (oldsize & (inode->i_sb->s_blocksize - 1))
- ext4_block_zero_eof(inode, oldsize,
- LLONG_MAX);
+ if (oldsize & (inode->i_sb->s_blocksize - 1)) {
+ error = ext4_block_zero_eof(inode,
+ oldsize, LLONG_MAX);
+ if (error)
+ goto out_mmap_sem;
+ }
+ }
+
+ handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
+ if (IS_ERR(handle)) {
+ error = PTR_ERR(handle);
+ goto out_mmap_sem;
+ }
+ if (ext4_handle_valid(handle) && shrink) {
+ error = ext4_orphan_add(handle, inode);
+ orphan = 1;
}
if (shrink)
--
2.52.0
^ permalink raw reply related
* [PATCH v3 10/11] ext4: move pagecache_isize_extended() out of active handle
From: Zhang Yi @ 2026-03-26 11:10 UTC (permalink / raw)
To: linux-ext4
Cc: linux-fsdevel, linux-kernel, tytso, adilger.kernel, jack, ojaswin,
ritesh.list, libaokun, yi.zhang, yi.zhang, yizhang089, yangerkun,
yukuai
In-Reply-To: <20260326111054.907252-1-yi.zhang@huaweicloud.com>
From: Zhang Yi <yi.zhang@huawei.com>
In ext4_alloc_file_blocks(), pagecache_isize_extended() is called under
an active handle and may also hold folio lock if the block size is
smaller than the folio size. This also breaks the "folio lock ->
transaction start" lock ordering for the upcoming iomap buffered I/O
path.
Therefore, move pagecache_isize_extended() outside of an active handle.
Additionally, it is unnecessary to update the file length during each
iteration of the allocation loop. Instead, update the file length only
to the position where the allocation is successful. Postpone updating
the inode size until after the allocation loop completes or is
interrupted due to an error.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
---
fs/ext4/extents.c | 69 +++++++++++++++++++++++++++++------------------
1 file changed, 43 insertions(+), 26 deletions(-)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 4155a2e37070..19fc1ef7b2c3 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4618,44 +4618,61 @@ static int ext4_alloc_file_blocks(struct file *file, loff_t offset, loff_t len,
ext4_journal_stop(handle);
break;
}
+ ext4_update_inode_fsync_trans(handle, inode, 1);
+ ret = ext4_journal_stop(handle);
+ if (unlikely(ret))
+ break;
+
/*
* allow a full retry cycle for any remaining allocations
*/
retries = 0;
- epos = EXT4_LBLK_TO_B(inode, map.m_lblk + ret);
- if (new_size) {
- if (epos > new_size)
- epos = new_size;
- ext4_update_inode_size(inode, epos);
- if (epos > old_size)
- pagecache_isize_extended(inode, old_size, epos);
+
+ if (alloc_zero &&
+ (map.m_flags & (EXT4_MAP_MAPPED | EXT4_MAP_UNWRITTEN))) {
+ ret = ext4_issue_zeroout(inode, map.m_lblk, map.m_pblk,
+ map.m_len);
+ if (likely(!ret))
+ ret = ext4_convert_unwritten_extents(NULL,
+ inode, (loff_t)map.m_lblk << blkbits,
+ (loff_t)map.m_len << blkbits);
+ if (ret)
+ break;
}
+
+ map.m_lblk += map.m_len;
+ map.m_len = len_lblk = len_lblk - map.m_len;
+ }
+
+ if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
+
+ if (!new_size)
+ return ret;
+
+ /*
+ * Update the file size to match the size of the already successfully
+ * allocated blocks.
+ */
+ epos = EXT4_LBLK_TO_B(inode, map.m_lblk);
+ if (epos > new_size)
+ epos = new_size;
+ if (epos > old_size) {
+ handle = ext4_journal_start(inode, EXT4_HT_MISC, 1);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ ext4_update_inode_size(inode, epos);
+
ret2 = ext4_mark_inode_dirty(handle, inode);
ext4_update_inode_fsync_trans(handle, inode, 1);
ret3 = ext4_journal_stop(handle);
ret2 = ret3 ? ret3 : ret2;
- if (unlikely(ret2))
- break;
- if (alloc_zero &&
- (map.m_flags & (EXT4_MAP_MAPPED | EXT4_MAP_UNWRITTEN))) {
- ret2 = ext4_issue_zeroout(inode, map.m_lblk, map.m_pblk,
- map.m_len);
- if (likely(!ret2))
- ret2 = ext4_convert_unwritten_extents(NULL,
- inode, (loff_t)map.m_lblk << blkbits,
- (loff_t)map.m_len << blkbits);
- if (ret2)
- break;
- }
-
- map.m_lblk += ret;
- map.m_len = len_lblk = len_lblk - ret;
+ pagecache_isize_extended(inode, old_size, epos);
}
- if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
- goto retry;
- return ret > 0 ? ret2 : ret;
+ return ret ? ret : ret2;
}
static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len);
--
2.52.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox