generic_write_checks() in f2fs_write_checks() can adjust iocb->ki_pos
for append writes and truncate the iterator to limit the number of bytes
to write.
In f2fs_file_write_iter(), the pinned-file overwrite check currently
uses the position and count saved before f2fs_write_checks(), so it
can check a range different from the actual write range.
The forced buffered I/O cleanup also uses orig_pos saved before
f2fs_write_checks(). For O_APPEND writes, this can make the cleanup
flush and invalidate the wrong page cache range.
Move the pinned-file overwrite check after f2fs_write_checks() and use
the adjusted iocb->ki_pos and iov_iter_count(from). Also save the
adjusted write position and use it for the forced buffered I/O cleanup.
Fixes: 3fdd89b452 ("f2fs: prevent writing without fallocate() for pinned files")
Fixes: 92318f20d7 ("f2fs: preserve direct write semantics when buffering is forced")
Signed-off-by: Seongjae Jeong <jsjlee1020@gmail.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
F2FS writes long symlink data with page_symlink() and then flushes the
symlink mapping to reduce the chance of exposing a broken symlink.
That flush result is currently ignored. If the writeback fails, symlink()
still returns success even though the symlink is not durable and the same
operation can already surface -EIO through syncfs().
Return the writeback error to userspace and skip the dirsync flush once the
symlink data flush has failed.
Fixes: d0cae97cb6 ("f2fs: flush symlink path to avoid broken symlink after POR")
Cc: stable@kernel.org
Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
In f2fs_rename() and f2fs_unlink(), directly returning -EPERM when
encountering a device aliasing file bypasses the cleanup path.
Fix this by setting err to -EPERM and jumping to the proper cleanup
labels (out_dir and out) instead of returning immediately.
Reported-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
Signed-off-by: Daeho Jeong <daehojeong@google.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Currently, ino entries for APPEND_INO, UPDATE_INO, TRANS_DIR_INO, and
XATTR_DIR_INO allocate a 'struct ino_entry' slab object and attach it to
both a list and a radix tree solely for existence checks via
f2fs_exist_written_data().
Since these ino types only track binary existence status, we can embed
the information directly into radix tree value entries as a bitmap:
- The Linux radix tree/XArray supports in-place value entries via
xa_mk_value() / xa_to_value(), which tag the least significant bit
to store an unallocated integer value of BITS_PER_XA_VALUE bits
(BITS_PER_LONG - 1) directly in the slot pointer.
- For each inode, (ino / BITS_PER_XA_VALUE) serves as the radix tree
slot index, and (ino % BITS_PER_XA_VALUE) is used as the bit offset
within the slot's bitmap.
For example, when tracking ino = 7:
- Before: Allocate a 'struct ino_entry' ({ .ino = 7 }), insert its
pointer into the radix tree at index = 7, and link it to im->ino_list.
- After: Compute slot_index = 7 / BITS_PER_XA_VALUE (index 0) and
bit_offset = 7 % BITS_PER_XA_VALUE (bit 7), then set bit 7 in the
value entry via xa_mk_value(bitmap) at index 0, without allocating
a slab object or linking to a list.
Additionally:
- In-place slot updates are performed via radix_tree_replace_slot(), and
slots are deleted with radix_tree_delete() once the bitmap is zeroed.
- Reorder the ino list enum so ORPHAN_INO and FLUSH_INO (which still
require struct ino_entry and list traversal) remain separated, while
bitmap-based trees are torn down using xa_destroy().
This eliminates 'struct ino_entry' slab allocations and linked-list
tracking for these ino types, significantly reducing memory consumption.
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
From: Zhan Xusheng <zhanxusheng@xiaomi.com>
Commit 4275b59673 ("f2fs: fix to round down start offset of fallocate
for pin file") moved the allocation loop's start down to a section
boundary, but the error path still converts @expanded against @pg_start,
which holds the unrounded start.
@pg_start exists for that conversion: commit 88f2cfc5fa ("f2fs: fix to
update last i_size if fallocate partially succeeds") added it as an
immutable base because map.m_lblk moves every round. Each round now maps
exactly sec_blks blocks starting from rounddown(pg_start, sec_blks), so
pg_start + expanded overshoots the last allocated block by
pg_start % sec_blks, and a partial failure leaves i_size covering a tail
that was never allocated. Nothing corrects that afterwards either, since
file_dont_truncate() has already cleared FADVISE_TRUNC_BIT.
It needs a start offset that is not section aligned plus a fallocate that
hits ENOSPC partway, so the error path runs with expanded > 0. On an
80 MiB image with 2 MiB sections:
truncate -s 80M img
mkfs.f2fs -s 1 -f img
mount -o loop img /mnt
touch /mnt/pinned
f2fs_io pinfile set /mnt/pinned
# 2093056 = block 511, so pg_start % sec_blks = 511
f2fs_io fallocate 0 2093056 536870912 /mnt/pinned
stat -c %s /mnt/pinned
filefrag -v /mnt/pinned
The last extent ends at block 10737 either way. Before, i_size is
46075904, block 11249, so 511 blocks of it were never allocated, and
filefrag does not mark the last extent eof. After, i_size is 43982848,
block 10738, and eof is back. A kernel from before that commit also
shows no overshoot.
Keep @pg_start pointing at where allocation actually begins.
Fixes: 4275b59673 ("f2fs: fix to round down start offset of fallocate for pin file")
Cc: stable@vger.kernel.org
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
In free_segment_range(), the curseg evacuation loop only iterates up to
NR_CURSEG_PERSIST_TYPE (0..5), missing non-persistent in-memory curseg
types such as CURSEG_COLD_DATA_PINNED and CURSEG_ALL_DATA_ATGC.
Even though these in-memory curseg types are not saved in the on-disk
checkpoint header, they still occupy active physical segments at runtime.
If an active in-memory curseg happens to be allocated within the segment
range being truncated during filesystem shrink, failing to evacuate it
will cause subsequent writes to the curseg attempting out-of-bounds I/O
on the truncated storage range.
Fix this by expanding the curseg evacuation loop upper bound to
NR_CURSEG_TYPE to ensure all active curseg types are safely migrated
out of the target range.
Fixes: d0b9e42ab6 ("f2fs: introduce inmem curseg")
Cc: stable@vger.kernel.org
Signed-off-by: Daeho Jeong <daehojeong@google.com>
Signed-off-by: Sunmin Jeong <s_min.jeong@samsung.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
When free_segment_range() fails in f2fs_resize_fs(), no on-disk
superblock or filesystem metadata has been modified yet, and
free_segment_range() safely restores all in-memory counters before
returning.
However, the current error recovery path unconditionally sets the
SBI_NEED_FSCK flag and prints a scary error message on any error,
forcing an unnecessary and time-consuming fsck.f2fs repair on the
subsequent mount/reboot.
Fix this by separating the error recovery path with a dedicated
recover_user_blocks label to bypass setting SBI_NEED_FSCK on
free_segment_range() failures.
Signed-off-by: Daeho Jeong <daehojeong@google.com>
Signed-off-by: Sunmin Jeong <s_min.jeong@samsung.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
In f2fs_allocate_pinning_section(), we will hold gc_lock before calling
f2fs_gc_range() to migrate section in conventional zone, we may suffer
worse case because we may need to traverse and migrate multiple sections
if we failed to move blocks in section due to lot of reasons: ENOMEM,
fail to migrate block of pinfile, racing on i_gc_rwsem.
To avoid hold gc_lock for long time to block checkpoint, let's hold
the lock and only try to migrate one section.
Cc: Daeho Jeong <daehojeong@google.com>
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
generic/794 4s ... - output mismatch (see /share/git/fstests/results//generic/794.out.bad)
--- tests/generic/794.out 2026-06-12 08:46:32.766426241 +0800
+++ /share/git/fstests/results//generic/794.out.bad 2026-07-05 18:32:55.000000000 +0800
@@ -1,4 +1,16 @@
QA output created by 794
append_write
+FAIL: non-zero data in gap [4080,4096) after shutdown+remount
+000000 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a >ZZZZZZZZZZZZZZZZ<
+*
+001000
truncate_up
...
(Run 'diff -u /share/git/fstests/tests/generic/794.out /share/git/fstests/results//generic/794.out.bad' to see the entire diff)
Ran: generic/794
Failures: generic/794
Failed 1 of 1 tests
Steps of generic/794:
1. write 4096 bytes to file w/ 0x5a
2. use fiemap to get PBA of first block in file
3. truncate file to 4080
4. umount; write 4096 bytes to file w/ 0x5a directly via PBA; mount
5. extend filesize via
a) append 4096 from offset 4096, or
b) truncate 8192, or
c) fallocate 4096 from offset 4096
6. verify the gap is zeroed in memory [4080,4096)
7. sync range 4096 from offset 4096; shutdown -f (flush meta before shutdown)
8. umount; mount; verify [4080,4096) is zeroed or not.
When extending file size (e.g. via truncate, fallocate, or write) across an
unaligned EOF boundary, we need to ensure that post-EOF data in the partial
page is zeroed out in pagecache and marked dirty, then writeback the cache to
persist zeroed data before committing inode w/ updated i_size.
This help to prevent stale disk data beyond the previous EOF from being exposed
after remounting or crash recovery.
Since f2fs is a LFS filesystem, we only support direct write via PBA in pinfile,
and pinfile has section-aligned filesize, so in Android, there should no problem,
but for other usage in different environment, let's fix this w/ fsync_mode=strict
mount option.
Cc: stable@kernel.org
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Otherwise, it will drop one more page after new_size which is not
necessary.
Cc: stable@kernel.org
Fixes: ba8dac350f ("f2fs: fix to zero post-eof page")
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
The f2fs_evict_inode() can be called during the direct reclaim path, but
__add_ino_entry requires allocating some memory. Since we don't need to
do that in that context, let's migrate it in other workqueue context.
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
1. f2fs_pre_evict_inode()
: drop all in-memory structures
2. f2fs_delete_inode()
: truncate inode blocks, if it was unlinked.
3. f2fs_post_evict_inode()
: update inode records for future access
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This patch adds a dynamic management feature to the existing device
aliasing functionality. It allows users to dynamically reserve or
release specific devices from the filesystem's free pool at runtime
through new ioctls.
To support this, three new ioctls are introduced:
- F2FS_IOC_RESERVE_DEV_ALIAS: This reclaims the space occupied by a
device aliasing file. It first performs a capacity check, resets GC
victim information for the target range, marks the segments as in-use
to prevent new allocations, and then triggers GC to migrate existing
valid data out of the range. Finally, it reserves these blocks in the
SIT to effectively exclude the device from the usable capacity.
- F2FS_IOC_RELEASE_DEV_ALIAS: This releases the reserved space of a
previously reserved device aliasing file. It truncates the blocks
associated with the file, which makes them available for general
filesystem allocation again.
- F2FS_IOC_GET_DEV_ALIAS_STATUS: This retrieves the current aliasing
status of a device aliasing file, returning whether the file is
released (inactive alias) or reserved (active alias, with blocks
fully allocated on the device).
Signed-off-by: Daeho Jeong <daehojeong@google.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Otherwise in f2fs_sanity_check_node_footer(), it will check the
same nid incorrectly.
Cc: stable@kernel.org
Fixes: 0a736109c9 ("f2fs: fix to do sanity check on node footer in __write_node_folio()")
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
On a multi-device setup, submit_flush_wait() walked the dirty devices
in order and aborted the whole loop on the first device whose flush
failed, leaving the remaining dirty devices un-flushed. Each device
still needs its own data made durable, so a failure on one device must
not skip the others. It also waited for one device's flush to complete
before issuing the next, even though the devices have independent
flush queues and could be flushed concurrently.
Flush every dirty device best-effort and in parallel instead: build
one PREFLUSH bio per dirty device, submit them all, then wait for
every completion, returning the first error seen (0 if all succeed).
This bounds the flush window by the slowest device rather than the sum
of all of them. No caller depends on the previous early-abort
behaviour -- fsync only checks whether the return value is zero
(fs/f2fs/file.c). The checkpoint path (f2fs_flush_device_cache) is
unaffected; this only touches the fsync flush path.
The per-device bio/completion array is small and bounded (at most
MAX_DEVICES entries), so allocate it with __GFP_NOFAIL rather than
keeping a separate serial fallback path for allocation failure.
Signed-off-by: Yonggil Song <yonggil.song@samsung.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
So that we can know in which path we may missed to account the
reference correclty: normal path or error handling path.
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
If node block is corrupted due to chksum mismatch or inconsistent
footer info, it needs to drop clear flag of node folio, in order
to persist inconsistent node data to storage.
Cc: stable@kernel.org
Fixes: b42b179bda ("f2fs: fix to do checksum even if inode page is uptodate")
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
In f2fs_shrink_scan(), let's check if we have already shrinked enough
number of memory before calling f2fs_shrink_read_extent_tree().
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
In __allocate_data_block(), when allocating a new data block
(dn->data_blkaddr == NULL_ADDR), inc_valid_block_count() is
called first to increment total_valid_block_count and i_blocks.
If the subsequent f2fs_allocate_data_block() fails, the function
returns the error directly without rolling back the
already-incremented block counts, causing a permanent leak.
Fix this by calling dec_valid_block_count() to undo the
increment before returning the error. The condition
old_blkaddr == NULL_ADDR precisely identifies the case where
inc_valid_block_count() was called.
Fixes: 7d009e048d ("f2fs: fix to handle segment allocation failure correctly")
Cc: <stable@vger.kernel.org>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Chen Changcheng <chenchangcheng@kylinos.cn>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
The sysfs store path already takes s_umount for GC thread control
entries, and ckpt_thread_ioprio is covered as well.
critical_task_priority also updates checkpoint or GC kthread scheduling
state, but it is not covered by that serialization. It can race with
remount or teardown paths that are stopping those threads.
Protect critical_task_priority sysfs writes with s_umount too.
Fixes: 52190933c3 ("f2fs: sysfs: introduce critical_task_priority")
Cc: stable@kernel.org
Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
checkpoint_merge can be enabled even when no checkpoint merge thread is
running. A read-only mount is one case: f2fs does not start
f2fs_issue_ckpt there, but ckpt_thread_ioprio is still writable through
sysfs.
The ckpt_thread_ioprio store path updates the saved ioprio value and,
when checkpoint_merge is enabled, calls set_task_ioprio() for the
checkpoint thread. If cprc->f2fs_issue_ckpt is NULL, that dereferences a
NULL task pointer.
Protect ckpt_thread_ioprio sysfs writes with s_umount as well, so the
checkpoint thread cannot disappear under the store path while updating
its ioprio.
Fixes: e659206617 ("f2fs: add ckpt_thread_ioprio sysfs node")
Cc: stable@kernel.org
Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
The bio_for_each_segment_all() loop can take more than 10 ms for a large
bio on an ARM little core. This is too much for interrupt context. Hence
perform the write bio completion work asynchronously if a bio is large and
if f2fs_write_end_io() is called from atomic context. This patch reduces
the time spent in f2fs_write_end_io() from about 10 ms to about 150
microseconds on an Arm Cortex-A520 core if the max_atc_write_bio_size
parameter is changed to 16384.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Recovery uses raw_inode->i_namelen directly when rebuilding fsynced
dentries. A zero-length name uses no dentry slots, so recovery can
report success without recreating the dentry.
Treat zero-length and oversized recovered names as corruption, mark
NEED_FSCK, and stop recovery with -EFSCORRUPTED.
Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
The only callers of curseg_segno() and curseg_alloc_type() were removed by
commit 5a4fed7cd9 ("f2fs: simplify do_checkpoint"); both helpers have
been unused since then.
Being static inline functions they do not trigger -Wunused-function, so
the dead code has gone unnoticed. Remove them. No functional change.
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Xfstests generic/547 sometimes fail with mismatched directory metadata
before and after a power failure. This happens because when a directory
entry is added, renamed, or deleted, its mtime and ctime are updated and
the inode is marked dirty via
f2fs_mark_inode_dirty_sync(dir, sync=false). The sync=false flag means
the dirty inode is not added to the global DIRTY_META list. Therefore,
subsequent checkpoints skip flushing these updated directory blocks,
causing directory timestamps to revert to stale values after a sudden
power failure.
Address this by changing the dirtying parameter to sync=true during
directory entry mutations and renames. This forces F2FS to immediately
queue the updated directory blocks on the global DIRTY_META list,
ensuring timestamps are committed to checkpoints.
Fixes: 7c45729a4d ("f2fs: keep dirty inodes selectively for checkpoint")
Cc: stable@vger.kernel.org
Signed-off-by: Joanne Chang <joannechien@google.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
The f2fs_iostat tracepoint stores the per-order read folio counts in a
fixed-size array and prints a fixed number of buckets, both hardcoded to
11. The sysfs iostat accounting array is instead sized by NR_PAGE_ORDERS
(= MAX_PAGE_ORDER + 1), which is not always 11:
arm64 16K pages -> MAX_PAGE_ORDER 11 -> NR_PAGE_ORDERS 12
arm64 64K pages -> MAX_PAGE_ORDER 13 -> NR_PAGE_ORDERS 14
f2fs enables large folios for immutable, non-compressed files, and the
read folio order is bounded by MAX_PAGECACHE_ORDER, i.e.
min(MAX_XAS_ORDER, PREFERRED_MAX_PAGECACHE_ORDER). With THP enabled this
reaches order 11 on 16K/64K base-page kernels (MAX_XAS_ORDER caps it at
11). So an order-11 read folio is possible there and is accounted into
index 11 of the array.
On those configurations the sysfs file reports the order-11 count
correctly, but the tracepoint silently drops it: the memcpy is capped at
min(NR_PAGE_ORDERS, 11), so index 11 is never copied and the trace
disagrees with sysfs. There is no memory-safety issue, only the order-11
bucket missing from the trace; 4K-page kernels (NR_PAGE_ORDERS == 11,
max order <= 9) are unaffected.
Size the array and the printed buckets by a ceiling that covers the
largest possible NR_PAGE_ORDERS (14) with headroom, and add a
BUILD_BUG_ON() so any future growth of NR_PAGE_ORDERS fails the build
loudly instead of silently truncating again. The human-readable
"order=count" output is preserved.
Fixes: cb8ff3ead9 ("f2fs: add page-order information for large folio reads in iostat")
Cc: stable@vger.kernel.org
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
F2FS_IOC_MOVE_RANGE treats a zero length as a request to move data
from pos_in to EOF. However, the same-file overlap check runs before
that expansion, so a request with len == 0 bypasses the overlap
rejection added for same-file moves.
For example, with a four-block file, moving from block 0 to block 1
with len == 0 is accepted by the old check because pos_in + len is
still pos_in at that point. The code then expands len to cover the
rest of the file and calls __exchange_data_block() on overlapping
source and destination ranges in the same inode, which is the
data-corruption case the overlap check was meant to reject.
Move the overlap check after the source range has been validated and
len == 0 has been expanded, so it sees the effective length. This is a
no-op for non-zero len (the value is unchanged there) and keeps the
existing early return for identical positions.
Fixes: d95fd91c1a ("f2fs: exclude special cases for f2fs_move_file_range")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-fable-5
Signed-off-by: Hao-Qun Huang <alvinhuang0603@gmail.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
f2fs_collapse_range() writes back pages moved by f2fs_do_collapse(),
but ignores the return value. If writeback fails, the ioctl can still
truncate page cache, shrink blocks, and report success.
Return the error before truncating page cache or updating the file size.
Fixes: b4ace33703 ("f2fs: support FALLOC_FL_COLLAPSE_RANGE")
Cc: stable@kernel.org
Assisted-by: Codex:gpt-5.5
Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
redirty_blocks() pins folios with read_cache_folio() and then walks the
same range again with filemap_lock_folio() to redirty them and drop the
references it took.
Commit 5951fee46b ("f2fs: Use a folio in redirty_blocks()") changed
the second pass to a do/while loop. If read_cache_folio() fails before
anything is pinned, page_idx does not advance but the cleanup loop still
runs once.
If readahead has already populated the failed folio in page cache, that
extra iteration finds it and folio_put_refs(folio, 2) drops one
reference too many. Later drop_caches or reclaim can then report
"BUG: Bad page state".
Only redirty the range that was pinned successfully.
Fixes: 5951fee46b ("f2fs: Use a folio in redirty_blocks()")
Cc: stable@kernel.org
Assisted-by: Codex:gpt-5.5
Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
F2FS stores recovery filenames as a length plus a fixed-size i_name
buffer. The buffer is not NUL-terminated, but recover_inode() and
recover_dentry() print it with %s.
For a 255-byte filename, recovery logging can read past i_name into the
following raw inode fields.
Print the name with a precision bounded by i_namelen and F2FS_NAME_LEN.
Fixes: f356fe0cba ("f2fs: add debug msgs in the recovery routine")
Cc: stable@kernel.org
Assisted-by: Codex:gpt-5.5
Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
F2FS_IOC_MOVE_RANGE checks the source range, but not the destination end
before updating i_size. A source hole can expose this: __clone_blkaddrs()
skips NULL_ADDR entries and returns success, so the caller can still extend
the destination inode with unchecked pos_out + len.
Reject destination overflow and use inode_newsize_ok() before extending
the destination inode.
Fixes: 4dd6f977fc ("f2fs: support an ioctl to move a range of data blocks")
Cc: stable@kernel.org
Assisted-by: Codex:gpt-5.5
Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
f2fs_xattr_advise_set() calls inode_owner_or_capable() with &nop_mnt_idmap
before allowing the "system.advise" xattr to be set, instead of the idmap
that the VFS passes to the ->set() handler.
f2fs supports idmapped mounts, so on such a mount this checks the caller's
fsuid against the unmapped on-disk owner rather than the mapped owner: the
actual owner can be wrongly denied with -EPERM and an unrelated caller
wrongly allowed. Pass the handler's idmap instead.
Fixes: 01beba7957 ("fs: port inode_owner_or_capable() to mnt_idmap")
Cc: stable@vger.kernel.org
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Acked-by: Christian Brauner (Amutable) <braurg>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
find_in_level() gets a dentry folio with f2fs_find_data_folio() before
calling find_in_block(). If find_in_block() returns an error, the
function stores the error in res_folio and breaks out of the loop without
dropping the dentry folio.
This leaks the folio reference on the find_in_block() error path. Drop
the dentry folio before returning the error to the caller.
Fixes: 7ad08a58bf ("f2fs: Handle casefolding with Encryption")
Cc: stable@vger.kernel.org
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Guanghui Yang <3497809730@qq.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Our v6.18 based Android system is continuely suffering livelock and bad
page stat as shown in[1] which related to broken xarray slot status. By
investigating big folio operations within f2fs, we find below races and
fix it by get the nr_pages before drop the refcount and folio_lock.
f2fs_get_read_data_folio() calls f2fs_folio_put() before
folio_nr_pages() when invalidating a large folio from the page cache.
That unlocks the folio and drops the caller reference, leaving a window
where a concurrent truncate or folio split can shrink the compound folio
or free it before the invalidate range is computed. An undersized range
then leaves split sub-folios in mapping->i_pages, which can later
interact badly with truncate and reclaim (stale xarray entries and bad
page state when folio->mapping no longer matches the mapping being
truncated).
[1]
PID: 2594 TASK: ffffff8169b81580 CPU: 7 COMMAND: "Thread-3"
#0 [ffffffc08ef2b8a0] xas_load at ffffffe52d1f42a4
#1 [ffffffc08ef2b900] find_get_entries at ffffffe52c185798
#2 [ffffffc08ef2bb60] truncate_inode_pages_range at ffffffe52c19e83c
#3 [ffffffc08ef2bbc0] truncate_inode_pages_final at ffffffe52c19ec2c
#4 [ffffffc08ef2bc20] f2fs_evict_inode at ffffffe52c4c8400
#5 [ffffffc08ef2bcc0] evict at ffffffe52c2de9f4
#6 [ffffffc08ef2bd00] iput at ffffffe52c2db1b4
#7 [ffffffc08ef2bd30] dentry_unlink_inode at ffffffe52c2d7204
#8 [ffffffc08ef2bd50] __dentry_kill at ffffffe52c2d3dcc
#9 [ffffffc08ef2bd80] dput at ffffffe52c2d3c3c
#10 [ffffffc08ef2bda0] __fput at ffffffe52c2b0a7c
#11 [ffffffc08ef2bde0] ____fput at ffffffe52c2b1034
#12 [ffffffc08ef2bdf0] task_work_run at ffffffe52beea200
#13 [ffffffc08ef2be20] exit_to_user_mode_loop at ffffffe52bfbc17c
#14 [ffffffc08ef2be80] el0_svc at ffffffe52d1f8e54
#15 [ffffffc08ef2beb0] el0t_64_sync_handler at ffffffe52d1f8d10
Cc: stable@kernel.org
Fixes: 05e65c14ea ("f2fs: support large folio for immutable non-compressed case")
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Zhaoyang Huang <zhaoyang.huang@unisoc.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Blocks of pinfile may not aligned to section size due to wrong use
on pinfile, result in heavy overhead of GC, let avoid this by
adding additional check condition in f2fs_setattr().
- truncate -s 8mb pinfile
: random checkpoint may persist filesize w/ inode
- fallocate -o 0 -l 8mb pinfile
- f2fs_fallocate
- f2fs_expand_inode_data
- f2fs_allocate_pinning_section
- f2fs_map_blocks
- f2fs_map_lock
- __allocate_data_block
- file_need_truncate
: w/ FADVISE_TRUNC_BIT, we can expect unaligned mapping can be
truncated while open() if f2fs is not umount abnormally
- f2fs_map_unlock
: following f2fs checkpoint and sudden power-cut
- mount
- open pinfile
- f2fs_file_open
- finish_preallocate_blocks
- truncate_setsize
: filesize is 8mb
- f2fs_truncate
: can only truncate block outside filesize, rather than truncating
unaligned blocks inside filesize
Fixes: f5a53edcf0 ("f2fs: support aligned pinned file")
Cc: stable@kernel.org
Cc: Daeho Jeong <daehojeong@google.com>
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Commit 02117b8ae9 ("f2fs: Set GF_NOFS in read_cache_page_gfp while doing
f2fs_quota_read") adds GFP_NOFS in f2fs_quota_read() to avoid below deadlock:
- do_sys_open
- vfs_open
- dquot_file_open
- dquot_initialize
- dqget
- dquot_acquire
: locks &dqopt->dqio_mutex (VFS Quota Mutex)
- qtree_read_dquot
- f2fs_quota_read
- read_mapping_page (GFP_KERNEL / allows GFP_FS)
- __alloc_pages_nodemask
- try_to_free_pages (Direct Reclaim)
- prune_icache_sb
- evict
- f2fs_evict_inode
- dquot_drop
- dqput
- dquot_commit
: tries to lock &dqopt->dqio_mutex again
==> DEADLOCK (waiting for itself)
As Jan Kara mentioned, quota system has fixed this issue w/ commit
537e11cdc7 ("quota: Prevent memory allocation recursion while holding
dq_lock"), so this GFP_NOFS flag should be relic, let's use GFP_KERNEL
instead.
Cc: Jan Kara <jack@suse.cz>
Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Chao Yu <chao@kernel.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This patch proposes to drop FGP_NOFS from f2fs_filemap_get_folio()
in f2fs_write_begin(), I don't see there is potential deadlock issue
when __filemap_get_folio() calling into filesystem reclaim interfaces,
e.g. .writepages, evict_inode, shrinker.
Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Pull misc fixes from Andrew Morton:
"13 hotfixes. All are cc:stable. 11 are for MM. All are singletons -
please see the changelogs for details"
* tag 'mm-hotfixes-stable-2026-07-27-14-18' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
fs/proc/task_mmu: fix PAGEMAP_SCAN written state for PMD holes
mm/hugetlb: fix list corruption in allocate_file_region_entries()
mm: mglru: fix stale batch updates after memcg reparenting
selftest: fix headers in fclog.c
ocfs2: fix boundary check in ocfs2_check_dir_entry() to use buffer offset
mm/percpu-km: fix bitmap overflow and accounting in pcpu_create_chunk()
mm/util: don't read __page_2 for order-1 folios in snapshot_page()
mm/hugetlb: fix swap entry corruption when clearing uffd-wp at fork()
mm: migrate_device: fix pte_pfn/pte_dirty called on non-present PTE
fs/proc/task_mmu: fix PAGEMAP_SCAN written state for unpopulated ptes
userfaultfd: wait on source PMD during UFFDIO_MOVE
lib: test_hmm: use device devt for coherent device range selection
mm/vmstat: fold stranded per-cpu node stats when a node comes online
Pull keys fixes from Jarkko Sakkinen:
- An unprivileged keyring whose keys collide through the
description-chunk path can drive assoc_array node splitting
into an out-of-bounds slot write. Fix it.
- Fix the DCP trusted keys backend
* tag 'for-next-keys-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
assoc_array: trim the final shortcut word using the current chunk end
keys: make keyring key-chunk byte order agree with keyring_diff_objects()
keys: fix out-of-bounds read in keyring_get_key_chunk()
KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type