| Age | Commit message (Collapse) | Author |
|
git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 updates from Ted Ts'o:
- Improve performance by allowing parallel DIO writes when we were
previously being overly conservative when checking whether it was
safe to avoid requiring an exclusive lock
- Improve the performance of ext4_mb_prefetch() used by fallocate() by
avoiding work when it is not needed
- Remove the unnecessary custom end_io function
ext4_end_buffer_io_sync()
- Improve performance when performing an overwrite to an already
uptodate folio
- Clean up how we handle deallocating EA inodes to avoid a potential
lock ordering issue when there is a failed mount while an EA inode is
still being evicted
- Use str_plural() instead of a custom macro
- Avoid soft lockups or RCU stalls if there are many busy buffers
(caused by heavy I/O) while checkpointing
- Use scoped NOFS when starting a handle in nojournal mode
- Align fields in handle structure to optimize setting and getting the
h_type and h_line_no fields
- Fix documentation of the meta_bg block group layout
- Bug fixes:
- Fix a potential out-of-bounds read in ext4_read_inline_dir()
- Fix a potential deadlock when concurrent xattr operations are
racing with each other when some of the xattrs are using the
ea_inode feature
- Fix a spurious warning with data=journal that can be triggered
when writeback races with remounting the file system read-only
- Fix a potential deadlock when EXT4_IOC_MIGRATE races with a file
system freeze operation
- Make sure all in-flight direct I/O operations are complete before
falling back to buffered I/O
- Handle IOCB_NOWAIT properly when performing a extending DAX write
- Prevent potentially sleeping on a block allocation when
IOCB_NOWAIT is set
- Fix potential races when racing an inline data write with a page
fault
- Propagate errors when adding or removing extent ranges during a
fast commit replay
- Avoid trying to expand an inode's extra size when it is being
evicted to avoid a number of corner case or deadlocks
- Avoid spurious error when retrying inode extra size expansion
- Fix corner cases where we underestimate the number of journal
credits needed
- Avoid hangs/crashes/WARNINGS caused by maliciously corrupted file
systems
- Don't issue spurious orphan clean message on RO file systems
- Avoid leaving the file system in an inconsistent state after a
crash when a WRITE_ZEROS in progress converting an unwritten
extent to a written extent
- Handle WRITE_ZEROS correctly when there are some partially dirtied
regions in the page cache
- Pass errors during zero-rage, truncate, or punch hole to the
caller if ext4_get_block() fails
- Wait for writeback to finish when triggered by zero-range or
zero-range for those devices that require stable writes
- If the reserved gid superblock field is set, set the reserved gid
instead of the reserved uid
* tag 'ext4_for_linus-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (56 commits)
ext4: fix estimate extent index blocks in ext4_ext_index_trans_blocks()
ext4: fix transaction overflow during writeback
ext4: teach ext4_meta_trans_blocks() about number of allocated extents
ext4: guard against NULL s_group_info in ext4_get_group_info
ext4: fix spurious message about orphan cleanup on RO fs
ext4: stop retrying saturated xattr cache entries
ext4: don't enable DAX on new encrypted files
ext4: protect WRITE_ZEROES written extents with orphan list
ext4: export converted block count from ext4_convert_unwritten_extents()
ext4: fix incorrect function call when initializing s_resgid
ext4: validate EA inode i_nlink in ext4_xattr_inode_iget
jbd2: align h_type and h_line_no in the handle structure on byte boundaries
ext4: enable scoped NOFS when starting a handle in nojournal mode
ext4: write back partial-zeroed edges in WRITE_ZEROES
ext4: zero out whole block for clean edges in WRITE_ZEROES
ext4: track partial-zero outcome per edge in ext4_zero_partial_blocks()
ext4: clarify return semantics of ext4_load_tail_bh()
ext4: move partial block zeroing earlier in ext4_zero_range()
ext4: check return value of ext4_get_block() in ext4_load_tail_bh()
ext4: skip tail block zeroing for inline data files
...
|
|
Pull fscrypt updates from Eric Biggers:
"The main change this cycle is a significant simplification that's been
overdue for a while now: standardizing on a single file contents
encryption implementation in ext4 and f2fs, instead of having two.
Specifically, the original filesystem-layer file contents encryption
implementation is removed, and the blk-crypto implementation is now
used unconditionally. blk-crypto delegates either to inline crypto
hardware or to the CPU via blk-crypto-fallback. The latter is
functionally equivalent to the original filesystem-layer code.
The blk-crypto implementation already existed, but previously it was
used only when the filesystem was mounted with "-o inlinecrypt". Now,
"-o inlinecrypt" just selects whether inline crypto hardware is used.
To allow maintaining that user control over hardware use, the
blk-crypto API is extended with a new flag BLK_CRYPTO_CFG_ALLOW_HW.
Overall, this removes quite a bit of redundant code from ext4, f2fs,
and fs/crypto/. It should make things easier for ongoing filesystem
efforts such as iomap support, large folios, and btrfs encryption
(btrfs had already been planning to use blk-crypto exclusively.)
There are two small behavior changes of note:
- Direct I/O now works on encrypted files even without "-o inlinecrypt",
rather than falling back to buffered I/O. This is effectively a
bugfix, though I'll continue to keep an eye out for any user that
may have been depending on the buffered I/O fallback.
- IV_INO_LBLK_32 policies are no longer supported in certain cases
that didn't make sense and have no known uses.
This has been in linux-next since July 22 with no reported issues. All
encryption xfstests pass on ext4 and f2fs. As usual I've also been
using it on a system with an fscrypt-encrypted home directory. Of
course, the blk-crypto code paths also aren't new and were already
being used on many systems via the inlinecrypt mount option.
In addition to the main change described above, there are a few other
cleanups such as using lock guards for mutexes, improving
documentation, and removing a workaround for outdated gcc versions"
* tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/linux: (29 commits)
blk-crypto: Update docs for blk-crypto-fallback motivation
blk-crypto: Remove unused function blk_crypto_config_supported()
fscrypt: Update docs for data path
fscrypt: Remove unused function fscrypt_finalize_bounce_page()
f2fs: Update outdated comment in f2fs_write_begin()
fs: Update outdated comment for SB_INLINECRYPT
fscrypt: Update encryption policy version docs
fscrypt: Replace some variable-size memsets with fixed-size
fscrypt: Add safety checks to non-block-based en/decryption
fscrypt: Merge bio.c and inline_crypt.c into block.c
fscrypt: Remove unused functions and workqueue
fscrypt: Remove fs-layer zeroout code
fscrypt: Remove fscrypt_dio_supported()
fscrypt: Replace calls to fscrypt_inode_uses_inline_crypto()
fs/buffer: Remove fs-layer decryption code
f2fs: Remove fs-layer file contents en/decryption code
ext4: Further de-generalize the bio postprocessing code
ext4: Make ext4_bio_write_folio() return void
ext4: Remove fs-layer file contents en/decryption code
Documentation: fscrypt: Update docs for inlinecrypt
...
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs writeback updates from Christian Brauner:
"This makes sync_inode_metadata() and writeback_single_inode() persist
not only the inode but all metadata associated with it.
A new .sync_inode_metadata superblock operation is called from
__writeback_single_inode(). Alongside it a new I_METADATA_WRITEBACK
state flag is added.
Filesystems no longer need their own mmb_fsync() implementations and
can just use simple_fsync(). All metadata is now written for IS_SYNC
and IS_DIRSYNC inodes. Races where several fsyncs raced and mmb_sync()
could return before all buffers were really persisted are fixed since
I_SYNC now serializes properly.
The I_METADATA_WRITEBACK scheme also fixes the case where a
WB_SYNC_NONE writeback landing between write(2) and fsync(2) left
fsync(2) failing to persist the inode. That problem is not specific to
filesystems using the generic metadata bh tracking, and the ones that
do not are left alone.
ext2, udf, bfs, minix, fat and ext4 in nojournal mode have their data
integrity writeout fixed and are converted. affs drops metadata bh
tracking and mmb_fsync() is removed.
A few other fixes came out of this:
- a UAF in mark_buffer_write_io_error()
- missed inode writeback when racing with __writeback_single_inode()
- ext4 allocating the mapping_metadata_bhs struct on demand
- three fat fixes: a lost inode update in do_msdos_rename() with
DIRSYNC, inode buffer write errors not propagating out of
fat_sync_inode_metadata() and directory entries not being
persisted on fsync(2) of the root directory"
* tag 'vfs-7.3-rc1.sync' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (24 commits)
writeback: Export __inode_attach_wb()
fat: Fix persisting directory entries on fsync(2) of the root directory
fat: Propagate inode buffer write errors from fat_sync_inode_metadata()
fat: Fix lost inode update in do_msdos_rename() with DIRSYNC
vfs: Remove mmb_fsync()
fat: Replace fat_sync_inode() with sync_inode_metadata()
fat: Fix missed inode writeback during fsync(2)
ext4: Fix data integrity writeout issues in nojournal mode
minix: Fix data integrity writeout issues
bfs: Fix data integrity writeout issues
udf: Fold udf_update_inode() into udf_write_inode()
udf: Use sync_inode_metadata() in udf_evict_inode()
udf: Drop udf_sync_inode()
udf: Use sync_inode_metadata() to writeout IS_SYNC inode
udf: Fix data integrity writeout issues
ext2: Fix data integrity writeout issues
ext2: Avoid unnecessary inode buffer writeback for sync(2)
ext2: Drop __ext2_write_inode()
ext2: Fix lost inode updates for IS_SYNC inodes
fs: Provide way for filesystem to wait for metadata writeback
...
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs superblock updates from Christian Brauner:
- Make it possible to share a block device between multiple
filesystems.
erofs can mount read-only blob devices shared between many
superblocks, but because we only tracked a single superblock a
freeze, thaw, removal or sync on such a device was never propagated
to all the superblocks using it, and there was no way to find them.
Add an efficient table to lookup all superblocks using a given block
device.
- A bunch of pre-existing fixes fell out of this work:
A block-device freeze racing a btrfs device change could leave the
whole filesystem stuck frozen. A bdev_freeze() issued by "dmsetup
suspend" or an LVM snapshot resolves that holder to freeze the
filesystem. and bdev_thaw() resolves it again to thaw. A freeze
landing while btrfs is adding, removing or replacing a device freezes
the filesystem. The membership change then drops that link. So the
matching thaw could no longer find the superblock.
Forbid freezing a device for the duration of a membership change,
modelled on deny_write_access()/allow_write_access().
* tag 'vfs-7.3-rc1.super' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (24 commits)
super: fix dying superblock warning messages
block: reject block device inodes with i_rdev == 0 in lookup_bdev()
selftests/filesystems: add ustat() coverage
fs: look up the superblock via the device table in user_get_super()
super: make fs_holder_ops private
f2fs: open via dedicated fs bdev helpers
erofs: open via dedicated fs bdev helpers
fs: tolerate per-superblock freeze errors on shared devices
fs: look up superblocks via the device table in fs_holder_ops
ext4: open via dedicated fs bdev helpers
btrfs: open via dedicated fs bdev helpers
xfs: port to fs_bdev_file_open_by_path()
fs: add dedicated block device open helpers for filesystems
fs: maintain a global device-to-superblock table
ocfs2: don't reset s_dev on dismount
ext4: use anonymous devices for KUnit test superblocks
fs, block: move blk_mode_t and fop_flags_t into <linux/types.h>
super: take lock after last reference count
super: convert s_count to refcount_t s_passive
btrfs: deny freezing devices undergoing a replace
...
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull misc vfs updates from Christian Brauner:
"Bigger cleanups:
- The lockref dead-count handling is tidied up.
The open-coded check for a count below zero as the dead marker
relies on information the caller should not have.
- make put_mnt_ns() leave mounts connected. Destroying a mount
namespace disconnected its mounts from their mount points. So a
file descriptor still open on the parent of a mount point could be
used to peek under it.
Locked mounts were already kept connected to prevent exactly that.
But a mount is only locked when its tree is copied across a user
namespace boundary. So a mount namespace set up by a privileged
component had no locked mounts and its mounts were disconnected.
Passing UMOUNT_CONNECTED keeps every mount connected and prevents
that bug.
- vfs_prepare_mode() passes S_IFDIR for directories. I meant to fix
that ago but didn't get to it. So now someone finally did it.
This kills the exception where the mode could be 0 when a directory
was created whereas every other creation operation passed it
explicitly already.
- move long delayed work for ufs, jffs2, hfsplus, hfs and affs from
the per-cpu system_long_wq to the new unbound system_dfl_long_wq.
None of that work relies on per-cpu state and the work item is
enqueued with queue_delayed_work() whose timer is global anyway. So
it may as well benefit from scheduler task placement.
Smaller fixes and cleanups:
- unlock_buffer() and journal_end_buffer_io_sync() use
clear_and_wake_up_bit()
- the pipe page pools are unified into a single per-pipe pool and the
extra wake_up(rd_wait) is limited to EPOLLET consumers
- eventpoll now computes its timer slack lazily in ep_poll()
- shrink_dcache_for_umount() keeps making progress on busy roots
- excess xarray nodes are freed in clear_inode()
- romfs detects hard link cycles
- the user path of nested backing files is fixed
- pidfd holds exec_update_lock around the namespace ioctl
- non-memcg-aware nr_cached_objects is skipped during memcg slab
shrink
- iomap_write_iter() always returns status
- mangle_path() is renamed to seq_mangle_path()
- inode timestamp accessors are annotated
- new regression test for pipe->poll_usage.
- a few documentation, kernel-doc and selftest fixes"
* tag 'vfs-7.3-rc1.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (67 commits)
selftests/namespaces: Fix racy pipe handshake in timens and pidns_separate
selftests/epoll: add a regression test for pipe->poll_usage
pipe: only enable the extra wake_up(rd_wait) for EPOLLET consumers
pidfd: hold exec_update_lock around namespace ioctl
fs: fix user path of nested backing files
fs: remove stale inode_insert5() kernel-doc parameter
fs: fix switch/case indentation in sysfs() syscall
fs: document semantics of kstat::{uid,gid} fields
dcache: keep shrink_dcache_for_umount() making progress on busy roots
seq_file: rename mangle_path to seq_mangle_path
nstree: add/fix struct ns_id_req kernel-doc member fields
dcache: use lockref routines for dead count checks
lockref: tidy up dead count handling
initramfs: fix typo in reserve_initrd_mem comment
fs/pipe: unify the page pools into a single per-pipe pool
fs: annotate inode timestamp accessors
eventpoll: compute timer slack lazily in ep_poll()
selftests/filesystems: add mntns cleanup test
put_mnt_ns(): leave mounts connected
affs: Move long delayed work on system_dfl_long_wq
...
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs lookup updates from Christian Brauner:
"This refactors lookup_open() and adds vfs_lookup_open() for nfsd.
mnt_want_write() and parent locking are moved into lookup_open()
itself.
audit_inode_child() is also now called in lookup_open() on failure.
That is the calling convention in vfs_create() and vfs_mkdir(), but
lookup_open() made no such call when atomic_open() should have created
a file and did not. And neither did the regular ->create() path fwiw.
This also contains work to remove the unneeded excl argument from the
->create() inode op"
* tag 'vfs-7.3-rc1.lookup' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
fs/namei.c: fix coding style in atomic_open() and lookup_open()
fs/namei.c: fix kerneldoc of atomic_open() and vfs_lookup_open()
fs/namei.c: update stale comments in lookup_open()
Remove excl arg to ->create inode_operation
fs/namei.c: update kerneldoc of atomic_open()
vfs: call audit_inode_child() in lookup_open() on failure
vfs: move create error && negative dentry case in lookup_open() up
VFS: add vfs_lookup_open() for nfsd
VFS: move delegated_inode retry loop into lookup_open()
VFS: move mnt_want_write() and locking into lookup_open()
|
|
The estimate of the number of impacted extent tree index blocks could be
one-too-low. If we modify say 2 extents, already two leaf index blocks
could be impacted, not just one the current estimate counts with. Fix
the estimate.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260805153605.166545-6-jack@suse.cz
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Commit 95ad8ee45cdb ("ext4: correct the reserved credits for extent
conversion") was correct to note that we need to reserve enough credits
for all extents possibly underlying a large folio. However it was too
eager to reduce the number of reserved credits. Extent conversion may
not only need to touch several leaf extent blocks, it may also need to
split extents - for example a single large unwritten extent may need to
be split into many small written ones in case of sparse folio dirtying.
This can thus result not only in extent leaf modifications but also in a
need to allocate new extent tree nodes. As a result the reserved
transaction credits were not sufficient in some corner cases. Use
ext4_meta_trans_blocks() for correct upper bound credit estimate.
Fixes: 95ad8ee45cdb ("ext4: correct the reserved credits for extent conversion")
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260805153605.166545-5-jack@suse.cz
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
So far ext4_meta_trans_blocks() expects that each extent counted in
@pextents will be allocated in the transaction we estimate credits for.
This is correct for the use in ext4_chunk_trans_blocks() and
ext4_chunk_trans_extent() however the use in atomic write path
(ext4_convert_unwritten_extents_atomic() and ext4_iomap_alloc() for
IOMAP_ATOMIC) unnecessarily overestimates the number of necessary
credits as neither of them allocates any data. Add argument to
ext4_meta_trans_blocks() for number of extents that are going to be
allocated in the transaction.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260805153605.166545-4-jack@suse.cz
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Resend: previous attempt was rejected by vger for containing HTML.
==================================================================
ext4_mark_group_bitmap_corrupted() already treats a NULL return from
ext4_get_group_info() as "nothing to do", but ext4_get_group_info()
indexes s_group_info without checking whether the array exists.
During mount, fast-commit replay runs inside jbd2_journal_load() from
ext4_load_and_init_journal(), which is before ext4_mb_init() allocates
s_group_info. Replaying an FC UNLINK for an inode whose bitmap bit is
already clear takes:
ext4_fc_replay_unlink -> iput -> ext4_evict_inode -> ext4_free_inode
-> ext4_mark_group_bitmap_corrupted -> ext4_get_group_info
and faults on the NULL s_group_info base. Userspace only mounts a dirty
ext4 image; this is a supported recovery path.
Return NULL when s_group_info (or the per-block grp_info row) is unset
so the existing caller check is effective during early mount.
Tested on Linux v6.6.145 KASAN: crafted FC-unlink image previously
triggered KASAN null-ptr-deref / panic in ext4_get_group_info; with this
patch, mount succeeds (EXT4 "bit already cleared" may still log). Also
observed on v6.6.144; still present on torvalds/linux as of
f5098b6bae76 (2026-07-26).
A self-contained Docker/QEMU reproducer (craft + mount + patch verify) is
available on request.
Signed-off-by: Yu Junzhe <junzheyu1@gmail.com>
Link: https://patch.msgid.link/65c955b0-716b-4599-b925-59c2782e38b4@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
When orphan_file feature is enabled, ext4_orphan_cleanup() was always
walking through the orphan file looking for orphan inodes. This is
mostly harmless but for read-only filesystem it results in spurious
"orphan cleanup on readonly fs" message and in other cornercases it
could result in similar somewhat misleading messages. Skip orphan
cleanup if the orphan file is empty to avoid confusing messages.
Fixes: 02f310fcf47f ("ext4: Speedup ext4 orphan inode handling")
Reported-by: Tigran Aivazian <aivazian.tigran@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Reviewed-by: Baokun Li <libaokun@linux.alibaba.com>
Link: https://patch.msgid.link/20260803160037.64285-2-jack@suse.cz
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
ext4_xattr_block_set() retries when a cache entry selected for reuse
has a saturated reference count after taking the buffer lock. The retry
returns to the mbcache lookup without making that entry ineligible, so
it can select the same unusable entry indefinitely. A task spinning
there can hold the parent directory's i_rwsem and leave concurrent
rmdir callers blocked.
Normally a reusable entry has a reference count below
EXT4_XATTR_REFCOUNT_MAX because the count and MBE_REUSABLE_B are
updated under the same buffer lock. A corrupted filesystem can violate
that invariant. The syzbot reproducer reports allocator and xattr
corruption before triggering this retry loop.
Check the untrusted on-disk count before incrementing it, avoiding
overflow, and clear MBE_REUSABLE_B when it is already saturated. The
next lookup then skips the entry that was just proven unusable. This
mirrors the normal transition at EXT4_XATTR_REFCOUNT_MAX; the release
path marks the entry reusable again on the exact 1024-to-1023
transition.
Using the same QEMU harness and guest parameters, current unpatched
Linux hung in 6 of 8 420-second trials with the do_rmdir signature;
representative NMI backtraces caught the owner spinning in
ext4_xattr_block_set(). The patched kernel completed 28 of 28 trials
without a hung-task report; the final twelve trials exercised the
reviewed overflow-safe form of the change. syzbot's patch testing also
completed without reproducing the hang.
Reported-and-tested-by: syzbot+e68dbebd9617a9250e8d@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=e68dbebd9617a9250e8d
Fixes: 65f8b80053a1 ("ext4: fix race when reusing xattr blocks")
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reported-by: syzbot+e68dbebd9617a9250e8d@syzkaller.appspotmail.com
Tested-by: syzbot+e68dbebd9617a9250e8d@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20260802065941.1726052-1-matthias.goergens@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Currently, when a new encrypted regular file is created, the call to
ext4_set_inode_flags(inode, init=true) in __ext4_new_inode() is made
before EXT4_INODE_ENCRYPT is set. As a result, it can set S_DAX if the
filesystem is mounted with "-o dax=always".
EXT4_INODE_ENCRYPT then actually gets set a bit later in
__ext4_new_inode(), when it calls fscrypt_set_context() which calls
ext4_set_context(). ext4_set_context() sets EXT4_INODE_ENCRYPT and
calls ext4_set_inode_flags(inode, init=false) to set S_ENCRYPTED too.
This was intended to clear S_DAX as well. However, this was broken by
commit 043546e46dc7 ("fs/ext4: Only change S_DAX on inode load"). This
causes data written to the file to bypass encryption, also causing
xfstests failures such as generic/548 (when "-o dax=always" is used).
Fix this by simplifying the flow by making __ext4_new_inode() set
EXT4_INODE_ENCRYPT earlier. This makes it take effect in
ext4_set_inode_flags(inode, init=true), making S_DAX never be set.
Similarly, make EXT4_STATE_MAY_INLINE_DATA never be set in the first
place on new encrypted inodes. Then it doesn't need to be cleared.
As a result of these simplifications, ext4_set_context() no longer needs
to change inode flags or state when 'handle != NULL'. Remove that too.
Reported-by: Disha Goel <disgoel@linux.ibm.com>
Reported-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Closes: https://lore.kernel.org/r/20260723085648.1500357-1-ojaswin@linux.ibm.com
Fixes: 043546e46dc7 ("fs/ext4: Only change S_DAX on inode load")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Tested-by: Disha Goel <disgoel@linux.ibm.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260730175212.36923-1-ebiggers@kernel.org
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Convert ext4 iomap_ops to the new ->iomap_next() callback. Each callback is
generated with the DEFINE_IOMAP_ITER_NEXT() macro, which wraps the
iomap_iter_next() helper to finish the previous mapping if needed and
produce the next one. No functional changes are intended.
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Baokun Li <libaokun@linux.alibaba.com>
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Link: https://patch.msgid.link/20260729192737.3190206-11-joannelkoong@gmail.com
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
The pending iomap_iter_next conversion creates performance issues for the
new simple direct I/O read fast path, because it assumes a model where
the iterator must be advanced at the end, which the direct I/O read fast
path tries to avoid.
Side step this by splitting the simple path from iomap_dio_rw, and
require the file systems to call into it explicitly, and pass only a
->begin callback. This allows to drop various checks for incompatible
features while creating a requirement for the file system to only call
the simple path for cases that it can handle.
As a side-benefit we can now inline the initial part of the simple
direct I/O read fast path and let the compiler convert the indirect call
to ->begin into a direct call.
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Fengnan Chang <changfengnan@bytedance.com>
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20260729192737.3190206-4-joannelkoong@gmail.com
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
The only time that 'false' is passed as the 'excl' arg to the ->create
inode_operation is in lookup_open() when ->atomic_open is not provided
by the parent directory.
*all* directory inode_operations which do not have ->atomic_open
completely ignore the 'excl' arg.
Therefore we don't need the 'excl' arg. Those few ->create operations
which pay attention to the arg are only ever called with a value of
'true'.
We remove that arg and change all ->create operations to behave as those
thhe arg were 'true'.
Signed-off-by: NeilBrown <neil@brown.name>
Link: https://patch.msgid.link/178290671516.27465.15984496764174914338@noble.neil.brown.name
Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
In ext4_alloc_file_blocks(), the WRITE_ZEROES path converts unwritten
extents to written in one transaction, while i_disksize is updated to
cover them only in a later transaction. A crash in between leaves
written extents beyond i_disksize on disk, which fsck will complain
about.
To fix this, add the inode to the orphan list in the same handle that
does the conversion, and remove it once i_disksize has caught up.
Also add a sanity check to ensure conversion does not extend beyond EOF.
Since ext4_alloc_file_blocks() is called from the fallocate() path,
partial allocation is safe. On partial conversion failure, advance
i_disksize only up to the boundary of successfully converted blocks, so
that orphan cleanup sees a consistent state. Document this behavior in
the function comment.
Reported-by: Jan Kara <jack@suse.cz>
Closes: https://lore.kernel.org/linux-ext4/3f6ao5amv7glbgigndtegcucgo3n34ij3lau6l3da3hgdxgn3v@ev66wv3r5umt/
Fixes: f4265b8d32c4 ("ext4: add FALLOC_FL_WRITE_ZEROES support")
Cc: stable@vger.kernel.org
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260729085918.3336221-3-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
ext4_convert_unwritten_extents() currently returns only a success or a
failure indication. A zero return means all requested blocks were
converted, and a negative value means the conversion failed. However,
some blocks may have already been converted when the function fails
partway through, and callers have no way to learn how many were done.
The WRITE_ZEROES caller in ext4_alloc_file_blocks() needs this
information to decide whether to add the inode to the orphan list before
updating i_disksize to cover the already-converted written extents, so
that a crash before i_disksize catches up can be recovered via orphan
truncation.
Switch the function to pass out the number of converted blocks through
the new output parameter @converted, which will be used by later
patches.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260729085918.3336221-2-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
In __ext4_fill_super(), s_resgid is initialized by calling
ext4_get_resuid() instead of ext4_get_resgid(), resulting in the
reserved GID being set to the same value as the reserved UID rather
than the value stored in the superblock.
Fixes: 12c84dd4d308 ("ext4: add support for 32-bit default reserved uid and gid values")
Cc: stable@vger.kernel.org
Signed-off-by: Jiazi Liu <liujiazi@amazon.com>
Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
Link: https://patch.msgid.link/20260727104103.28916-1-liujiazi@amazon.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Validate EA inode state in ext4_xattr_inode_iget() to reject corrupted
EA inodes early, before they trigger WARN_ONCE in
ext4_xattr_inode_update_ref().
When a corrupted ext4 image has an EA inode with inconsistent i_nlink
and ref_count values (e.g. i_nlink=65535), the code currently allows it
through and later hits WARN_ONCE when ref_count transitions cross the
0/1 boundary. This is better handled as an early sanity check that
returns -EFSCORRUPTED, consistent with how ext4 treats other on-disk
corruption.
Since ext4_xattr_inode_iget() resolves references from active xattr
entries, the target EA inode must be in active state (i_nlink=1,
ref_count>0). Reject any inode that does not satisfy this.
Reported-by: syzbot+76916a45d2294b551fd9@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=76916a45d2294b551fd9
Fixes: dec214d00e0d ("ext4: xattr inode deduplication")
Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260724100255.144768-1-yun.zhou@windriver.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Several racing fsyncs on ext4 in nojournal mode could result in some
fsync returning earlier than all metadata buffers were properly
persisted. Also ext4_fsync() in nojournal mode was somewhat inefficient
because it was always writing out the inode regardless whether it was
dirty or not.
Fix these issues by using new .sync_inode_metadata method which makes
sure all inode related metadata is written to disk during any
WB_SYNC_ALL writeback in nojournal mode. This also somewhat simplifies
the nojournal mode fsync handling.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-37-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Currently every ext4 inode gets mapping_metadata_bhs struct although it
is only needed when running without a journal and only for inodes where
any metadata was dirtied. Allocate mapping_metadata_bhs struct on demand
when dirtying the first metadata buffer for the inode.
Acked-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-24-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
The jbd2 layer enables NOFS mode using memalloc_nofs_{save,restore}()
while a handle is active. We need to do the same in nojournal mode so
that it is safe to remove GFP_NOFS flags while a jbd2 handle is
active.
This will require that we actually allocate a real handle, but with an
h_invalid flag set, so there is a place to put the saved memalloc
context.
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
|
|
FALLOC_FL_WRITE_ZEROES requires that all blocks in the requested range
end up as written extents with zeroed content. For unaligned edges that
were partial-zeroed in dirty unwritten or delalloc state, the buffer
is left dirty while the underlying extent may not yet be converted to
written. As a result, a subsequent SYNC write to this range would still
trigger metadata changes, which violates the semantics of WRITE_ZEROES.
Fix this by calling filemap_write_and_wait_range() for partial-zeroed
edges to flush out the zeroed data and ensure the extent conversion
is complete.
Fixes: f4265b8d32c4 ("ext4: add FALLOC_FL_WRITE_ZEROES support")
Cc: stable@vger.kernel.org
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260714080044.4038124-9-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
FALLOC_FL_WRITE_ZEROES requires that all blocks in the requested range
end up as written extents with zeroed content. For unaligned edges that
were already allocated, ext4_zero_partial_blocks() zeros them directly.
However, for unaligned edges whose underlying extent is a clean
unwritten extent or a hole, the extent type remains unwritten after
partial zeroing, which does not align with the semantics of
WRITE_ZEROES.
Therefore, when ext4_zero_partial_blocks() skips partial zeroing, it
indicates that the corresponding edges are clean unwritten extents or
holes. In this case, we need to expand the aligned allocation range
outward to cover such edges, so that ext4_alloc_file_blocks() can
correctly allocate blocks for the unaligned range. Edges that were
partial-zeroed (i.e., written or dirty) are left untouched.
Fixes: f4265b8d32c4 ("ext4: add FALLOC_FL_WRITE_ZEROES support")
Cc: stable@vger.kernel.org
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260714080044.4038124-8-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Replace the single bool did_zero output of ext4_zero_partial_blocks()
with a bitmask that records which edge (start, end, or both in the
single-block case) was actually partial-zeroed. This allows callers to
distinguish which edges have been zeroed, preparing for unaligned
FALLOC_FL_WRITE_ZEROES handling in later patches.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260714080044.4038124-7-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
ext4_load_tail_bh() returns NULL for both holes and clean unwritten
buffers, but the conditions that lead to this are not obvious from the
code alone. Document this behavior to clarify the return value, so that
readers do not mistakenly assume that only holes result in a NULL
return.
Also update the inline comment following the ext4_get_block() call to
reflect this, and note that a lookup-only get_block (without
EXT4_GET_BLOCKS_CREATE) never sets BH_Mapped for clean unwritten
extents, which is why a clean unwritten bh falls through to the
"nothing to do" path.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260714080044.4038124-6-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
In ext4_zero_range(), move the ext4_zero_partial_blocks() call, which
handles unaligned edges, into the same branch where the unaligned range
is preallocated, immediately after ext4_alloc_file_blocks(). This is
safe because there is no dependency between partial block handling and
the subsequent full block handling.
This change will be used by later patches that handle unaligned
FALLOC_FL_WRITE_ZEROES operations, which will need to check the partial
zeroed result.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260714080044.4038124-5-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
ext4_load_tail_bh() ignores the return value of ext4_get_block(), so an
I/O or allocation failure is silently discarded. buffer_mapped(bh) stays
false and the function returns NULL, which callers such as
ext4_block_do_zero_range() treat as "nothing to do" and return success.
This can mask real failures during zero-range, truncate, or punch-hole
operations, potentially exposing stale data if the block was not
actually a hole and needed zeroing. So propagate the error to the
callers.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260714080044.4038124-4-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
ext4_block_zero_eof() is called from ext4_write_checks() on every
append write beyond EOF. For inline data files, ext4_get_block()
returns -ERANGE when ext4_load_tail_bh() looks up the tail block.
However, this error is currently ignored because the return value
of ext4_get_block() in ext4_load_tail_bh() is discarded.
Before we fix ext4_load_tail_bh() to properly propagate the error,
skip the zeroing for inline data inodes to avoid unnecessary
failures or confusion.
Fixes: 3f60efd65412d ("ext4: zero post-EOF partial block before appending write")
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260714080044.4038124-3-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
ext4_load_tail_bh() returns a locked folio that callers immediately
mutate through folio_zero_range() and mark_buffer_dirty(). Use
FGP_WRITEBEGIN so that, on backing devices that require stable writes,
__filemap_get_folio() waits for writeback to finish before returning
the folio; on regular devices the wait is a no-op.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260714080044.4038124-2-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Remove the custom PLURAL() macro and use str_plural() from
string_choices.h instead.
Reviewed-by: Baokun Li <libaokun@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Joshua Crofts <joshua.crofts1@gmail.com>
Link: https://patch.msgid.link/20260713-remove-plural-macro-v2-1-424e1536ac10@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Now that ext4_put_ea_inode() handles deferred iput safely for all cases
(using iput_if_not_last + embedded llist_node), the ea_inode_array
mechanism for batching deferred iputs is redundant.
Remove:
- ext4_expand_inode_array() and ext4_xattr_inode_array_free()
- struct ext4_xattr_inode_array and EIA_INCR/EIA_MASK defines
- ea_inode_array parameter from ext4_xattr_inode_dec_ref_all(),
ext4_xattr_release_block(), and ext4_xattr_delete_inode()
- ea_inode_array variable from ext4_evict_inode()
Instead, ext4_xattr_inode_dec_ref_all() now calls ext4_put_ea_inode()
directly after processing each EA inode. This simplifies the code
by eliminating multi-layer parameter threading and removes the need
for callers to manage array lifetime.
Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
Suggested-by: Jan Kara <jack@suse.cz>
Reviewed-by: Jan Kara <jack@suse.cz>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20260710030851.2791589-5-yun.zhou@windriver.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Convert all iput() calls on EA inodes in xattr code paths to use
ext4_put_ea_inode(). This establishes a uniform rule: every EA inode
reference release in ext4 xattr code goes through ext4_put_ea_inode(),
eliminating the need to analyze each call site individually for lock
safety.
Converted sites:
- ext4_xattr_inode_get() read path
- ext4_xattr_inode_inc_ref_all() main loop and cleanup path
- ext4_xattr_inode_dec_ref_all() error paths
- ext4_xattr_inode_create() error path
- ext4_xattr_inode_cache_find() mismatch path
- ext4_xattr_inode_lookup_create() out_err
- ext4_xattr_set_entry() old_ea_inode
- ext4_xattr_block_set() new block path, cleanup, and tmp_inode
- ext4_xattr_ibody_set() error and success paths
- ext4_xattr_delete_inode() quota loop
For most of these, iput_if_not_last() will succeed (the EA inode has
other references) making the overhead a single atomic operation.
Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20260710030851.2791589-4-yun.zhou@windriver.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Calling iput() on EA inodes while holding xattr_sem or a jbd2 handle
can trigger write_inode_now() -> ext4_writepages() -> s_writepages_rwsem,
creating a lock ordering issue during mount (!SB_ACTIVE).
Add ext4_put_ea_inode() which uses iput_if_not_last() as a fast path.
If this is not the last reference, it is dropped immediately. If this
is the last reference, the inode is linked onto a per-sb lock-free llist
via i_ea_iput_node (embedded in ext4_inode_info, sharing space with the
unused xattr_sem of EA inodes via a union) and a delayed worker
(1 jiffie) performs the final iput() in a clean context. This avoids
per-iput memory allocation.
Flush points ensure all pending EA inode evictions complete before
dependent resources become unavailable:
- ext4_put_super / failed_mount9: before quota shutdown
- failed_mount_wq: before freeing xattr caches
- failed_mount3a: before freeing shrinker (journal replay case)
- ext4_sync_fs: before remount-ro, freeze, or sync completes
Initialization is placed before journal loading since fast commit
replay may trigger evictions that call ext4_put_ea_inode().
Also moves init_rwsem(xattr_sem) from init_once to ext4_alloc_inode to
handle slab object reuse after the union field has been overwritten.
Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
Suggested-by: Jan Kara <jack@suse.cz>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260710030851.2791589-3-yun.zhou@windriver.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
For casefolded encrypted directories ext4 stores an 8-byte hash trailer
after the name (EXT4_DIRENT_HASHES()), at an offset derived from
de->name_len. On the sb_no_casefold_compat_fallback() path ext4_match()
reads that trailer, but ext4_search_dir()'s by-hand pre-check only tests
de->name + de->name_len <= dlimit, which proves the name fits, not the
rounded trailer. A crafted entry whose name ends at the block boundary
passes the check while EXT4_DIRENT_HASHES(de) lands past the block end,
so ext4_match() reads out of bounds on an ordinary lookup. KASAN reports
it as a use-after-free when the page after the directory block holds a
freed object:
BUG: KASAN: use-after-free in ext4_match (fs/ext4/namei.c:1435)
Read of size 4 at addr ffff888010458000 by task exploit
Call Trace:
ext4_match (fs/ext4/namei.c:1435)
ext4_search_dir (fs/ext4/namei.c:1470)
__ext4_find_entry (fs/ext4/namei.c:1268 fs/ext4/namei.c:1632)
ext4_lookup (fs/ext4/namei.c:1703 fs/ext4/namei.c:1769)
...
filename_lookup (fs/namei.c:2842)
vfs_statx (fs/stat.c:353)
__do_sys_newfstatat (fs/stat.c:538)
do_syscall_64 (arch/x86/entry/syscall_64.c:94)
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
Require, for hash-in-dirent directories, that the whole entry including
the rounded trailer fits before calling ext4_match(). This is the same
bound ext4_check_dir_entry() already enforces via ext4_dir_rec_len(), so
no well-formed entry is rejected. The other caller, ext4_find_dest_de(),
runs ext4_check_dir_entry() first and is unaffected.
Fixes: 471fbbea7ff7 ("ext4: handle casefolding with encryption")
Reported-by: Weiming Shi <bestswngs@gmail.com>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Xiang Mei <xmei5@asu.edu>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260709184101.441348-1-xmei5@asu.edu
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
ext4_init_orphan_info() reads orphan file blocks with ext4_bread()
and stores the returned buffer_head in oi->of_binfo[i].ob_bh.
If ext4_bread() succeeds but the orphan block magic or checksum
validation fails, the function jumps to out_free. However, the old
out_free loop starts releasing buffers from i - 1, so the current
buffer_head at index i is skipped.
This leaks the buffer_head reference obtained by ext4_bread() on the
bad magic and bad checksum error paths.
Fix this by tracking the number of successfully read buffer_heads and
releasing exactly those buffer_heads on the error path.
Fixes: 02f310fcf47f ("ext4: Speedup ext4 orphan inode handling")
Signed-off-by: Guanghui Yang <3497809730@qq.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/tencent_B38798612A159E21450ECF959016371B0807@qq.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
When ext4_xattr_make_inode_space() returns -ENOSPC,
ext4_expand_extra_isize_ea() can retry the expansion with
s_min_extra_isize. If that retry succeeds by finding enough ibody free
space, control jumps directly to the shift label.
The previous -ENOSPC is still stored in error in that path, so the
function can update i_extra_isize but still return -ENOSPC to the
caller. Clear error before retrying so a successful fallback expansion
returns success.
Reproduced with an ext4 image using 1 KiB blocks, project quota support,
256-byte inodes, and min_extra_isize/want_extra_isize set to 32.
FS_IOC_FSSETXATTR failures dropped from 802 to 86 after the fix.
Fixes: 69f3a3039b0d ("ext4: introduce ITAIL helper")
Cc: stable@vger.kernel.org
Signed-off-by: Guanghui Yang <3497809730@qq.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/tencent_192F8A699EFD21126E02101131C9546F3C08@qq.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
ext4_fc_replay() stops replaying fast commit tags only when a tag
handler returns a negative error. However, ext4_fc_replay_add_range()
and ext4_fc_replay_del_range() currently return 0 from their common
exit paths even after internal failures.
This hides errors from ext4_fc_record_modified_inode(),
ext4_map_blocks(), ext4_find_extent(), ext4_ext_insert_extent(),
ext4_ext_replay_update_ex(), and ext4_ext_remove_space(). As a result,
a failed ADD_RANGE or DEL_RANGE replay can be treated as successful and
the replay code may continue with subsequent fast commit tags.
This is particularly problematic for DEL_RANGE because it may already
have marked blocks as free before ext4_ext_remove_space() fails. If the
error is swallowed, replay may continue from a partially applied range
operation.
Return the saved error from the common exit paths and make the
ERR_PTR() cases in ADD_RANGE store PTR_ERR() before jumping to out.
Fixes: 8016e29f4362 ("ext4: fast commit recovery path")
Cc: stable@vger.kernel.org
Signed-off-by: Guanghui Yang <3497809730@qq.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/tencent_E3622146846A84C75C31C7D32AC4D5AD0605@qq.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
A corrupted directory can trigger the following KASAN report when
ext4_readdir() resumes from an invalid position:
BUG: KASAN: use-after-free in __ext4_check_dir_entry+0x5ef/0x820
Read of size 2 at addr ffff88810a646000 by task repro_linear/509
Call Trace:
<TASK>
dump_stack_lvl+0x53/0x70
print_report+0xd0/0x630
kasan_report+0xce/0x100
__ext4_check_dir_entry+0x5ef/0x820
ext4_readdir+0xcde/0x2b70
iterate_dir+0x1a1/0x520
__x64_sys_getdents64+0x12b/0x220
do_syscall_64+0xf9/0x540
entry_SYSCALL_64_after_hwframe+0x77/0x7f
</TASK>
KASAN reports use-after-free because the out-of-bounds access lands in an
adjacent freed page. The directory buffer itself is still referenced.
ext4_dir_llseek() invalidates the directory cookie so that ext4_readdir()
rescans directory entries from the start of the block. The rescan checks
only the lower bound of rec_len before advancing. A corrupted rec_len can
therefore place the offset where the block has insufficient space for a
complete directory entry. The rescan itself may dereference that truncated
entry, or the main loop may pass it to __ext4_check_dir_entry(). The latter
reads de->rec_len before validating the range. For example:
block offset 0 4092 4096
|---- de1.rec_len = 4092 -----|----|
de2.inode
| de2.rec_len
^ OOB, reported as UAF
de2 starts at offset 4092 in this 4 KiB block. Its four-byte inode fits in
the block, but its rec_len starts at offset 4096 and crosses the boundary.
The minimum safe length is inode-dependent. Encrypted and casefolded
directory entries need eight additional hash bytes, while a valid metadata
checksum tail is only 12 bytes.
Cache the metadata checksum feature state and derive the minimum directory
entry length from the on-disk format. Use it to bound both the rescan and
the offset passed to the main loop. Report an offset in a truncated block
tail and skip the remainder of the block, while continuing to accept an
offset exactly at the block boundary.
Reported-by: syzbot+5322c5c260eb44d209ed@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=5322c5c260eb44d209ed
Fixes: ac27a0ec112a ("[PATCH] ext4: initial copy of files from ext3")
Signed-off-by: Yao Kai <yaokai34@huawei.com>
Reviewed-by: Zhihao Cheng <chengzhihao1@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Link: https://patch.msgid.link/20260706041313.708346-1-yaokai34@huawei.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
After implementing bitwise flags for tracking the inline data write
state in the address space fsdata parameter, the CONVERT_INLINE_DATA
state flag is left unused and can be removed.
Perform this clean-up by:
1) Deleting the CONVERT_INLINE_DATA definition from ext4.h.
2) Removing the void **fsdata argument from both the forward
declaration and the definition of the internal helper
ext4_da_convert_inline_data_to_extent().
3) Removing the void **fsdata argument from the declaration and
definition of ext4_generic_write_inline_data() and updating
the caller ext4_try_to_write_inline_data() and the internal
re-alloc retry logic accordingly.
4) Updating ext4_da_write_begin() to call
ext4_generic_write_inline_data() without the fsdata parameter.
Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Aditya Prakash Srivastava <aditya.ansh182@gmail.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260703045414.1768-2-aditya.ansh182@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Instead of checking the live inode state (ext4_has_inline_data(inode)
and ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) in the
write_end handlers, use the fsdata parameter of the address space
operations to explicitly pass down the state in which write_begin
prepared the write.
A concurrent thread (such as ext4_page_mkwrite()) can convert the
inline data to an extent between write_begin and write_end. If this
happens, the write_end handlers would previously miss the inline
write_end path and fall through to extent-based write_end logic.
However, since block buffers were never allocated in write_begin,
this resulted in NULL pointer dereferences or data loss because
folio_buffers(folio) was NULL.
Define EXT4_WRITE_DATA_INLINE (4) as a bit flag (Bit 2), treating
fsdata as bitwise flags rather than mutually exclusive enums to keep
states of the write path independent. Communicate this state via
fsdata:
1) ext4_write_begin() and ext4_da_write_begin() set the
EXT4_WRITE_DATA_INLINE bit in *fsdata via bitwise OR when an inline
write is successfully prepared.
2) On entry, ext4_write_begin() clears the EXT4_WRITE_DATA_INLINE bit
to safely handle VFS retries (where generic_perform_write() bypasses
the fsdata initialization on its retry jump).
3) The write_end handlers perform a bitwise AND to check if the
EXT4_WRITE_DATA_INLINE bit is set and invoke the inline write_end
helper accordingly.
Furthermore, during a buffered write, ext4_write_inline_data_end()
acquires the xattr lock after preparing the write. If a concurrent
page fault (ext4_page_mkwrite()) converts the inline data to an extent
after the write_end handlers check the state but before
ext4_write_inline_data_end() acquires the xattr write lock, the
subsequent check will trigger a kernel panic via
BUG_ON(!ext4_has_inline_data(inode)).
To keep git history working and bisectability clean, replace the
BUG_ON check in ext4_write_inline_data_end() with a graceful error-
handling retry path in this same commit. If the inline data is cleared
after locking the xattr, we safely release all resources (releasing
iloc.bh, unlocking/putting the folio, stopping the active journal
transaction handle) and return 0 (VFS retry) to let the generic write
path retry the operation safely.
Reported-by: syzbot+0c89d865531d053abb2d@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=0c89d865531d053abb2d
Fixes: 3fdcfb668fd7 ("ext4: add journalled write support for inline data")
Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Aditya Prakash Srivastava <aditya.ansh182@gmail.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260703045414.1768-1-aditya.ansh182@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
When a DAX write starts before EOF but extends past i_disksize,
ext4_write_checks() skips the IOCB_NOWAIT check because
iocb->ki_pos <= old_size. However, ext4_dax_write_iter() later calls
ext4_journal_start() to prepare for inode extension, which can sleep
waiting for journal space or transaction commit.
This violates NOWAIT semantics and can stall asynchronous I/O frameworks
like io_uring that rely on non-blocking behavior.
Fix this by checking IOCB_NOWAIT before calling ext4_journal_start()
in the extending write path. If NOWAIT is set and extension is needed,
return -EAGAIN so the caller can retry in blocking context.
Example scenario:
- File: i_size = 1000, i_disksize = 1000
- DAX NOWAIT write: offset = 500, count = 2000
- ext4_write_checks(): ki_pos (500) <= old_size (1000), skip NOWAIT check
- ext4_dax_write_iter(): offset + count (2500) > i_disksize (1000)
- ext4_journal_start() → may sleep → violates NOWAIT
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260618125735.4156639-1-libaokun@linux.alibaba.com?part=5
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Link: https://patch.msgid.link/20260629113827.4074335-7-libaokun@linux.alibaba.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
file_modified() passes flags=0 which drops IOCB_NOWAIT, causing
file_update_time() to sleep in ext4_journal_start() via
ext4_dirty_inode() even in non-blocking contexts.
kiocb_modified(iocb) propagates iocb->ki_flags so that
generic_update_time() correctly returns -EAGAIN when IOCB_NOWAIT
is set and ->dirty_inode could block, matching the behavior
already adopted by XFS, FUSE, and ext2.
Affected paths:
- ext4_dio_write_checks(): DIO NOWAIT write
- ext4_write_checks(): shared by buffered (rejects NOWAIT upfront)
and DAX write (supports NOWAIT)
ext4_fallocate() in extents.c is not affected as it has no kiocb.
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
Link: https://patch.msgid.link/20260629113827.4074335-6-libaokun@linux.alibaba.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
For unaligned DIO writes, the previous ext4_overwrite_io() required the
entire range to fall within a single written extent. This was overly
conservative: the DIO layer only performs partial block zeroing for the
head and tail blocks when they are partially covered by the write.
Middle blocks that are fully covered are written as whole blocks
without any zeroing, so they are safe regardless of extent state.
Therefore exclusive lock is only required when partial block zeroing
will actually happen:
- The head partial block (if any) lands on a hole or unwritten extent.
- The tail partial block (if any) lands on a hole or unwritten extent.
Middle full-cover blocks can be in any state (hole, unwritten, or
written) - block allocation under shared lock is safe per the previous
patch's analysis (inode_dio_begin + i_data_sem protection).
Replace ext4_overwrite_io() with ext4_dio_needs_zeroing(), which
directly answers the question driving the lock decision. It uses at
most two ext4_map_blocks() calls: one for the head partial block (also
catching the case where it spans through the tail), and one for the
tail partial block if not already covered.
This enables shared lock for previously-rejected scenarios such as:
- Unaligned write spanning written extent + mid-range hole + written
extent at the tail.
- Unaligned write where the partial blocks land on written extents but
the middle has unwritten extents.
Performance:
Hardware: /dev/sda (rotational disk, ~1 GB/s sustained write)
Filesystem: ext4 default mkfs
Unaligned DIO writes (14336 bytes at +512 within each 16K stripe).
Each stripe is laid out as [written][unwritten][unwritten][written],
so the head and tail partial blocks land on written extents but the
middle is unwritten. Metric: IOPS.
JOBS Before After speedup
---- -------- --------- -------
1 15,547 17,381 1.12x
2 15,910 34,172 2.15x
4 15,014 57,567 3.83x
8 15,022 81,947 5.46x
16 14,586 99,126 6.80x
32 14,047 92,519 6.59x
Wall time at JOBS=32: 149.3s (Before) -> 22.7s (After), 6.58x faster.
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
Link: https://patch.msgid.link/20260629113827.4074335-5-libaokun@linux.alibaba.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Currently, ext4_dio_write_checks() calls ext4_overwrite_io() to
determine if a write is a pure overwrite, and upgrades to exclusive
i_rwsem if not. However, ext4_overwrite_io() uses a single
ext4_map_blocks() call which only returns the first contiguous extent of
the same type. A write spanning multiple pre-allocated extents (e.g.
written + unwritten, or two physically discontiguous written extents)
produces a false negative, forcing an unnecessary exclusive lock upgrade.
After commit 5d87c7fca2c1 ("ext4: avoid starting handle when dio
writing an unwritten extent") and commit 012924f0eeef ("ext4: remove
useless ext4_iomap_overwrite_ops"), ext4_iomap_begin()'s fast path
accepts both EXT4_MAP_MAPPED and EXT4_MAP_UNWRITTEN without starting a
journal transaction. The iomap iteration naturally handles multi-extent
ranges: each call returns the mapping for the current segment, and
unwritten-to-written conversion is deferred to ext4_dio_write_end_io().
This means the common case of mixed written/unwritten extents never
reaches ext4_iomap_alloc() at all.
Even for the less common case where the range contains a hole and
ext4_iomap_alloc() is needed, exclusive i_rwsem is still unnecessary for
aligned non-extending writes:
- truncate/punch_hole are kept out: they require exclusive i_rwsem
(blocked by our shared lock during allocation), and inode_dio_begin()
keeps their inode_dio_wait() blocked until in-flight bios complete.
- i_data_sem write-lock inside ext4_map_blocks() serializes concurrent
extent tree modifications (parallel writers to the same hole).
- The journal handle is per-thread and does not require i_rwsem
exclusion.
- i_disksize and orphan list are not involved in non-extending writes.
Skip the ext4_overwrite_io() check entirely for aligned writes by
initializing overwrite to true and only calling ext4_overwrite_io() for
unaligned writes. Unaligned writes still need the extent state check
because concurrent partial block zeroing in the DIO layer requires
exclusive serialization unless the range is a pure written-extent
overwrite.
Performance:
Hardware: /dev/sda (rotational disk, ~1 GB/s sustained write)
Filesystem: ext4 default mkfs
Aligned 8K DIO writes spanning written+unwritten extent boundaries.
Each thread writes its own 1G region sequentially; the file is rebuilt
between runs so every block is written exactly once. Metric: IOPS.
JOBS Before After speedup
---- -------- --------- -------
1 42,322 43,329 1.02x
2 68,516 70,677 1.03x
4 62,489 97,072 1.55x
8 58,701 110,819 1.89x
16 58,569 116,392 1.99x
32 60,860 117,244 1.93x
Wall time at JOBS=32: 69.2s (Before) -> 35.4s (After), 1.96x faster.
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
Link: https://patch.msgid.link/20260629113827.4074335-4-libaokun@linux.alibaba.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
generic/746 started failing intermittently on ext3 (no-extent inodes).
The test triggers 'Page cache invalidation failure on direct I/O'
warnings and subsequent fsync returns -EIO. Adding a 50ms delay
between ext4_buffered_write_iter() and filemap_write_and_wait_range()
in ext4_dio_write_iter() makes the race almost always reproducible.
On no-extent inodes, DIO writes to holes cannot use unwritten extents,
so ext4_iomap_alloc() leaves m_flags=0 and ext4_map_blocks() returns 0.
The iomap layer then returns -ENOTBLK, causing fallback to buffered I/O.
The fallback path in ext4_dio_write_iter() calls
ext4_buffered_write_iter() which dirties pages, then does flush and
invalidate. However, there's an unprotected window between
ext4_buffered_write_iter() returning (with inode lock released) and
the subsequent flush+invalidate.
Concurrent async DIO completions from other threads can run
kiocb_invalidate_post_direct_write() during this window. If pages have
been re-dirtied, post-invalidation finds dirty pages and triggers the
warning, setting -EIO in the error sequence.
Consider a file with two 4k extents: [hole][written]. Thread A does
DIO to the written extent, while thread B does DIO spanning both:
kworker A (4k DIO, allocated block) kworker B (8k DIO, fallback)
----------------------------------- ----------------------------
inode_lock_shared() inode_lock_shared()
iomap_dio_rw(): iomap_dio_rw():
kiocb_invalidate_pages -> clean iomap_begin -> -ENOTBLK
submit_bio (async) dio->size = 0
inode_unlock_shared() inode_unlock_shared()
[bio pending in block layer] /* fallback: lock released */
ext4_buffered_write_iter()
inode_lock(exclusive)
generic_perform_write()
-> dirty pages [0, 8k]
inode_unlock(exclusive)
/* pages dirty, no lock */
[bio completes] filemap_write_and_wait_range()
iomap_dio_complete() -> flush dirty pages
kiocb_invalidate_post_direct_write() invalidate_mapping_pages()
invalidate_inode_pages2_range()
-> finds dirty page!
-> dio_warn_stale_pagecache()
-> errseq_set(-EIO)
This issue can be triggered through normal I/O paths, not just
intentionally overlapping DIO writes from userspace. For example,
generic/746 uses a loop device where multiple kworkers issue concurrent
I/O to the backing file. Additionally, when block_size < folio_size,
non-overlapping DIO writes that share a large folio can also trigger
the race.
Add inode_dio_wait() in ext4_buffered_write_iter() before
ext4_write_checks() to drain all in-flight DIO. This ensures that
all DIO clears existing pages before submitting IO (via
kiocb_invalidate_pages()), all BIO waits for all DIO to complete
(via inode_dio_wait()), and ext4_write_checks() observes the inode
size after all completed DIO so that ext4_block_zero_eof() does not
race with in-flight DIO, thus eliminating the race.
Fixes: 378f32bab371 ("ext4: introduce direct I/O write using iomap infrastructure")
Suggested-by: Zhang Yi <yi.zhang@huawei.com>
Link: https://patch.msgid.link/d1adcf7c-c276-458d-9cac-68a4410f7626@gmail.com
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
Link: https://patch.msgid.link/20260629113827.4074335-3-libaokun@linux.alibaba.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Block allocation requires journal access which may sleep, violating
NOWAIT semantics. Return -EAGAIN early when IOMAP_NOWAIT is set,
allowing the caller to retry without the NOWAIT constraint.
This ensures that write paths using IOMAP_NOWAIT (e.g., DIO with
RWF_NOWAIT) will not block on journal operations when blocks need
to be allocated.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260611163441.2431805-1-libaokun@linux.alibaba.com?part=1
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
Link: https://patch.msgid.link/20260629113827.4074335-2-libaokun@linux.alibaba.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
In data=journal mode, the writeback thread can hit the
WARN_ON_ONCE(sb_rdonly(sb)) in ext4_journal_check_start() while the
superblock is being remounted read-only during reboot:
Workqueue: writeback wb_workfn (flush-253:0)
RIP: 0010:ext4_journal_check_start+0x8b/0xd0
Call Trace:
__ext4_journal_start_sb+0x3c/0x1e0
mpage_prepare_extent_to_map+0x4af/0x580
ext4_do_writepages+0x3c0/0x1080
ext4_writepages+0xc8/0x1a0
do_writepages+0xc4/0x180
__writeback_single_inode+0x45/0x2f0
writeback_sb_inodes+0x26b/0x5d0
__writeback_inodes_wb+0x54/0x100
wb_writeback+0x1ac/0x320
wb_workfn+0x394/0x470
And followed by the warning:
EXT4-fs warning (device vda1): ext4_evict_inode:195: inode #6263:
comm (sd-umount): data will be lost
This issue is not reproduced every time, but frequently.
The reproduction step is to create a VM with 8 CPUs, 16G memory and
setup data=journal:
sudo tune2fs -o journal_data /dev/vda1
Run fio:
rm -f fiotest
fio --name=fiotest --rw=randwrite --bs=4k --runtime=6 --ioengine=libaio
--iodepth=256 --numjobs=8 --filename=fiotest --filesize=30G
--group_reporting
Reboot the VM, and check the console output from:
virsh console testvm
But there is no dirty inode, folio_clear_dirty_for_io clears PG_dirty
but leaves tags PAGECACHE_TAG_DIRTY and PAGECACHE_TAG_TOWRITE set which
are only cleared by __folio_start_writeback.
In data=journal mode, jbd2 checkpoints the journalled data to its final
location and clears its own dirty flag without touching folio PG_dirty
or xarray dirty flags.
The commit f4a2b42e7891 ("ext4: fix stale xarray tags after writeback")
fixes when PG_dirty is still set but there is no dirty page.
Another case is PG_dirty is cleared, but PAGECACHE_TAG_DIRTY and
PAGECACHE_TAG_TOWRITE is still set. In this case, writeback thread
checks clean folio and skips it in mpage_prepare_extent_to_map:
if (!folio_test_dirty(folio) ||
...
folio_unlcok(folio);
continue
And never reaches ext4_bio_write_folio where the commit f4a2b42e7891
clears the stale xarray tags. Print debug logs after the filesystem
is remounted read-only:
writepages RDONLY nrpages=2048 dirtytag=1 wbtag=0 towrite=1 sync=0
And all folios are actually clean:
folio idx=3 dirty=0 wb=0 checked=0 dirtybuf=0 jbddirty=0 mapped=1
...
We need to clear the xarray stale tags for such clean folios by
cycling them through writeback in the skip path, the same way
f4a2b42e7891 does in ext4_bio_write_folio.
Fixes: dff4ac75eeee ("ext4: move keep_towrite handling to ext4_bio_write_page()")
Signed-off-by: Gerald Yang <gerald.yang@canonical.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260625160127.162272-1-gerald.yang@canonical.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Syzbot/stress-ng reported an ABBA deadlock in ext4 when exercising
concurrent xattr workloads (using the ea_inode mount/format option).
The deadlock occurs between the running transaction and the eviction
thread:
- Task 1 (stress-ng): Holds a reference to a shared mbcache_entry (ce)
and calls ext4_xattr_inode_cache_find() -> ext4_iget() to retrieve
the corresponding EA inode. Since the EA inode is currently being
evicted, ext4_iget() blocks in __wait_on_freeing_inode() waiting for
eviction to complete.
- Task 2 (eviction thread): Currently evicting the same EA inode in
ext4_evict_ea_inode(). It calls mb_cache_entry_wait_unused(oe) which
blocks waiting for Task 1 to release the reference to the mbcache_entry.
To break this deadlock, implement a new ext4_iget() configuration flag
named EXT4_IGET_NOWAIT. When set, perform a non-blocking lookup of the
inode via VFS's find_inode_nowait() API.
If the inode is currently being evicted (marked with I_FREEING or
I_WILL_FREE) or created (I_CREATING), or if it is not present in the VFS
inode cache (cache miss), simply skip it (returning -ENOENT) rather than
waiting for eviction/creation to complete, breaking the ABBA cycle.
Since we return -ENOENT immediately on a cache miss, we never attempt to
allocate a new inode or call iget_locked(), completely eliminating any
TOCTOU race window.
If the returned inode is I_NEW, wait for its initialization to clear via
wait_on_new_inode(). If initialization fails and the inode is unhashed
during wait_on_new_inode() waking up (e.g., due to an I/O read error in
another thread), safely drop the reference and return -ENOENT. This
unhashed check is executed unconditionally on all cache-hit pathways to
properly handle concurrent initialization failures.
Finally, standard validation checks (including is_bad_inode,
EXT4_EA_INODE_FL, file_acl, and xattr flags) are executed as normal inside
check_igot_inode() to fully guarantee VFS-layer safety.
In ext4_xattr_inode_cache_find(), invoke ext4_iget() with the new
EXT4_IGET_NOWAIT flag to perform the non-blocking cache search.
Suggested-by: Jan Kara <jack@suse.cz>
Reported-by: Colin Ian King <colin.i.king@gmail.com>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219283
Fixes: 0a46ef234756 ("ext4: do not create EA inode under buffer lock")
Signed-off-by: Aditya Prakash Srivastava <aditya.ansh182@gmail.com>
Tested-by: Colin Ian King <colin.i.king@gmail.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260626054821.1729-1-aditya.ansh182@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|