From: Greg Kroah-Hartman Date: Thu, 2 Jul 2026 13:14:48 +0000 (+0200) Subject: 7.1-stable patches X-Git-Tag: v5.10.260~40 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=07779bfba792ce9873ee578cc9e90a2a323dd171;p=thirdparty%2Fkernel%2Fstable-queue.git 7.1-stable patches added patches: block-avoid-mounting-the-bdev-pseudo-filesystem-in-userspace.patch bpf-use-kvfree-for-replaced-sysctl-write-buffer.patch crypto-nx-fix-nx_crypto_ctx_exit-argument.patch exfat-fix-potential-use-after-free-in-exfat_find_dir_entry.patch f2fs-atomic-fix-uaf-issue-on-f2fs_inode_info.atomic_inode.patch f2fs-bound-i_inline_xattr_size-for-non-inline-xattr-inodes.patch f2fs-fix-incorrect-fi_no_extent-handling-in-__destroy_extent_node.patch f2fs-fix-missing-read-bio-submission-on-large-folio-error.patch f2fs-fix-to-do-sanity-check-on-f2fs_get_node_folio_ra.patch f2fs-fix-to-round-down-start-offset-of-fallocate-for-pin-file.patch f2fs-keep-atomic-write-retry-from-zeroing-original-data.patch f2fs-pass-correct-iostat-type-for-single-node-writes.patch f2fs-read-cow-data-with-the-original-inode-during-atomic-write.patch f2fs-reject-setattr-size-changes-on-large-folio-files.patch f2fs-validate-acl-entry-sizes-in-f2fs_acl_from_disk.patch f2fs-validate-compress-cache-inode-only-when-enabled.patch f2fs-validate-orphan-inode-entry-count.patch kvm-replace-guest-triggerable-bug_on-in-ioeventfd-datamatch-with-get_unaligned.patch kvm-x86-mmu-ensure-hugepage-is-in-by-slot-before-checking-max-mapping-level.patch mips-dec-prevent-initial-console-buffer-from-landing-in-xkphys.patch revert-f2fs-remove-non-uptodate-folio-from-the-page-cache-in-move_data_block.patch --- diff --git a/queue-7.1/block-avoid-mounting-the-bdev-pseudo-filesystem-in-userspace.patch b/queue-7.1/block-avoid-mounting-the-bdev-pseudo-filesystem-in-userspace.patch new file mode 100644 index 0000000000..556f49234b --- /dev/null +++ b/queue-7.1/block-avoid-mounting-the-bdev-pseudo-filesystem-in-userspace.patch @@ -0,0 +1,76 @@ +From f73aa66dffcb8e61e78f01b56163ec16a15d06d2 Mon Sep 17 00:00:00 2001 +From: Denis Arefev +Date: Thu, 21 May 2026 10:28:56 +0300 +Subject: block: Avoid mounting the bdev pseudo-filesystem in userspace + +From: Denis Arefev + +commit f73aa66dffcb8e61e78f01b56163ec16a15d06d2 upstream. + +The bdev pseudo-filesystem is an internal kernel filesystem with which +userspace should not interfere. Unregister it so that userspace cannot +even attempt to mount it. + +This fixes a bug [1] that occurs when attempting to access files, +because the system call move_mount() uses pointers declared in the +inode_operations structure, which for the bdev pseudo-filesystem +are always equal to 0. `inode->i_op = &empty_iops;` + +[1] + + BUG: kernel NULL pointer dereference, address: 0000000000000000 + #PF: supervisor instruction fetch in kernel mode + #PF: error_code(0x0010) - not-present page + PGD 23380067 P4D 23380067 PUD 23381067 PMD 0 + Oops: 0010 [#1] PREEMPT SMP KASAN NOPTI + CPU: 2 PID: 17125 Comm: syz-executor.0 Not tainted 6.1.155-syzkaller-00350-g84221fde2681 #0 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 + RIP: 0010:0x0 + + Call Trace: + + lookup_open.isra.0+0x700/0x1180 fs/namei.c:3460 + open_last_lookups fs/namei.c:3550 [inline] + path_openat+0x953/0x2700 fs/namei.c:3780 + do_filp_open+0x1c5/0x410 fs/namei.c:3810 + do_sys_openat2+0x171/0x4d0 fs/open.c:1318 + do_sys_open fs/open.c:1334 [inline] + __do_sys_openat fs/open.c:1350 [inline] + __se_sys_openat fs/open.c:1345 [inline] + __x64_sys_openat+0x13c/0x1f0 fs/open.c:1345 + do_syscall_x64 arch/x86/entry/common.c:51 [inline] + do_syscall_64+0x35/0x80 arch/x86/entry/common.c:81 + entry_SYSCALL_64_after_hwframe+0x6e/0xd8 + +Found by Linux Verification Center (linuxtesting.org) with Syzkaller. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Link: https://lore.kernel.org/all/20131010004732.GJ13318@ZenIV.linux.org.uk/T/# +Cc: stable@vger.kernel.org +Signed-off-by: Denis Arefev +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260521072857.5078-1-arefev@swemel.ru +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + block/bdev.c | 5 ----- + 1 file changed, 5 deletions(-) + +--- a/block/bdev.c ++++ b/block/bdev.c +@@ -446,15 +446,10 @@ EXPORT_SYMBOL_GPL(blockdev_superblock); + + void __init bdev_cache_init(void) + { +- int err; +- + bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode), + 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| + SLAB_ACCOUNT|SLAB_PANIC), + init_once); +- err = register_filesystem(&bd_type); +- if (err) +- panic("Cannot register bdev pseudo-fs"); + blockdev_mnt = kern_mount(&bd_type); + if (IS_ERR(blockdev_mnt)) + panic("Cannot create bdev pseudo-fs"); diff --git a/queue-7.1/bpf-use-kvfree-for-replaced-sysctl-write-buffer.patch b/queue-7.1/bpf-use-kvfree-for-replaced-sysctl-write-buffer.patch new file mode 100644 index 0000000000..4ab8538414 --- /dev/null +++ b/queue-7.1/bpf-use-kvfree-for-replaced-sysctl-write-buffer.patch @@ -0,0 +1,89 @@ +From 4c21b5927d4364bfe7365f2700da5fea0ed0d004 Mon Sep 17 00:00:00 2001 +From: Dawei Feng +Date: Wed, 3 Jun 2026 18:53:16 +0800 +Subject: bpf: use kvfree() for replaced sysctl write buffer + +From: Dawei Feng + +commit 4c21b5927d4364bfe7365f2700da5fea0ed0d004 upstream. + +proc_sys_call_handler() allocates its temporary sysctl buffer with +kvzalloc() and passes it to __cgroup_bpf_run_filter_sysctl(). Since +kvzalloc() may fall back to vmalloc() for large allocations, freeing +that buffer with kfree() is wrong and can corrupt memory. + +Use kvfree() to safely handle both kmalloc and kvzalloc()/vmalloc +allocations. + +The bug was first flagged by an experimental analysis tool we are +developing for kernel memory-management bugs while analyzing +v6.13-rc1. The tool is still under development and is not yet publicly +available. Manual inspection confirms that the bug is still +present in v7.1-rc5. + +Reproduced the bug based on v7.1-rc4 in a QEMU x86_64 guest booted with +KASAN and CONFIG_FAILSLAB enabled. To exercise the replacement path, the +test tree also included the accompanying fix for the stale ret == 1 +check in __cgroup_bpf_run_filter_sysctl(). The reproducer confines +failslab injections to the proc_sys_call_handler() range, uses +stacktrace-depth=32, and injects fail-nth=1 while writing 8191 bytes to +/proc/sys/kernel/domainname from a task in the target cgroup. Under +that setup, fail-nth=1 triggered the fault: + + BUG: unable to handle page fault for address: ffffeb0200024d48 + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + PGD 0 P4D 0 + Oops: Oops: 0000 SMP KASAN NOPTI + CPU: 2 UID: 0 PID: 209 Comm: repro_proc_sys_ Not tainted 7.1.0-rc4-00686-g97625979a5d4 PREEMPT(lazy) + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.15.0-1 04/01/2014 + RIP: 0010:kfree+0x6e/0x510 + ... + Call Trace: + + ? __cgroup_bpf_run_filter_sysctl+0x626/0xc30 + __cgroup_bpf_run_filter_sysctl+0x74d/0xc30 + ? __pfx___cgroup_bpf_run_filter_sysctl+0x10/0x10 + ? srso_return_thunk+0x5/0x5f + ? __kvmalloc_node_noprof+0x345/0x870 + ? proc_sys_call_handler+0x250/0x480 + ? srso_return_thunk+0x5/0x5f + proc_sys_call_handler+0x3a2/0x480 + ? __pfx_proc_sys_call_handler+0x10/0x10 + ? srso_return_thunk+0x5/0x5f + ? selinux_file_permission+0x39f/0x500 + ? srso_return_thunk+0x5/0x5f + ? lock_is_held_type+0x9e/0x120 + vfs_write+0x98e/0x1000 + ... + + +With this fix applied on top of the same test setup, rerunning the +reproducer with fail-nth=1 yields no corresponding Oops reports. + +Fixes: 4508943794ef ("proc: use kvzalloc for our kernel buffer") +Cc: stable@vger.kernel.org + +Reviewed-by: Emil Tsalapatis +Reviewed-by: Jiayuan Chen +Acked-by: Yonghong Song +Signed-off-by: Zilin Guan +Signed-off-by: Dawei Feng +Link: https://lore.kernel.org/r/20260603105317.944304-3-dawei.feng@seu.edu.cn +Signed-off-by: Alexei Starovoitov +Signed-off-by: Greg Kroah-Hartman +--- + kernel/bpf/cgroup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/kernel/bpf/cgroup.c ++++ b/kernel/bpf/cgroup.c +@@ -1936,7 +1936,7 @@ int __cgroup_bpf_run_filter_sysctl(struc + kfree(ctx.cur_val); + + if (ret == 1 && ctx.new_updated) { +- kfree(*buf); ++ kvfree(*buf); + *buf = ctx.new_val; + *pcount = ctx.new_len; + } else { diff --git a/queue-7.1/crypto-nx-fix-nx_crypto_ctx_exit-argument.patch b/queue-7.1/crypto-nx-fix-nx_crypto_ctx_exit-argument.patch new file mode 100644 index 0000000000..fe77e0c322 --- /dev/null +++ b/queue-7.1/crypto-nx-fix-nx_crypto_ctx_exit-argument.patch @@ -0,0 +1,90 @@ +From 4e67f504ee9ded15e256b64f4fde150e917381d7 Mon Sep 17 00:00:00 2001 +From: Sam James +Date: Mon, 25 May 2026 08:56:19 +0100 +Subject: crypto: nx - fix nx_crypto_ctx_exit argument + +From: Sam James + +commit 4e67f504ee9ded15e256b64f4fde150e917381d7 upstream. + +nx_crypto_ctx_shash_exit calls nx_crypto_ctx_exit with crypto_shash_ctx(...) +but crypto_shash_ctx gives a nx_crypto_ctx *, not a crypto_tfm *. + +Fix the type in nx_crypto_ctx_exit and drop the bogus crypto_tfm_ctx +call. + +This fixes the following oops: + + BUG: Unable to handle kernel data access at 0xc0403effffffffc8 + Faulting instruction address: 0xc000000000396cb4 + Oops: Kernel access of bad area, sig: 11 [#15] + Call Trace: + nx_crypto_ctx_shash_exit+0x24/0x60 + crypto_shash_exit_tfm+0x28/0x40 + crypto_destroy_tfm+0x98/0x140 + crypto_exit_ahash_using_shash+0x20/0x40 + crypto_destroy_tfm+0x98/0x140 + hash_release+0x1c/0x30 + alg_sock_destruct+0x38/0x60 + __sk_destruct+0x48/0x2b0 + af_alg_release+0x58/0xb0 + __sock_release+0x68/0x150 + sock_close+0x20/0x40 + __fput+0x110/0x3a0 + sys_close+0x48/0xa0 + system_call_exception+0x140/0x2d0 + system_call_common+0xf4/0x258 + +.. which came from hardlink(1) opportunistically using AF_ALG. + +The same problem exists with nx_crypto_ctx_skcipher_exit getting a context +it wasn't expecting, but apparently nobody hit that for years. + +Cc: Eric Biggers +Cc: stable@vger.kernel.org +Fixes: bfd9efddf990 ("crypto: nx - convert AES-ECB to skcipher API") +Fixes: 9420e628e7d8 ("crypto: nx - Use API partial block handling") +Acked-by: Breno Leitao +Reviewed-by: Eric Biggers +Reported-by: Calvin Buckley +Tested-by: Calvin Buckley +Suggested-by: Brad Spengler +Signed-off-by: Sam James +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/nx/nx.c | 6 ++---- + drivers/crypto/nx/nx.h | 2 +- + 2 files changed, 3 insertions(+), 5 deletions(-) + +--- a/drivers/crypto/nx/nx.c ++++ b/drivers/crypto/nx/nx.c +@@ -714,15 +714,13 @@ int nx_crypto_ctx_aes_xcbc_init(struct c + /** + * nx_crypto_ctx_exit - destroy a crypto api context + * +- * @tfm: the crypto transform pointer for the context ++ * @nx_ctx: the crypto api context + * + * As crypto API contexts are destroyed, this exit hook is called to free the + * memory associated with it. + */ +-void nx_crypto_ctx_exit(struct crypto_tfm *tfm) ++void nx_crypto_ctx_exit(struct nx_crypto_ctx *nx_ctx) + { +- struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm); +- + kfree_sensitive(nx_ctx->kmem); + nx_ctx->csbcpb = NULL; + nx_ctx->csbcpb_aead = NULL; +--- a/drivers/crypto/nx/nx.h ++++ b/drivers/crypto/nx/nx.h +@@ -153,7 +153,7 @@ int nx_crypto_ctx_aes_ctr_init(struct cr + int nx_crypto_ctx_aes_cbc_init(struct crypto_skcipher *tfm); + int nx_crypto_ctx_aes_ecb_init(struct crypto_skcipher *tfm); + int nx_crypto_ctx_sha_init(struct crypto_shash *tfm); +-void nx_crypto_ctx_exit(struct crypto_tfm *tfm); ++void nx_crypto_ctx_exit(struct nx_crypto_ctx *nx_ctx); + void nx_crypto_ctx_skcipher_exit(struct crypto_skcipher *tfm); + void nx_crypto_ctx_aead_exit(struct crypto_aead *tfm); + void nx_crypto_ctx_shash_exit(struct crypto_shash *tfm); diff --git a/queue-7.1/exfat-fix-potential-use-after-free-in-exfat_find_dir_entry.patch b/queue-7.1/exfat-fix-potential-use-after-free-in-exfat_find_dir_entry.patch new file mode 100644 index 0000000000..d0aac0f25f --- /dev/null +++ b/queue-7.1/exfat-fix-potential-use-after-free-in-exfat_find_dir_entry.patch @@ -0,0 +1,90 @@ +From 3f5f8ee9917cc2b9076ac533492d8a200edcabb8 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Wed, 22 Apr 2026 11:58:44 -0400 +Subject: exfat: fix potential use-after-free in exfat_find_dir_entry() + +From: Michael Bommarito + +commit 3f5f8ee9917cc2b9076ac533492d8a200edcabb8 upstream. + +In exfat_find_dir_entry(), the buffer_head obtained from +exfat_get_dentry() is released with brelse(bh) before the fall-through +TYPE_EXTEND branch reads the directory entry through ep (which points +into bh->b_data): + + brelse(bh); + if (entry_type == TYPE_EXTEND) { + ... + len = exfat_extract_uni_name(ep, entry_uniname); + ... + } + +After brelse() drops our reference, nothing guarantees that the +underlying page backing bh->b_data remains valid for the subsequent +exfat_extract_uni_name() read. This is the same pattern fixed in +commit fc961522ddbd ("exfat: Fix potential use after free in +exfat_load_upcase_table()"). + +Move brelse(bh) so it runs after ep is no longer dereferenced on +each branch. + +Confirmed on QEMU x86_64 with CONFIG_KASAN=y + CONFIG_DEBUG_PAGEALLOC=y ++ CONFIG_PAGE_POISONING=y on linux-next, using a crafted exFAT image +(long filename with same-hash collisions forcing the TYPE_EXTEND path). +With a debug-only invalidate_bdev() inserted between brelse(bh) and +the ep read to make the stale-deref window deterministic, the +unpatched kernel faults: + + BUG: KASAN: use-after-free in exfat_find_dir_entry+0x133b/0x15a0 + BUG: unable to handle page fault for address: ffff88801a5fa0c2 + Oops: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN NOPTI + RIP: 0010:exfat_find_dir_entry+0x1188/0x15a0 + +With this patch applied, the same instrumented harness completes +cleanly under the same sanitizer stack. I have not reproduced a +crash on an uninstrumented kernel under ordinary reclaim; the +instrumented A/B establishes the lifetime violation and that the +patch closes it, not an unaided triggerability claim. + +Fixes: ca06197382bd ("exfat: add directory operations") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Signed-off-by: Namjae Jeon +Signed-off-by: Greg Kroah-Hartman +--- + fs/exfat/dir.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/exfat/dir.c ++++ b/fs/exfat/dir.c +@@ -1027,12 +1027,12 @@ rewind: + continue; + } + +- brelse(bh); + if (entry_type == TYPE_EXTEND) { + unsigned short entry_uniname[16], unichar; + + if (step != DIRENT_STEP_NAME || + name_len >= MAX_NAME_LENGTH) { ++ brelse(bh); + step = DIRENT_STEP_FILE; + continue; + } +@@ -1043,6 +1043,7 @@ rewind: + uniname += EXFAT_FILE_NAME_LEN; + + len = exfat_extract_uni_name(ep, entry_uniname); ++ brelse(bh); + name_len += len; + + unichar = *(uniname+len); +@@ -1061,6 +1062,7 @@ rewind: + continue; + } + ++ brelse(bh); + if (entry_type & + (TYPE_CRITICAL_SEC | TYPE_BENIGN_SEC)) { + if (step == DIRENT_STEP_SECD) { diff --git a/queue-7.1/f2fs-atomic-fix-uaf-issue-on-f2fs_inode_info.atomic_inode.patch b/queue-7.1/f2fs-atomic-fix-uaf-issue-on-f2fs_inode_info.atomic_inode.patch new file mode 100644 index 0000000000..b324736435 --- /dev/null +++ b/queue-7.1/f2fs-atomic-fix-uaf-issue-on-f2fs_inode_info.atomic_inode.patch @@ -0,0 +1,164 @@ +From e0288584baa5dc41df4a829a023c4c1b33fe53d7 Mon Sep 17 00:00:00 2001 +From: Chao Yu +Date: Thu, 21 May 2026 10:15:05 +0800 +Subject: f2fs: atomic: fix UAF issue on f2fs_inode_info.atomic_inode + +From: Chao Yu + +commit e0288584baa5dc41df4a829a023c4c1b33fe53d7 upstream. + +- ioctl(F2FS_IOC_GARBAGE_COLLECT_RANGE) - shrink + - f2fs_gc + - gc_data_segment + - ra_data_block(cow_inode) + - mapping = F2FS_I(inode)->atomic_inode->i_mapping + : f2fs_is_cow_file(cow_inode) is true + - f2fs_evict_inode(atomic_inode) + - clear_inode_flag(fi->cow_inode, FI_COW_FILE) + - F2FS_I(fi->cow_inode)->atomic_inode = NULL + ... + - truncate_inode_pages_final(atomic_inode) + - f2fs_grab_cache_folio(mapping) + : create folio in atomic_inode->mapping + - clear_inode(atomic_inode) + - BUG_ON(atomic_inode->i_data.nrpages) + +We need to add a reference on fi->atomic_inode before using its mapping +field during garbage collection, otherwise, it will cause UAF issue. + +Cc: stable@kernel.org +Cc: Daeho Jeong +Cc: Sunmin Jeong +Fixes: 3db1de0e582c ("f2fs: change the current atomic write way") +Fixes: f18d00769336 ("f2fs: use meta inode for GC of COW file") +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/gc.c | 50 ++++++++++++++++++++++++++++++++++++++++++-------- + fs/f2fs/inode.c | 11 ++++++++--- + 2 files changed, 50 insertions(+), 11 deletions(-) + +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -1220,8 +1220,8 @@ static bool is_alive(struct f2fs_sb_info + static int ra_data_block(struct inode *inode, pgoff_t index) + { + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); +- struct address_space *mapping = f2fs_is_cow_file(inode) ? +- F2FS_I(inode)->atomic_inode->i_mapping : inode->i_mapping; ++ struct address_space *mapping = inode->i_mapping; ++ struct inode *atomic_inode = NULL; + struct dnode_of_data dn; + struct folio *folio, *efolio; + struct f2fs_io_info fio = { +@@ -1236,9 +1236,22 @@ static int ra_data_block(struct inode *i + }; + int err = 0; + ++ f2fs_down_read(&F2FS_I(inode)->i_sem); ++ if (f2fs_is_cow_file(inode)) { ++ atomic_inode = igrab(F2FS_I(inode)->atomic_inode); ++ if (!atomic_inode) { ++ f2fs_up_read(&F2FS_I(inode)->i_sem); ++ return -EBUSY; ++ } ++ mapping = atomic_inode->i_mapping; ++ } ++ f2fs_up_read(&F2FS_I(inode)->i_sem); ++ + folio = f2fs_grab_cache_folio(mapping, index, true); +- if (IS_ERR(folio)) +- return PTR_ERR(folio); ++ if (IS_ERR(folio)) { ++ err = PTR_ERR(folio); ++ goto out_iput; ++ } + + if (f2fs_lookup_read_extent_cache_block(inode, index, + &dn.data_blkaddr)) { +@@ -1299,11 +1312,16 @@ got_it: + f2fs_update_iostat(sbi, inode, FS_DATA_READ_IO, F2FS_BLKSIZE); + f2fs_update_iostat(sbi, NULL, FS_GDATA_READ_IO, F2FS_BLKSIZE); + ++ if (atomic_inode) ++ iput(atomic_inode); + return 0; + put_encrypted_page: + f2fs_put_page(fio.encrypted_page, true); + put_folio: + f2fs_folio_put(folio, true); ++out_iput: ++ if (atomic_inode) ++ iput(atomic_inode); + return err; + } + +@@ -1314,8 +1332,8 @@ put_folio: + static int move_data_block(struct inode *inode, block_t bidx, + int gc_type, unsigned int segno, int off) + { +- struct address_space *mapping = f2fs_is_cow_file(inode) ? +- F2FS_I(inode)->atomic_inode->i_mapping : inode->i_mapping; ++ struct address_space *mapping = inode->i_mapping; ++ struct inode *atomic_inode = NULL; + struct f2fs_io_info fio = { + .sbi = F2FS_I_SB(inode), + .ino = inode->i_ino, +@@ -1337,10 +1355,23 @@ static int move_data_block(struct inode + (fio.sbi->gc_mode != GC_URGENT_HIGH) ? + CURSEG_ALL_DATA_ATGC : CURSEG_COLD_DATA; + ++ f2fs_down_read(&F2FS_I(inode)->i_sem); ++ if (f2fs_is_cow_file(inode)) { ++ atomic_inode = igrab(F2FS_I(inode)->atomic_inode); ++ if (!atomic_inode) { ++ f2fs_up_read(&F2FS_I(inode)->i_sem); ++ return -EBUSY; ++ } ++ mapping = atomic_inode->i_mapping; ++ } ++ f2fs_up_read(&F2FS_I(inode)->i_sem); ++ + /* do not read out */ + folio = f2fs_grab_cache_folio(mapping, bidx, false); +- if (IS_ERR(folio)) +- return PTR_ERR(folio); ++ if (IS_ERR(folio)) { ++ err = PTR_ERR(folio); ++ goto out_iput; ++ } + + if (!check_valid_map(F2FS_I_SB(inode), segno, off)) { + err = -ENOENT; +@@ -1473,6 +1504,9 @@ out: + folio_unlock(folio); + folio_end_dropbehind(folio); + folio_put(folio); ++out_iput: ++ if (atomic_inode) ++ iput(atomic_inode); + return err; + } + +--- a/fs/f2fs/inode.c ++++ b/fs/f2fs/inode.c +@@ -863,10 +863,15 @@ void f2fs_evict_inode(struct inode *inod + f2fs_abort_atomic_write(inode, true); + + if (fi->cow_inode && f2fs_is_cow_file(fi->cow_inode)) { +- clear_inode_flag(fi->cow_inode, FI_COW_FILE); +- F2FS_I(fi->cow_inode)->atomic_inode = NULL; +- iput(fi->cow_inode); ++ struct inode *cow_inode = fi->cow_inode; ++ ++ f2fs_down_write(&F2FS_I(cow_inode)->i_sem); ++ clear_inode_flag(cow_inode, FI_COW_FILE); ++ F2FS_I(cow_inode)->atomic_inode = NULL; + fi->cow_inode = NULL; ++ f2fs_up_write(&F2FS_I(cow_inode)->i_sem); ++ ++ iput(cow_inode); + } + + trace_f2fs_evict_inode(inode); diff --git a/queue-7.1/f2fs-bound-i_inline_xattr_size-for-non-inline-xattr-inodes.patch b/queue-7.1/f2fs-bound-i_inline_xattr_size-for-non-inline-xattr-inodes.patch new file mode 100644 index 0000000000..c3b0a71cc9 --- /dev/null +++ b/queue-7.1/f2fs-bound-i_inline_xattr_size-for-non-inline-xattr-inodes.patch @@ -0,0 +1,72 @@ +From 378acf3cf19b6af6cba55e8dd1154c4e1504bae8 Mon Sep 17 00:00:00 2001 +From: Bryam Vargas +Date: Thu, 11 Jun 2026 23:00:36 -0500 +Subject: f2fs: bound i_inline_xattr_size for non-inline-xattr inodes + +From: Bryam Vargas + +commit 378acf3cf19b6af6cba55e8dd1154c4e1504bae8 upstream. + +When the flexible_inline_xattr feature is enabled, do_read_inode() loads +the on-disk i_inline_xattr_size unconditionally: + + if (f2fs_sb_has_flexible_inline_xattr(sbi)) + fi->i_inline_xattr_size = le16_to_cpu(ri->i_inline_xattr_size); + +but sanity_check_inode() only range-checks it when the inode also has the +FI_INLINE_XATTR flag set. An inode that carries an inline dentry or inline +data but not FI_INLINE_XATTR -- the normal layout for an inline +directory -- therefore keeps a fully attacker-controlled +i_inline_xattr_size from a crafted image. + +get_inline_xattr_addrs() returns that value with no flag gating, so it +feeds the inode geometry: + + MAX_INLINE_DATA() = 4 * (CUR_ADDRS_PER_INODE - i_inline_xattr_size - 1) + NR_INLINE_DENTRY() = MAX_INLINE_DATA() * BITS_PER_BYTE / (...) + addrs_per_page() = CUR_ADDRS_PER_INODE - i_inline_xattr_size + +A large i_inline_xattr_size drives MAX_INLINE_DATA() and NR_INLINE_DENTRY() +negative, so make_dentry_ptr_inline() sets d->max (int) to a negative +value. The inline directory walk then compares an unsigned long bit_pos +against that negative d->max, which is promoted to a huge unsigned bound, +and reads far past the inline area: + + while (bit_pos < d->max) /* fs/f2fs/dir.c */ + ... test_bit_le(bit_pos, d->bitmap) / d->dentry[bit_pos] ... + +Mounting a crafted image and reading such a directory triggers an +out-of-bounds read in f2fs_fill_dentries(); the same underflow also +corrupts ADDRS_PER_INODE for regular files. + +Validate i_inline_xattr_size against MAX_INLINE_XATTR_SIZE whenever the +flexible_inline_xattr feature is enabled -- i.e. whenever the value is +loaded from disk and consumed -- and keep the lower MIN_INLINE_XATTR_SIZE +bound gated on inodes that actually carry an inline xattr, so legitimate +inodes with i_inline_xattr_size == 0 are still accepted. + +Cc: stable@vger.kernel.org +Fixes: 6afc662e68b5 ("f2fs: support flexible inline xattr size") +Signed-off-by: Bryam Vargas +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/inode.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/fs/f2fs/inode.c ++++ b/fs/f2fs/inode.c +@@ -324,9 +324,9 @@ static bool sanity_check_inode(struct in + } + + if (f2fs_sb_has_flexible_inline_xattr(sbi) && +- f2fs_has_inline_xattr(inode) && +- (fi->i_inline_xattr_size < MIN_INLINE_XATTR_SIZE || +- fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE)) { ++ (fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE || ++ (f2fs_has_inline_xattr(inode) && ++ fi->i_inline_xattr_size < MIN_INLINE_XATTR_SIZE))) { + f2fs_warn(sbi, "%s: inode (ino=%llx) has corrupted i_inline_xattr_size: %d, min: %zu, max: %lu", + __func__, inode->i_ino, fi->i_inline_xattr_size, + MIN_INLINE_XATTR_SIZE, MAX_INLINE_XATTR_SIZE); diff --git a/queue-7.1/f2fs-fix-incorrect-fi_no_extent-handling-in-__destroy_extent_node.patch b/queue-7.1/f2fs-fix-incorrect-fi_no_extent-handling-in-__destroy_extent_node.patch new file mode 100644 index 0000000000..2d5aaa2371 --- /dev/null +++ b/queue-7.1/f2fs-fix-incorrect-fi_no_extent-handling-in-__destroy_extent_node.patch @@ -0,0 +1,85 @@ +From 1f70ddb28a3c71df124da5fa4040c808116d6bb9 Mon Sep 17 00:00:00 2001 +From: Yongpeng Yang +Date: Mon, 27 Apr 2026 21:10:51 +0800 +Subject: f2fs: fix incorrect FI_NO_EXTENT handling in __destroy_extent_node() + +From: Yongpeng Yang + +commit 1f70ddb28a3c71df124da5fa4040c808116d6bb9 upstream. + +When __destroy_extent_node() sets the inode flag FI_NO_EXTENT, it does +not reset the length of the largest extent to 0 and update the inode +folio. Since modifications to the extent tree are disallowed afterward, +the cached largest extent may become stale. This can trigger the +following error in xfstests generic/388: + +F2FS-fs (dm-0): sanity_check_extent_cache: inode (ino=1761) extent info [220057, 57, 6] is incorrect, run fsck to fix + +In the f2fs_drop_inode path, __destroy_extent_node() does not need to +guarantee that et->node_cnt is 0, because concurrency with writeback +is expected in this path, and writeback may update the extent cache. + +This patch reverts commit ed78aeebef05 ("f2fs: fix node_cnt race between +extent node destroy and writeback"), and remove the unnecessary zero +check of et->node_cnt. + +Fixes: ed78aeebef05 ("f2fs: fix node_cnt race between extent node destroy and writeback") +Cc: stable@vger.kernel.org +Reported-by: Chao Yu +Suggested-by: Chao Yu +Signed-off-by: Yongpeng Yang +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/extent_cache.c | 19 +++++++------------ + 1 file changed, 7 insertions(+), 12 deletions(-) + +--- a/fs/f2fs/extent_cache.c ++++ b/fs/f2fs/extent_cache.c +@@ -119,10 +119,9 @@ static bool __may_extent_tree(struct ino + if (!__init_may_extent_tree(inode, type)) + return false; + +- if (is_inode_flag_set(inode, FI_NO_EXTENT)) +- return false; +- + if (type == EX_READ) { ++ if (is_inode_flag_set(inode, FI_NO_EXTENT)) ++ return false; + if (is_inode_flag_set(inode, FI_COMPRESSED_FILE) && + !f2fs_sb_has_readonly(F2FS_I_SB(inode))) + return false; +@@ -645,14 +644,10 @@ static unsigned int __destroy_extent_nod + + while (atomic_read(&et->node_cnt)) { + write_lock(&et->lock); +- if (!is_inode_flag_set(inode, FI_NO_EXTENT)) +- set_inode_flag(inode, FI_NO_EXTENT); + node_cnt += __free_extent_tree(sbi, et, nr_shrink); + write_unlock(&et->lock); + } + +- f2fs_bug_on(sbi, atomic_read(&et->node_cnt)); +- + return node_cnt; + } + +@@ -691,12 +686,12 @@ static void __update_extent_tree_range(s + + write_lock(&et->lock); + +- if (is_inode_flag_set(inode, FI_NO_EXTENT)) { +- write_unlock(&et->lock); +- return; +- } +- + if (type == EX_READ) { ++ if (is_inode_flag_set(inode, FI_NO_EXTENT)) { ++ write_unlock(&et->lock); ++ return; ++ } ++ + prev = et->largest; + dei.len = 0; + diff --git a/queue-7.1/f2fs-fix-missing-read-bio-submission-on-large-folio-error.patch b/queue-7.1/f2fs-fix-missing-read-bio-submission-on-large-folio-error.patch new file mode 100644 index 0000000000..2f659a5705 --- /dev/null +++ b/queue-7.1/f2fs-fix-missing-read-bio-submission-on-large-folio-error.patch @@ -0,0 +1,67 @@ +From 74c8d2ec95c59a5651ecd975c466998af1961fd4 Mon Sep 17 00:00:00 2001 +From: Wenjie Qi +Date: Wed, 20 May 2026 17:52:04 +0800 +Subject: f2fs: fix missing read bio submission on large folio error + +From: Wenjie Qi + +commit 74c8d2ec95c59a5651ecd975c466998af1961fd4 upstream. + +f2fs_read_data_large_folio() can keep a read bio across multiple +readahead folios. If a later folio hits an error before any of its +blocks are added to the bio, folio_in_bio is false and the current error +path returns immediately after ending that folio. + +This can leave the bio accumulated for earlier folios unsubmitted. Those +folios then never receive read completion, and readers can wait +indefinitely on the locked folios. + +Route errors through the common out path so any pending bio is submitted +before returning. Stop consuming more readahead folios once an error is +seen, and only wait on and clear the current folio when it was actually +added to the bio. + +Cc: stable@kernel.org +Fixes: a5d8b9d94e18 ("f2fs: fix to unlock folio in f2fs_read_data_large_folio()") +Signed-off-by: Wenjie Qi +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/data.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -2495,7 +2495,7 @@ static int f2fs_read_data_large_folio(st + unsigned nrpages; + struct f2fs_folio_state *ffs; + int ret = 0; +- bool folio_in_bio; ++ bool folio_in_bio = false; + + if (!IS_IMMUTABLE(inode) || f2fs_compressed_file(inode)) { + if (folio) +@@ -2611,18 +2611,17 @@ submit_and_realloc: + } + trace_f2fs_read_folio(folio, DATA); + err_out: +- if (!folio_in_bio) { ++ if (!folio_in_bio) + folio_end_read(folio, !ret); +- if (ret) +- return ret; +- } ++ if (ret) ++ goto out; + if (rac) { + folio = readahead_folio(rac); + goto next_folio; + } + out: + f2fs_submit_read_bio(F2FS_I_SB(inode), bio, DATA); +- if (ret) { ++ if (ret && folio_in_bio) { + /* Wait bios and clear uptodate. */ + folio_lock(folio); + folio_clear_uptodate(folio); diff --git a/queue-7.1/f2fs-fix-to-do-sanity-check-on-f2fs_get_node_folio_ra.patch b/queue-7.1/f2fs-fix-to-do-sanity-check-on-f2fs_get_node_folio_ra.patch new file mode 100644 index 0000000000..8c965e433b --- /dev/null +++ b/queue-7.1/f2fs-fix-to-do-sanity-check-on-f2fs_get_node_folio_ra.patch @@ -0,0 +1,111 @@ +From 8712353ed80f87271d732297567dcdbe4b84e8c7 Mon Sep 17 00:00:00 2001 +From: Chao Yu +Date: Fri, 22 May 2026 15:53:29 +0800 +Subject: f2fs: fix to do sanity check on f2fs_get_node_folio_ra() + +From: Chao Yu + +commit 8712353ed80f87271d732297567dcdbe4b84e8c7 upstream. + +kernel BUG at fs/f2fs/file.c:845! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +CPU: 0 UID: 0 PID: 5336 Comm: syz.0.0 Not tainted syzkaller #0 PREEMPT(full) +Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +RIP: 0010:f2fs_do_truncate_blocks+0x1115/0x1140 fs/f2fs/file.c:845 +Code: fc fc 90 0f 0b e8 8b 9d 9a fd 90 0f 0b e8 83 9d 9a fd 48 89 df 48 c7 c6 60 d1 1a 8c e8 54 f1 fc fc 90 0f 0b e8 6c 9d 9a fd 90 <0f> 0b e8 64 9d 9a fd 90 0f 0b 90 e9 93 fd ff ff e8 56 9d 9a fd 90 +RSP: 0018:ffffc9000e4474c0 EFLAGS: 00010283 +RAX: ffffffff842b1d34 RBX: 0000000000000003 RCX: 0000000000100000 +RDX: ffffc9000f03a000 RSI: 0000000000035503 RDI: 0000000000035504 +RBP: ffffc9000e447608 R08: ffff8880123b0000 R09: 0000000000000002 +R10: 00000000fffffffe R11: 0000000000000002 R12: 0000000000000001 +R13: 0000000000000000 R14: 1ffff92001c88ea0 R15: 00000000ffff039c +FS: 00007f7e02ee36c0(0000) GS:ffff88808c887000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007ff0305c4000 CR3: 0000000012d4c000 CR4: 0000000000352ef0 +Call Trace: + + f2fs_truncate_blocks+0x10a/0x300 fs/f2fs/file.c:882 + f2fs_truncate+0x471/0x7c0 fs/f2fs/file.c:940 + f2fs_evict_inode+0xa3f/0x1ac0 fs/f2fs/inode.c:907 + evict+0x61e/0xb10 fs/inode.c:841 + f2fs_fill_super+0x5f43/0x78f0 fs/f2fs/super.c:5224 + get_tree_bdev_flags+0x431/0x4f0 fs/super.c:1694 + vfs_get_tree+0x92/0x2a0 fs/super.c:1754 + fc_mount fs/namespace.c:1193 [inline] + do_new_mount_fc fs/namespace.c:3758 [inline] + do_new_mount+0x341/0xd30 fs/namespace.c:3834 + do_mount fs/namespace.c:4167 [inline] + __do_sys_mount fs/namespace.c:4383 [inline] + __se_sys_mount+0x31d/0x420 fs/namespace.c:4360 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + + count = ADDRS_PER_PAGE(dn.node_folio, inode); + + count -= dn.ofs_in_node; + f2fs_bug_on(sbi, count < 0); + +The fuzz test will trigger above bug_on in f2fs. + +The root cause should be: in the corrupted inode, there is a direct node +which has the same ino and nid in its footer, so in f2fs_do_truncate_blocks(), +after f2fs_get_dnode_of_data() finds such dnode: +1) ADDRS_PER_PAGE(dn.node_folio, inode) will return 923 +2) once dn.ofs_in_node points to addr[923, 1017] +Then it will trigger the system panic. + +Let's introduce NODE_TYPE_NON_IXNODE to indicate current node should +not be an inode or xattr node, and then use it in below path to detect +inconsistent node chain in inode mapping table: + +- f2fs_do_truncate_blocks + - f2fs_get_dnode_of_data + - f2fs_get_node_folio_ra + - __get_node_folio + - f2fs_sanity_check_node_footer + - case NODE_TYPE_NON_IXNODE -> check whether it is inode|xnode + +Cc: stable@kernel.org +Reported-by: syzbot+2488d8d751b27f7ce268@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69fa3697.170a0220.59368.0018.GAE@google.com +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/f2fs.h | 1 + + fs/f2fs/node.c | 6 +++++- + 2 files changed, 6 insertions(+), 1 deletion(-) + +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -1583,6 +1583,7 @@ enum node_type { + NODE_TYPE_INODE, + NODE_TYPE_XATTR, + NODE_TYPE_NON_INODE, ++ NODE_TYPE_NON_IXNODE, /* non inode and xnode */ + }; + + /* a threshold of maximum elapsed time in critical region to print tracepoint */ +--- a/fs/f2fs/node.c ++++ b/fs/f2fs/node.c +@@ -1541,6 +1541,10 @@ int f2fs_sanity_check_node_footer(struct + if (is_inode) + goto out_err; + break; ++ case NODE_TYPE_NON_IXNODE: ++ if (is_inode || is_xnode) ++ goto out_err; ++ break; + default: + break; + } +@@ -1634,7 +1638,7 @@ static struct folio *f2fs_get_node_folio + struct f2fs_sb_info *sbi = F2FS_F_SB(parent); + nid_t nid = get_nid(parent, start, false); + +- return __get_node_folio(sbi, nid, parent, start, NODE_TYPE_REGULAR); ++ return __get_node_folio(sbi, nid, parent, start, NODE_TYPE_NON_IXNODE); + } + + static void flush_inline_data(struct f2fs_sb_info *sbi, nid_t ino) diff --git a/queue-7.1/f2fs-fix-to-round-down-start-offset-of-fallocate-for-pin-file.patch b/queue-7.1/f2fs-fix-to-round-down-start-offset-of-fallocate-for-pin-file.patch new file mode 100644 index 0000000000..2350568a65 --- /dev/null +++ b/queue-7.1/f2fs-fix-to-round-down-start-offset-of-fallocate-for-pin-file.patch @@ -0,0 +1,71 @@ +From 4275b59673eb60b02eec3997816c83f1f4b909c4 Mon Sep 17 00:00:00 2001 +From: Sunmin Jeong +Date: Mon, 22 Jun 2026 14:28:17 +0900 +Subject: f2fs: fix to round down start offset of fallocate for pin file + +From: Sunmin Jeong + +commit 4275b59673eb60b02eec3997816c83f1f4b909c4 upstream. + +Currently, the length of fallocate for pin file is section-aligned to +keep allocated sections from being selected as victims of GC. However, +for the case that the start offset of fallocate is not aligned in +section, the allocated sections can't be fully utilized. It's because a +new section is allocated by f2fs_allocate_pinning_section() after using +blks_per_sec blocks regardless of the start offset. As a result, several +unexpected dirty segments may be created, including blocks assigned to +the pinned file. + +To address this issue, let's round down the start offset of fallocate +to the length of section. + +The reproducing scenario is as below + +chunk=$(((2<<20)+4096)) # 2MB + 4KB +touch test +f2fs_io pinfile set test +f2fs_io fallocate 0 0 $chunk test +f2fs_io fallocate 0 $chunk $chunk test +f2fs_io fallocate 0 $((chunk*2)) $chunk test +f2fs_io fiemap 0 $((chunk*3)) test + +Fiemap: offset = 0 len = 12288 + logical addr. physical addr. length flags +0 0000000000000000 000000068c600000 0000000000400000 00001088 +1 0000000000400000 000000003d400000 0000000000001000 00001088 +2 0000000000401000 00000003eb200000 0000000000200000 00001088 +3 0000000000601000 00000005e4200000 0000000000001000 00001088 +4 0000000000602000 0000000605400000 0000000000200000 00001089 + +Cc: stable@vger.kernel.org +Fixes: f5a53edcf01e ("f2fs: support aligned pinned file") +Reviewed-by: Yunji Kang +Reviewed-by: Yeongjin Gil +Reviewed-by: Sungjong Seo +Signed-off-by: Sunmin Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/file.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -1916,8 +1916,15 @@ static int f2fs_expand_inode_data(struct + + if (f2fs_is_pinned_file(inode)) { + block_t sec_blks = CAP_BLKS_PER_SEC(sbi); +- block_t sec_len = roundup(map.m_len, sec_blks); ++ block_t sec_len; + ++ if (map.m_lblk % sec_blks) { ++ map.m_lblk = rounddown(map.m_lblk, sec_blks); ++ map.m_len = pg_end - map.m_lblk; ++ if (off_end) ++ map.m_len++; ++ } ++ sec_len = roundup(map.m_len, sec_blks); + map.m_len = sec_blks; + next_alloc: + f2fs_down_write(&sbi->pin_sem); diff --git a/queue-7.1/f2fs-keep-atomic-write-retry-from-zeroing-original-data.patch b/queue-7.1/f2fs-keep-atomic-write-retry-from-zeroing-original-data.patch new file mode 100644 index 0000000000..8d613dd9ea --- /dev/null +++ b/queue-7.1/f2fs-keep-atomic-write-retry-from-zeroing-original-data.patch @@ -0,0 +1,76 @@ +From 6d874b65aadce56ac78f76129dbcfc2599b638f8 Mon Sep 17 00:00:00 2001 +From: Wenjie Qi +Date: Wed, 27 May 2026 20:06:28 +0800 +Subject: f2fs: keep atomic write retry from zeroing original data + +From: Wenjie Qi + +commit 6d874b65aadce56ac78f76129dbcfc2599b638f8 upstream. + +A partial atomic write reserves a block in the COW inode before reading the +original data page for the untouched bytes in that page. + +If that read fails, write_begin returns an error but leaves the COW inode +entry as NEW_ADDR. A retry of the same partial write then finds the COW +entry, treats it as existing COW data, and f2fs_write_begin() zeroes the +whole folio because blkaddr is NEW_ADDR. + +If the retry is committed, the bytes outside the retried write range are +committed as zeroes instead of preserving the original file contents. + +Only use the COW inode as the read source when it already has a real data +block. If the COW entry is still NEW_ADDR, treat it as a reservation to +reuse: keep reading the old data from the original inode and avoid +reserving or accounting the same atomic block again. + +Cc: stable@kernel.org +Fixes: 3db1de0e582c ("f2fs: change the current atomic write way") +Signed-off-by: Wenjie Qi +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/data.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -3828,6 +3828,7 @@ static int prepare_atomic_write_begin(st + pgoff_t index = folio->index; + int err = 0; + block_t ori_blk_addr = NULL_ADDR; ++ bool cow_has_reserved_block = false; + + /* If pos is beyond the end of file, reserve a new block in COW inode */ + if ((pos & PAGE_MASK) >= i_size_read(inode)) +@@ -3837,9 +3838,11 @@ static int prepare_atomic_write_begin(st + err = __find_data_block(cow_inode, index, blk_addr); + if (err) { + return err; +- } else if (*blk_addr != NULL_ADDR) { ++ } else if (__is_valid_data_blkaddr(*blk_addr)) { + *use_cow = true; + return 0; ++ } else if (*blk_addr == NEW_ADDR) { ++ cow_has_reserved_block = true; + } + + if (is_inode_flag_set(inode, FI_ATOMIC_REPLACE)) +@@ -3852,10 +3855,13 @@ static int prepare_atomic_write_begin(st + + reserve_block: + /* Finally, we should reserve a new block in COW inode for the update */ +- err = __reserve_data_block(cow_inode, index, blk_addr, node_changed); +- if (err) +- return err; +- inc_atomic_write_cnt(inode); ++ if (!cow_has_reserved_block) { ++ err = __reserve_data_block(cow_inode, index, blk_addr, ++ node_changed); ++ if (err) ++ return err; ++ inc_atomic_write_cnt(inode); ++ } + + if (ori_blk_addr != NULL_ADDR) + *blk_addr = ori_blk_addr; diff --git a/queue-7.1/f2fs-pass-correct-iostat-type-for-single-node-writes.patch b/queue-7.1/f2fs-pass-correct-iostat-type-for-single-node-writes.patch new file mode 100644 index 0000000000..fd529650c5 --- /dev/null +++ b/queue-7.1/f2fs-pass-correct-iostat-type-for-single-node-writes.patch @@ -0,0 +1,43 @@ +From fcb05c26c2a67953b420739b85f49386efc9b6c0 Mon Sep 17 00:00:00 2001 +From: Wenjie Qi +Date: Wed, 20 May 2026 20:07:05 +0800 +Subject: f2fs: pass correct iostat type for single node writes + +From: Wenjie Qi + +commit fcb05c26c2a67953b420739b85f49386efc9b6c0 upstream. + +f2fs_write_single_node_folio() takes an io_type argument, but still +passes FS_GC_NODE_IO to __write_node_folio() unconditionally. + +This was harmless while the helper was only used by +f2fs_move_node_folio(), whose caller passes FS_GC_NODE_IO. However, +commit fe9b8b30b971 ("f2fs: fix inline data not being written to disk +in writeback path") made f2fs_inline_data_fiemap() call the helper with +FS_NODE_IO for FIEMAP_FLAG_SYNC. + +Honor the caller supplied io_type so inline-data FIEMAP sync writeback is +accounted as normal node IO instead of GC node IO, while the GC path +continues to pass FS_GC_NODE_IO explicitly. + +Cc: stable@kernel.org +Fixes: fe9b8b30b971 ("f2fs: fix inline data not being written to disk in writeback path") +Signed-off-by: Wenjie Qi +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/node.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/f2fs/node.c ++++ b/fs/f2fs/node.c +@@ -1875,7 +1875,7 @@ int f2fs_write_single_node_folio(struct + } + + if (!__write_node_folio(node_folio, false, false, NULL, +- &wbc, false, FS_GC_NODE_IO, NULL)) ++ &wbc, false, io_type, NULL)) + err = -EAGAIN; + goto release_folio; + out_folio: diff --git a/queue-7.1/f2fs-read-cow-data-with-the-original-inode-during-atomic-write.patch b/queue-7.1/f2fs-read-cow-data-with-the-original-inode-during-atomic-write.patch new file mode 100644 index 0000000000..24812f1d56 --- /dev/null +++ b/queue-7.1/f2fs-read-cow-data-with-the-original-inode-during-atomic-write.patch @@ -0,0 +1,137 @@ +From a41075acde0124d2f8a5f563068a5d63e8ffd57b Mon Sep 17 00:00:00 2001 +From: Mikhail Lobanov +Date: Mon, 15 Jun 2026 14:36:13 +0300 +Subject: f2fs: read COW data with the original inode during atomic write + +From: Mikhail Lobanov + +commit a41075acde0124d2f8a5f563068a5d63e8ffd57b upstream. + +When updating an atomic-write file, f2fs_write_begin() may read the +previously written data back from the COW inode: +prepare_atomic_write_begin() locates the block in the COW inode and sets +use_cow, and the read bio is then built with the COW inode: + + f2fs_submit_page_read(use_cow ? F2FS_I(inode)->cow_inode : inode, + ...); + +and f2fs_grab_read_bio() decides whether to schedule fs-layer decryption +(STEP_DECRYPT) for the bio based on that inode via +fscrypt_inode_uses_fs_layer_crypto(). + +However, the folio being filled belongs to the original inode +(folio->mapping->host == inode), and the data stored in the COW block was +encrypted (or left as plaintext) using the original inode's context, not +the COW inode's -- see f2fs_encrypt_one_page(), which keys off +fio->page->mapping->host. fscrypt_decrypt_pagecache_blocks() likewise +operates on folio->mapping->host. + +The COW inode is created as a tmpfile in the parent directory and inherits +its encryption policy from there. With test_dummy_encryption the newly +created COW inode gets the dummy policy and becomes encrypted, while a +pre-existing regular file -- created before the policy applied, e.g. +already present in the on-disk image -- stays unencrypted. The read +path then sets STEP_DECRYPT based on the encrypted COW inode and calls +fscrypt_decrypt_pagecache_blocks() on a folio whose host (the unencrypted +original inode) has a NULL ->i_crypt_info, dereferencing it: + + Oops: general protection fault, probably for non-canonical address ... + KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] + RIP: 0010:fscrypt_decrypt_pagecache_blocks+0xa0/0x310 + Workqueue: f2fs_post_read_wq f2fs_post_read_work + Call Trace: + fscrypt_decrypt_bio+0x1eb/0x340 + f2fs_post_read_work+0xba/0x140 + process_one_work+0x91c/0x1a40 + worker_thread+0x677/0xe90 + kthread+0x2bc/0x3a0 + +The COW inode is only needed to locate the on-disk block, and that block +address is already resolved into @blkaddr by prepare_atomic_write_begin() +via __find_data_block(cow_inode, ...); f2fs_submit_page_read() then reads +from that physical @blkaddr directly, so the inode argument only selects +the post-read crypto context, not which block is fetched. Reading with +@inode therefore returns the same (latest, not-yet-committed) COW data, +while making both the fs-layer decryption decision and the inline crypto +path use the correct (original inode's) key. + +With the COW inode no longer used at the read site, the use_cow flag has no +remaining consumer; drop it from f2fs_write_begin() and +prepare_atomic_write_begin(). + +Fixes: 591fc34e1f98 ("f2fs: use cow inode data when updating atomic write") +Cc: stable@vger.kernel.org +Signed-off-by: Mikhail Lobanov +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/data.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -3821,7 +3821,7 @@ unlock_out: + + static int prepare_atomic_write_begin(struct f2fs_sb_info *sbi, + struct folio *folio, loff_t pos, unsigned int len, +- block_t *blk_addr, bool *node_changed, bool *use_cow) ++ block_t *blk_addr, bool *node_changed) + { + struct inode *inode = folio->mapping->host; + struct inode *cow_inode = F2FS_I(inode)->cow_inode; +@@ -3836,14 +3836,14 @@ static int prepare_atomic_write_begin(st + + /* Look for the block in COW inode first */ + err = __find_data_block(cow_inode, index, blk_addr); +- if (err) { ++ if (err) + return err; +- } else if (__is_valid_data_blkaddr(*blk_addr)) { +- *use_cow = true; ++ ++ if (__is_valid_data_blkaddr(*blk_addr)) + return 0; +- } else if (*blk_addr == NEW_ADDR) { ++ ++ if (*blk_addr == NEW_ADDR) + cow_has_reserved_block = true; +- } + + if (is_inode_flag_set(inode, FI_ATOMIC_REPLACE)) + goto reserve_block; +@@ -3878,7 +3878,6 @@ static int f2fs_write_begin(const struct + struct folio *folio; + pgoff_t index = pos >> PAGE_SHIFT; + bool need_balance = false; +- bool use_cow = false; + block_t blkaddr = NULL_ADDR; + int err = 0; + +@@ -3941,7 +3940,7 @@ repeat: + + if (f2fs_is_atomic_file(inode)) + err = prepare_atomic_write_begin(sbi, folio, pos, len, +- &blkaddr, &need_balance, &use_cow); ++ &blkaddr, &need_balance); + else + err = prepare_write_begin(sbi, folio, pos, len, + &blkaddr, &need_balance); +@@ -3981,8 +3980,15 @@ repeat: + err = -EFSCORRUPTED; + goto put_folio; + } +- f2fs_submit_page_read(use_cow ? F2FS_I(inode)->cow_inode : +- inode, ++ /* ++ * Although the block may be stored in the COW inode, the folio ++ * belongs to @inode and its data was encrypted (or not) using ++ * @inode's context (see f2fs_encrypt_one_page()). Read with ++ * @inode so the post-read decryption decision matches the ++ * folio's owner; otherwise an unencrypted @inode whose COW inode ++ * is encrypted hits a NULL ->i_crypt_info on decryption. ++ */ ++ f2fs_submit_page_read(inode, + NULL, /* can't write to fsverity files */ + folio, blkaddr, 0, true); + diff --git a/queue-7.1/f2fs-reject-setattr-size-changes-on-large-folio-files.patch b/queue-7.1/f2fs-reject-setattr-size-changes-on-large-folio-files.patch new file mode 100644 index 0000000000..5ea707aa05 --- /dev/null +++ b/queue-7.1/f2fs-reject-setattr-size-changes-on-large-folio-files.patch @@ -0,0 +1,43 @@ +From 242d30bfc0a84b8b5de0a88821b53c9ad7fd31c4 Mon Sep 17 00:00:00 2001 +From: Wenjie Qi +Date: Wed, 10 Jun 2026 22:37:35 +0800 +Subject: f2fs: reject setattr size changes on large folio files + +From: Wenjie Qi + +commit 242d30bfc0a84b8b5de0a88821b53c9ad7fd31c4 upstream. + +F2FS large folios are only enabled for immutable non-compressed files. +Writable open and writable mmap reject such mappings, but truncate(2) +through f2fs_setattr() misses the same guard. + +If FS_IMMUTABLE_FL is cleared while the inode is still cached, the mapping +can keep large-folio support and ATTR_SIZE can change i_size. Reject size +changes in that state. + +Cc: stable@kernel.org +Fixes: 05e65c14ea59 ("f2fs: support large folio for immutable non-compressed case") +Signed-off-by: Wenjie Qi +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/file.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c +index 69aad1060c48..d240ca78a31f 100644 +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -1098,6 +1098,8 @@ int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, + return -EPERM; + + if ((attr->ia_valid & ATTR_SIZE)) { ++ if (mapping_large_folio_support(inode->i_mapping)) ++ return -EOPNOTSUPP; + if (!f2fs_is_compress_backend_ready(inode) || + IS_DEVICE_ALIASING(inode)) + return -EOPNOTSUPP; +-- +2.55.0 + diff --git a/queue-7.1/f2fs-validate-acl-entry-sizes-in-f2fs_acl_from_disk.patch b/queue-7.1/f2fs-validate-acl-entry-sizes-in-f2fs_acl_from_disk.patch new file mode 100644 index 0000000000..2a6b3411d7 --- /dev/null +++ b/queue-7.1/f2fs-validate-acl-entry-sizes-in-f2fs_acl_from_disk.patch @@ -0,0 +1,118 @@ +From c4810ada31e80cbe4011467c4f3b1e93f94134f3 Mon Sep 17 00:00:00 2001 +From: Zhang Cen +Date: Mon, 15 Jun 2026 15:19:54 +0800 +Subject: f2fs: validate ACL entry sizes in f2fs_acl_from_disk() + +From: Zhang Cen + +commit c4810ada31e80cbe4011467c4f3b1e93f94134f3 upstream. + +f2fs_acl_count() only validates the aggregate ACL xattr length. A +malformed ACL can still place ACL_USER or ACL_GROUP in a slot that only +contains struct f2fs_acl_entry_short bytes, and f2fs_acl_from_disk() +then reads entry->e_id before verifying that a full entry fits. + +Require a short entry before reading e_tag and e_perm, and require a +full entry before reading e_id for ACL_USER and ACL_GROUP. Return +-EFSCORRUPTED from these new truncated-entry checks, while keeping the +pre-existing -EINVAL paths unchanged. + +Validation reproduced this kernel report: +KASAN slab-out-of-bounds in __f2fs_get_acl+0x6fb/0x7e0 +RIP: 0033:0x7f4b835ea7aa +The buggy address belongs to the object at ffff888114589960 which belongs +to the cache kmalloc-8 of size 8 +The buggy address is located 0 bytes to the right of allocated 8-byte +region [ffff888114589960, ffff888114589968) +Read of size 4 +Call trace: + dump_stack_lvl+0x66/0xa0 (?:?) + print_report+0xce/0x630 (?:?) + __f2fs_get_acl+0x6fb/0x7e0 (fs/f2fs/acl.c:169) + srso_alias_return_thunk+0x5/0xfbef5 (?:?) + __virt_addr_valid+0x224/0x430 (?:?) + kasan_report+0xe0/0x110 (?:?) + __f2fs_get_acl+0x5/0x7e0 (fs/f2fs/acl.c:169) + __get_acl+0x281/0x380 (?:?) + vfs_get_acl+0x10b/0x190 (?:?) + do_get_acl+0x2a/0x410 (?:?) + do_get_acl+0x9/0x410 (?:?) + do_getxattr+0xe8/0x260 (?:?) + filename_getxattr+0xd1/0x140 (?:?) + do_getname+0x2d/0x2d0 (?:?) + path_getxattrat+0x16c/0x200 (?:?) + lock_release+0xc8/0x290 (?:?) + cgroup_update_frozen+0x9d/0x320 (?:?) + lockdep_hardirqs_on_prepare+0xea/0x1a0 (?:?) + trace_hardirqs_on+0x1a/0x170 (?:?) + _raw_spin_unlock_irq+0x28/0x50 (?:?) + do_syscall_64+0x115/0x6a0 (arch/x86/entry/syscall_64.c:87) + entry_SYSCALL_64_after_hwframe+0x77/0x7f (?:?) + +Cc: stable@kernel.org +Fixes: af48b85b8cd3 ("f2fs: add xattr and acl functionalities") +Assisted-by: Codex:gpt-5.5 +Signed-off-by: Zhang Cen +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/acl.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +--- a/fs/f2fs/acl.c ++++ b/fs/f2fs/acl.c +@@ -47,6 +47,7 @@ static inline int f2fs_acl_count(size_t + static struct posix_acl *f2fs_acl_from_disk(const char *value, size_t size) + { + int i, count; ++ int err = -EINVAL; + struct posix_acl *acl; + struct f2fs_acl_header *hdr = (struct f2fs_acl_header *)value; + struct f2fs_acl_entry *entry = (struct f2fs_acl_entry *)(hdr + 1); +@@ -70,8 +71,11 @@ static struct posix_acl *f2fs_acl_from_d + + for (i = 0; i < count; i++) { + +- if ((char *)entry > end) ++ if (unlikely((char *)entry + ++ sizeof(struct f2fs_acl_entry_short) > end)) { ++ err = -EFSCORRUPTED; + goto fail; ++ } + + acl->a_entries[i].e_tag = le16_to_cpu(entry->e_tag); + acl->a_entries[i].e_perm = le16_to_cpu(entry->e_perm); +@@ -86,6 +90,11 @@ static struct posix_acl *f2fs_acl_from_d + break; + + case ACL_USER: ++ if (unlikely((char *)entry + ++ sizeof(struct f2fs_acl_entry) > end)) { ++ err = -EFSCORRUPTED; ++ goto fail; ++ } + acl->a_entries[i].e_uid = + make_kuid(&init_user_ns, + le32_to_cpu(entry->e_id)); +@@ -93,6 +102,11 @@ static struct posix_acl *f2fs_acl_from_d + sizeof(struct f2fs_acl_entry)); + break; + case ACL_GROUP: ++ if (unlikely((char *)entry + ++ sizeof(struct f2fs_acl_entry) > end)) { ++ err = -EFSCORRUPTED; ++ goto fail; ++ } + acl->a_entries[i].e_gid = + make_kgid(&init_user_ns, + le32_to_cpu(entry->e_id)); +@@ -108,7 +122,7 @@ static struct posix_acl *f2fs_acl_from_d + return acl; + fail: + posix_acl_release(acl); +- return ERR_PTR(-EINVAL); ++ return ERR_PTR(err); + } + + static void *f2fs_acl_to_disk(struct f2fs_sb_info *sbi, diff --git a/queue-7.1/f2fs-validate-compress-cache-inode-only-when-enabled.patch b/queue-7.1/f2fs-validate-compress-cache-inode-only-when-enabled.patch new file mode 100644 index 0000000000..42ea494fe4 --- /dev/null +++ b/queue-7.1/f2fs-validate-compress-cache-inode-only-when-enabled.patch @@ -0,0 +1,53 @@ +From 5073c66a96a9c23c0c2533ed4ed06e42f9021208 Mon Sep 17 00:00:00 2001 +From: Wenjie Qi +Date: Thu, 21 May 2026 11:16:18 +0800 +Subject: f2fs: validate compress cache inode only when enabled + +From: Wenjie Qi + +commit 5073c66a96a9c23c0c2533ed4ed06e42f9021208 upstream. + +F2FS_COMPRESS_INO() uses NM_I(sbi)->max_nid as the synthetic inode +number for the compressed page cache inode. That inode only exists when +the compress_cache mount option is enabled. + +When compress_cache is disabled, max_nid is outside the valid inode +range. A corrupted directory entry that points to ino == max_nid should +therefore be rejected by f2fs_check_nid_range(). However, is_meta_ino() +currently treats F2FS_COMPRESS_INO() as a meta inode unconditionally, +so f2fs_iget() bypasses do_read_inode() and its nid range check, and +instantiates a fake internal inode instead. + +Gate the compressed cache inode case on COMPRESS_CACHE, matching +f2fs_init_compress_inode(). With compress_cache disabled, ino == +max_nid now follows the normal inode path and is rejected as an +out-of-range nid. + +Cc: stable@kernel.org +Fixes: 6ce19aff0b8c ("f2fs: compress: add compress_inode to cache compressed blocks") +Signed-off-by: Wenjie Qi +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/inode.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/fs/f2fs/inode.c ++++ b/fs/f2fs/inode.c +@@ -561,8 +561,13 @@ static int do_read_inode(struct inode *i + + static bool is_meta_ino(struct f2fs_sb_info *sbi, unsigned int ino) + { +- return ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi) || +- ino == F2FS_COMPRESS_INO(sbi); ++ if (ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi)) ++ return true; ++#ifdef CONFIG_F2FS_FS_COMPRESSION ++ if (test_opt(sbi, COMPRESS_CACHE) && ino == F2FS_COMPRESS_INO(sbi)) ++ return true; ++#endif ++ return false; + } + + struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) diff --git a/queue-7.1/f2fs-validate-orphan-inode-entry-count.patch b/queue-7.1/f2fs-validate-orphan-inode-entry-count.patch new file mode 100644 index 0000000000..b33d75c2d9 --- /dev/null +++ b/queue-7.1/f2fs-validate-orphan-inode-entry-count.patch @@ -0,0 +1,75 @@ +From 846c499a65816d13f1186e3090e825e8bb8bcb8b Mon Sep 17 00:00:00 2001 +From: Wenjie Qi +Date: Tue, 26 May 2026 13:35:57 +0800 +Subject: f2fs: validate orphan inode entry count + +From: Wenjie Qi + +commit 846c499a65816d13f1186e3090e825e8bb8bcb8b upstream. + +f2fs_recover_orphan_inodes() trusts the orphan block entry_count when +replaying orphan inodes from the checkpoint pack. A corrupted entry_count +larger than F2FS_ORPHANS_PER_BLOCK makes the recovery loop read past the +ino[] array and interpret footer or following data as inode numbers. + +On a crafted image, mounting an unpatched kernel can drive orphan recovery +into f2fs_bug_on() and panic the kernel. Validate entry_count before +consuming entries so corrupted checkpoint data fails the mount with +-EFSCORRUPTED and requests fsck instead. + +Set ERROR_INCONSISTENT_ORPHAN as well, so the corruption reason can be +recorded in the superblock s_errors[] field. This gives fsck a persistent +hint even though mount-time orphan recovery failure may leave no chance to +persist SBI_NEED_FSCK through a checkpoint. + +Cc: stable@kernel.org +Fixes: 127e670abfa7 ("f2fs: add checkpoint operations") +Signed-off-by: Wenjie Qi +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/checkpoint.c | 14 +++++++++++++- + include/linux/f2fs_fs.h | 1 + + 2 files changed, 14 insertions(+), 1 deletion(-) + +--- a/fs/f2fs/checkpoint.c ++++ b/fs/f2fs/checkpoint.c +@@ -943,6 +943,7 @@ int f2fs_recover_orphan_inodes(struct f2 + for (i = 0; i < orphan_blocks; i++) { + struct folio *folio; + struct f2fs_orphan_block *orphan_blk; ++ unsigned int entry_count; + + folio = f2fs_get_meta_folio(sbi, start_blk + i); + if (IS_ERR(folio)) { +@@ -951,7 +952,18 @@ int f2fs_recover_orphan_inodes(struct f2 + } + + orphan_blk = folio_address(folio); +- for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) { ++ entry_count = le32_to_cpu(orphan_blk->entry_count); ++ if (entry_count > F2FS_ORPHANS_PER_BLOCK) { ++ f2fs_err(sbi, "invalid orphan inode entry count %u", ++ entry_count); ++ set_sbi_flag(sbi, SBI_NEED_FSCK); ++ f2fs_handle_error(sbi, ERROR_INCONSISTENT_ORPHAN); ++ err = -EFSCORRUPTED; ++ f2fs_folio_put(folio, true); ++ goto out; ++ } ++ ++ for (j = 0; j < entry_count; j++) { + nid_t ino = le32_to_cpu(orphan_blk->ino[j]); + + err = recover_orphan_inode(sbi, ino); +--- a/include/linux/f2fs_fs.h ++++ b/include/linux/f2fs_fs.h +@@ -107,6 +107,7 @@ enum f2fs_error { + ERROR_CORRUPTED_XATTR, + ERROR_INVALID_NODE_REFERENCE, + ERROR_INCONSISTENT_NAT, ++ ERROR_INCONSISTENT_ORPHAN, + ERROR_MAX, + }; + diff --git a/queue-7.1/kvm-replace-guest-triggerable-bug_on-in-ioeventfd-datamatch-with-get_unaligned.patch b/queue-7.1/kvm-replace-guest-triggerable-bug_on-in-ioeventfd-datamatch-with-get_unaligned.patch new file mode 100644 index 0000000000..6ae2aaab04 --- /dev/null +++ b/queue-7.1/kvm-replace-guest-triggerable-bug_on-in-ioeventfd-datamatch-with-get_unaligned.patch @@ -0,0 +1,116 @@ +From f1edbed787ba67988ed34e0132ca128b052b6ce8 Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Fri, 12 Jun 2026 15:52:41 -0700 +Subject: KVM: Replace guest-triggerable BUG_ON() in ioeventfd datamatch with get_unaligned() + +From: Sean Christopherson + +commit f1edbed787ba67988ed34e0132ca128b052b6ce8 upstream. + +Drop a BUG_ON() that has been reachable since it was first added, way back +in 2009, and instead use get_unaligned() to perform potentially-unaligned +accesses. + +For a given store, KVM x86's emulator tracks the entire value in the +destination operand, x86_emulate_ctxt.dst. If the destination is memory, +and the target splits multiple pages and/or is emulated MMIO, then KVM +handles each fragment independently. E.g. on a page split starting at page +offset 0xffc, KVM writes 4 bytes to the first page, then the remaining +bytes to the second page, using ctxt->dst as the source for both (with +appropriate offsets). + +If the destination splits a page *and* hits emulated MMIO on the second +page, then KVM will complete the write to the first page, then emulate the +MMIO access to the second page. If there is a datamatch-enabled ioeventfd +at offset 0 of the second page, then KVM will process the remainder of the +store as a potential ioeventfd signal. + +Putting it all together, if the guest emits a store that splits a page +starting at page offset N, and the second page has a datamatch-enabled +ioeventfd at offset 0, then KVM will check for datamatch using +&dst.valptr[N] as the source. Due to dst (and thus dst.valptr) being +32-byte aligned, if N is not aligned to @len, the BUG_ON() fires. + +E.g. with a 16-byte store at page offset 0xffc, to an ioeventfd of len 8, +all initial checks in ioeventfd_in_range() will succeed, and the BUG_ON() +fires due to @val being 4-byte aligned, but not 8-byte aligned. + + ------------[ cut here ]------------ + kernel BUG at arch/x86/kvm/../../../virt/kvm/eventfd.c:783! + Oops: invalid opcode: 0000 [#1] SMP + CPU: 0 UID: 1000 PID: 615 Comm: repro Not tainted 7.1.0-rc2-ff238429d1ea #365 PREEMPT + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 + RIP: 0010:ioeventfd_write+0x6c/0x70 [kvm] + Call Trace: + + __kvm_io_bus_write+0x85/0xb0 [kvm] + kvm_io_bus_write+0x53/0x80 [kvm] + vcpu_mmio_write+0x66/0xf0 [kvm] + emulator_read_write_onepage+0x12a/0x540 [kvm] + emulator_read_write+0x109/0x2b0 [kvm] + x86_emulate_insn+0x4f8/0xfb0 [kvm] + x86_emulate_instruction+0x181/0x790 [kvm] + kvm_mmu_page_fault+0x313/0x630 [kvm] + vmx_handle_exit+0x18a/0x590 [kvm_intel] + kvm_arch_vcpu_ioctl_run+0xc81/0x1c90 [kvm] + kvm_vcpu_ioctl+0x2d5/0x970 [kvm] + __x64_sys_ioctl+0x8a/0xd0 + do_syscall_64+0xb7/0x890 + entry_SYSCALL_64_after_hwframe+0x4b/0x53 + RIP: 0033:0x7f19c931a9bf + + Modules linked in: kvm_intel kvm irqbypass + ---[ end trace 0000000000000000 ]--- + +In a perfect world, the fix would be to simply delete the BUG_ON(), as KVM +x86 doesn't perform alignment checks on "normal" memory accesses at CPL0. +Sadly, C99 ruins all the fun; while the x86 architecture plays nice, +dereferencing an unaligned pointer directly is undefined behavior in C, +e.g. triggers splats when running with CONFIG_UBSAN_ALIGNMENT=y. + +Fixes: d34e6b175e61 ("KVM: add ioeventfd support") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Message-ID: <20260612225241.678509-1-seanjc@google.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + virt/kvm/eventfd.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +--- a/virt/kvm/eventfd.c ++++ b/virt/kvm/eventfd.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -779,21 +780,18 @@ ioeventfd_in_range(struct _ioeventfd *p, + return true; + + /* otherwise, we have to actually compare the data */ +- +- BUG_ON(!IS_ALIGNED((unsigned long)val, len)); +- + switch (len) { + case 1: +- _val = *(u8 *)val; ++ _val = get_unaligned((u8 *)val); + break; + case 2: +- _val = *(u16 *)val; ++ _val = get_unaligned((u16 *)val); + break; + case 4: +- _val = *(u32 *)val; ++ _val = get_unaligned((u32 *)val); + break; + case 8: +- _val = *(u64 *)val; ++ _val = get_unaligned((u64 *)val); + break; + default: + return false; diff --git a/queue-7.1/kvm-x86-mmu-ensure-hugepage-is-in-by-slot-before-checking-max-mapping-level.patch b/queue-7.1/kvm-x86-mmu-ensure-hugepage-is-in-by-slot-before-checking-max-mapping-level.patch new file mode 100644 index 0000000000..de0f6230b2 --- /dev/null +++ b/queue-7.1/kvm-x86-mmu-ensure-hugepage-is-in-by-slot-before-checking-max-mapping-level.patch @@ -0,0 +1,128 @@ +From ef057cbf825e03b63f6edf5980f96abf3c53089d Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Wed, 29 Apr 2026 09:34:01 -0700 +Subject: KVM: x86/mmu: Ensure hugepage is in by slot before checking max mapping level + +From: Sean Christopherson + +commit ef057cbf825e03b63f6edf5980f96abf3c53089d upstream. + +When recovering hugepages in the shadow MMU, verify that the base gfn of +the shadow page is actually contained within the target memslot, *before* +querying the max mapping level given the shadow page's gfn. Failure to +pre-check the validity of the gfn can lead to an out-of-bounds access to +the slot's lpage_info (which typically manifests as a host #PF because the +lpage_info is vmalloc'd) if the guest creates a hugepage mapping (in its +PTEs) that extends "below" the bounds of a memslot. + +When faulting in memory for a guest, and the size of the guest mapping is +greater than KVM's (current) max mapping, then KVM will create a "direct" +shadow page (direct in that there are no gPTEs to shadow, and so the target +gfn is a direct calculation given the base gfn of the shadow page). The +hugepage recovery flow looks for such direct shadow pages, as forcing 4KiB +mappings when dirty logging generates the guest > host mapping size case. +When the 4KiB restriction is lifted, then KVM can replace the shadow page +with a hugepage. + +But if KVM originally used a smaller mapping than the guest because the +range of memory covered by the guest hugepage exceeds the bounds of a +memslot, then KVM will link a direct shadow page with a gfn that is outside +the bounds of the memslot being used to fault in memory. The rmap entry +added for the leaf mapping is correct and within bounds, but the gfn of the +leaf SPTE's parent shadow page will be out of bounds. + + BUG: unable to handle page fault for address: ffffc90000806ffc + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + PGD 100000067 P4D 100000067 PUD 1002a7067 PMD 10612f067 PTE 0 + Oops: Oops: 0000 [#1] SMP + CPU: 13 UID: 1000 PID: 757 Comm: mmu_stress_test Not tainted 7.1.0-rc1-48ce1e26eace-x86_pir_to_irr_comments-vm #341 PREEMPT + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 + RIP: 0010:kvm_mmu_max_mapping_level+0x79/0x2b0 [kvm] + Call Trace: + + kvm_mmu_recover_huge_pages+0x21b/0x320 [kvm] + kvm_set_memslot+0x1ee/0x590 [kvm] + kvm_set_memory_region.part.0+0x3a1/0x4d0 [kvm] + kvm_vm_ioctl+0x9bf/0x15d0 [kvm] + __x64_sys_ioctl+0x8a/0xd0 + do_syscall_64+0xb7/0xbb0 + entry_SYSCALL_64_after_hwframe+0x4b/0x53 + RIP: 0033:0x7f21c0f1a9bf + + +Don't bother pre-checking the bounds of the potential hugepage, i.e. don't +check that e.g. sp->gfn + KVM_PAGES_PER_HPAGE(sp->role.level + 1) is also +within the memslot, as the checks performed by kvm_mmu_max_mapping_level() +are a superset of the basic bounds checks. I.e. pre-checking the full +range would be a dubious micro-optimization. + +Fixes: 9eba50f8d7fc ("KVM: x86/mmu: Consult max mapping level when zapping collapsible SPTEs") +Cc: stable@vger.kernel.org +Cc: David Matlack +Cc: James Houghton +Cc: Alexander Bulekov +Cc: Fred Griffoul +Cc: Alexander Graf +Cc: David Woodhouse +Cc: Filippo Sironi +Cc: Ivan Orlov +Signed-off-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/mmu/mmu.c | 18 ++++++++++++------ + include/linux/kvm_host.h | 7 ++++++- + 2 files changed, 18 insertions(+), 7 deletions(-) + +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -7288,13 +7288,19 @@ restart: + sp = sptep_to_sp(sptep); + + /* +- * We cannot do huge page mapping for indirect shadow pages, +- * which are found on the last rmap (level = 1) when not using +- * tdp; such shadow pages are synced with the page table in +- * the guest, and the guest page table is using 4K page size +- * mapping if the indirect sp has level = 1. ++ * Direct shadow page can be replaced by a hugepage if the host ++ * mapping level allows it and the memslot maps all of the host ++ * hugepage. Note! If the memslot maps only part of the ++ * hugepage, sp->gfn may be below slot->base_gfn, and querying ++ * the max mapping level would cause an out-of-bounds lpage_info ++ * access. So the gfn bounds check *must* be done first. ++ * ++ * Indirect shadow pages are created when the guest page tables ++ * are using 4K pages. Since the host mapping is always ++ * constrained by the page size in the guest, indirect shadow ++ * pages are never collapsible. + */ +- if (sp->role.direct && ++ if (sp->role.direct && is_gfn_in_memslot(slot, sp->gfn) && + sp->role.level < kvm_mmu_max_mapping_level(kvm, NULL, slot, sp->gfn)) { + kvm_zap_one_rmap_spte(kvm, rmap_head, sptep); + +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -1815,6 +1815,11 @@ void kvm_unregister_irq_ack_notifier(str + struct kvm_irq_ack_notifier *kian); + bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args); + ++static inline bool is_gfn_in_memslot(const struct kvm_memory_slot *slot, gfn_t gfn) ++{ ++ return gfn >= slot->base_gfn && gfn < slot->base_gfn + slot->npages; ++} ++ + /* + * Returns a pointer to the memslot if it contains gfn. + * Otherwise returns NULL. +@@ -1825,7 +1830,7 @@ try_get_memslot(struct kvm_memory_slot * + if (!slot) + return NULL; + +- if (gfn >= slot->base_gfn && gfn < slot->base_gfn + slot->npages) ++ if (is_gfn_in_memslot(slot, gfn)) + return slot; + else + return NULL; diff --git a/queue-7.1/mips-dec-prevent-initial-console-buffer-from-landing-in-xkphys.patch b/queue-7.1/mips-dec-prevent-initial-console-buffer-from-landing-in-xkphys.patch new file mode 100644 index 0000000000..92f4cdabfd --- /dev/null +++ b/queue-7.1/mips-dec-prevent-initial-console-buffer-from-landing-in-xkphys.patch @@ -0,0 +1,116 @@ +From 7fb13fd35110ebe95eb053faf79d018f51144d85 Mon Sep 17 00:00:00 2001 +From: "Maciej W. Rozycki" +Date: Wed, 6 May 2026 23:42:27 +0100 +Subject: MIPS: DEC: Prevent initial console buffer from landing in XKPHYS + +From: Maciej W. Rozycki + +commit 7fb13fd35110ebe95eb053faf79d018f51144d85 upstream. + +In 64-bit configurations calling the initial console output handler from +a kernel thread other than the initial one will result in a situation +where the stack has been placed in the XKPHYS 64-bit memory segment and +consequently so has been the buffer allocated there that is used as the +argument corresponding to the `%s' output conversion specifier for the +firmware's printf() entry point. + +This 64-bit address will then be truncated by 32-bit firmware, resulting +in an attempt to access the wrong memory location, which in turn will +cause all kinds of unpredictable behaviour, such as a kernel crash: + + Console: colour dummy device 160x64 + Calibrating delay loop... 49.36 BogoMIPS (lpj=192512) + pid_max: default: 32768 minimum: 301 + CPU 0 Unable to handle kernel paging request at virtual address 000000000203bd00, epc == ffffffffbfc08364, ra == ffffffffbfc08800 + Oops[#1]: + CPU: 0 PID: 0 Comm: swapper Not tainted 5.18.0-rc2-00254-gfb649bda6f56-dirty #121 + $ 0 : 0000000000000000 0000000000000001 0000000000000023 ffffffff80684ba0 + $ 4 : 000000000203bd00 ffffffffbfc0f3b4 ffffffffffffffff 0000000000000073 + $ 8 : 0a303d7469000000 0000000000000000 0000000000000073 ffffffffbfc0f473 + $12 : 0000000000000002 0000000000000000 ffffffff80684c1c 0000000000000000 + $16 : 0000000000000000 ffffffff80596dc9 0000000000000000 ffffffffbfc09240 + $20 : ffffffff80684c40 ffffffffbfc0f400 000000000000002d 000000000000002b + $24 : ffffffffffffffbf 000000000203bd00 + $28 : ffffffff805f0000 ffffffff80684b58 0000000000000030 ffffffffbfc08800 + Hi : 0000000000000000 + Lo : 0000000000000aa8 + epc : ffffffffbfc08364 0xffffffffbfc08364 + ra : ffffffffbfc08800 0xffffffffbfc08800 + Status: 140120e2 KX SX UX KERNEL EXL + Cause : 00000008 (ExcCode 02) + BadVA : 000000000203bd00 + PrId : 00000430 (R4000SC) + Modules linked in: + Process swapper (pid: 0, threadinfo=(____ptrval____), task=(____ptrval____), tls=0000000000000000) + Stack : 0000000000000000 0000000000000000 0000000000000000 0000004d0000004d + 80684cc0806a2a40 80596dc80000004d 8061000000000000 bfc0850c80684c38 + 0000000000000000 000000000203bd00 0000000000000000 0000000000000000 + 0000000000000000 00000000bfc0f3b4 0000000000000000 0000000000000000 + 0000000000000000 0000000000000000 0000000000000000 0000000000000000 + 0000000000000000 0000000000000000 0000000000000000 0000000000000000 + 0000002500000000 0000000000000000 0000000000000000 802c1a7400000000 + 0203bd0080596dc8 0203bd4d69000000 6c61632000000018 5f746567646e6172 + 6c616320625f6d6f 5f736e5f6d6f7266 206361323778302b 303d74696e726320 + 806a0a38806b0000 806a0a38806b0000 00000000806b0000 80683c58806b0000 + ... + Call Trace: + + Code: a082ffff 03e00008 00601021 <80820000> 00001821 10400005 24840001 80820000 24630001 + + ---[ end trace 0000000000000000 ]--- + Kernel panic - not syncing: Fatal exception in interrupt + + KN04 V2.1k (PC: 0xa0026768, SP: 0x806848e8) + >> + +In this case the pointer in $4 was truncated from 0x980000000203bd00 to +0x000000000203bd00. + +This may happen when no final console driver has been enabled in the +configuration and consequently the initial console continues being used +late into bootstrap or with an upcoming change that will switch the zs +driver to use a platform device, which in turn will make the console +handover happen only after other kernel threads have already been +started. + +Fix the issue by making the buffer static and initdata, and therefore +placed in the CKSEG0 32-bit compatibility segment, observing that the +console output handler is called with the console lock held, implying +no need for this code to be reentrant. Add an assertion to verify the +buffer actually has been placed in a compatibility segment. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Maciej W. Rozycki +Cc: stable@vger.kernel.org # v2.6.12+ +Signed-off-by: Thomas Bogendoerfer +Signed-off-by: Greg Kroah-Hartman +--- + arch/mips/dec/prom/console.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/arch/mips/dec/prom/console.c ++++ b/arch/mips/dec/prom/console.c +@@ -2,8 +2,9 @@ + /* + * DECstation PROM-based early console support. + * +- * Copyright (C) 2004, 2007 Maciej W. Rozycki ++ * Copyright (C) 2004, 2007, 2026 Maciej W. Rozycki + */ ++#include + #include + #include + #include +@@ -14,9 +15,11 @@ + static void __init prom_console_write(struct console *con, const char *s, + unsigned int c) + { +- char buf[81]; ++ static char buf[81] __initdata = { 0 }; + unsigned int chunk = sizeof(buf) - 1; + ++ BUG_ON((long)buf != (int)(long)buf); ++ + while (c > 0) { + if (chunk > c) + chunk = c; diff --git a/queue-7.1/revert-f2fs-remove-non-uptodate-folio-from-the-page-cache-in-move_data_block.patch b/queue-7.1/revert-f2fs-remove-non-uptodate-folio-from-the-page-cache-in-move_data_block.patch new file mode 100644 index 0000000000..6b156e36f5 --- /dev/null +++ b/queue-7.1/revert-f2fs-remove-non-uptodate-folio-from-the-page-cache-in-move_data_block.patch @@ -0,0 +1,152 @@ +From ccaba785821970f422c47770331c7e3271763f17 Mon Sep 17 00:00:00 2001 +From: Zhaoyang Huang +Date: Mon, 8 Jun 2026 17:09:39 +0800 +Subject: Revert "f2fs: remove non-uptodate folio from the page cache in move_data_block" + +From: Zhaoyang Huang + +commit ccaba785821970f422c47770331c7e3271763f17 upstream. + +This reverts commit 9609dd704725a40cd63d915f2ab6c44248a44598. + +The kernel panics are keeping to be reported especially when the f2fs +partition get almost full. By investigation, we find that the reason is +one f2fs page got freed to buddy without being deleted from LRU and the +root cause is the race happened in [2] which is enrolled by this commit. + +There are 3 race processes in this scenario, please find below for their +main activities. + +The changed code in move_data_block() lets the GC path evict the tail-end +folio from the page cache through folio_end_dropbehind(). Once +folio_unmap_invalidate() removes the folio from mapping->i_pages, the +page-cache references for all pages in the folio are dropped. The folio +is then kept alive only by temporary external references, which allows a +later split to operate on a folio whose subpages are no longer protected +by page-cache references. + +After the page-cache references are gone, split_folio_to_order() can +split the big folio into individual pages and put the resulting subpages +back on the LRU. For tail pages beyond EOF, split removes them from the +page cache and drops their page-cache references. A tail page can then +remain on the LRU with PG_lru set while holding only the split caller's +temporary reference. When free_folio_and_swap_cache() drops that final +reference, the page enters the final folio_put() release path. + +In parallel, folio_isolate_lru() can observe the same tail page with a +non-zero refcount and PG_lru set. It clears PG_lru before taking its own +reference. If this races with the final folio_put() from the split path, +__folio_put() sees PG_lru already cleared and skips lruvec_del_folio(). +The page is then freed back to the allocator while its lru links are +still present in the LRU list. A later LRU operation on a neighboring +page detects the stale link and reports list corruption. + +[1] +[ 22.486082] list_del corruption. next->prev should be fffffffec10e0ac8, but was dead000000000122. (next=fffffffec10e0a88) +[ 22.486130] ------------[ cut here ]------------ +[ 22.486134] kernel BUG at lib/list_debug.c:67! +[ 22.486141] Internal error: Oops - BUG: 00000000f2000800 [#1] SMP +[ 22.488502] Tainted: [W]=WARN, [O]=OOT_MODULE +[ 22.488506] Hardware name: Spreadtrum UMS9230 1H10 SoC (DT) +[ 22.488511] pstate: 604000c5 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--) +[ 22.488517] pc : __list_del_entry_valid_or_report+0x14c/0x154 +[ 22.488531] lr : __list_del_entry_valid_or_report+0x14c/0x154 +[ 22.488539] sp : ffffffc08006b830 +[ 22.488542] x29: ffffffc08006b868 x28: 0000000000003020 x27: 0000000000000000 +[ 22.488553] x26: 0000000000000000 x25: 0000000000000004 x24: fffffffec10e0ac0 +[ 22.488564] x23: 00000000000000e8 x22: 0000000000000024 x21: dead000000000122 +[ 22.488574] x20: fffffffec10e0a88 x19: fffffffec10e0ac8 x18: ffffffc080061060 +[ 22.488585] x17: 20747562202c3863 x16: 6130653031636566 x15: 0000000000000058 +[ 22.488595] x14: 0000000000000004 x13: ffffff80f91e0000 x12: 0000000000000003 +[ 22.488605] x11: 0000000000000003 x10: 0000000000000001 x9 : ffe85721f0e25f00 +[ 22.488615] x8 : ffe85721f0e25f00 x7 : 0000000000000000 x6 : 6c65645f7473696c +[ 22.488625] x5 : ffffffed39b23026 x4 : 0000000000000000 x3 : 0000000000000010 +[ 22.488636] x2 : 0000000000000000 x1 : 0000000000000000 x0 : 000000000000006d +[ 22.488647] Call trace: +[ 22.488651] __list_del_entry_valid_or_report+0x14c/0x154 (P) +[ 22.488661] __folio_put+0x2bc/0x434 +[ 22.488670] folio_put+0x28/0x58 +[ 22.488678] do_garbage_collect+0x1a34/0x2584 +[ 22.488689] f2fs_gc+0x230/0x9b4 +[ 22.488697] f2fs_fallocate+0xb90/0xdf4 +[ 22.488706] vfs_fallocate+0x1b4/0x2bc +[ 22.488716] __arm64_sys_fallocate+0x44/0x78 +[ 22.488725] invoke_syscall+0x58/0xe4 +[ 22.488732] do_el0_svc+0x48/0xdc +[ 22.488739] el0_svc+0x3c/0x98 +[ 22.488747] el0t_64_sync_handler+0x20/0x130 +[ 22.488754] el0t_64_sync+0x1c4/0x1c8 + +[2] +CPU0 (f2fs GC) CPU1 (split_folio_to_order) CPU2 (folio_isolate_lru) + +F: pagecache refs = n +F: extra refs = GC + split +F: PG_lru set +move_data_block() +folio = f2fs_grab_cache_folio(F) +... +__folio_set_dropbehind(F) +folio_unlock(F) +folio_end_dropbehind(F) + folio_unmap_invalidate(F) + __filemap_remove_folio(F) + folio_put_refs(F, n) +folio_put(F) + split_folio_to_order(F) + folio_ref_freeze(F, 1) + ... + lru_add_split_folio(T) + list_add_tail(&T->lru, &F->lru) + folio_set_lru(T) + __filemap_remove_folio(T) + folio_put_refs(T, 1) + /* T refcount == 1, PageLRU set */ + folio_isolate_lru(T) + folio_test_clear_lru(T) + free_folio_and_swap_cache(T) + folio_put(T) + /* refcount: 1 -> 0 */ + __folio_put(T) + __page_cache_release(T) + folio_test_lru(T) == false + /* skip lruvec_del_folio(T) */ + free_frozen_pages(T) + folio_get(T) + lruvec_del_folio(T) +later: + list_del(adjacent->lru) + next == &T->lru + next->prev == LIST_POISON / PCP freelist + BUG + +Cc: stable@vger.kernel.org +Fixes: 9609dd704725 ("f2fs: remove non-uptodate folio from the page cache in move_data_block") +Signed-off-by: Zhaoyang Huang +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/gc.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 69e0a867219d..56a1c0547d76 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -1499,11 +1499,7 @@ static int move_data_block(struct inode *inode, block_t bidx, + put_out: + f2fs_put_dnode(&dn); + out: +- if (!folio_test_uptodate(folio)) +- __folio_set_dropbehind(folio); +- folio_unlock(folio); +- folio_end_dropbehind(folio); +- folio_put(folio); ++ f2fs_folio_put(folio, true); + out_iput: + if (atomic_inode) + iput(atomic_inode); +-- +2.55.0 + diff --git a/queue-7.1/series b/queue-7.1/series index 11eda06db6..5b7049de95 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -56,3 +56,24 @@ wifi-rtw88-usb-fix-memory-leaks-on-usb-write-failures.patch wifi-iwlwifi-mvm-fix-race-condition-in-ptp-removal.patch wifi-iwlwifi-mld-fix-race-condition-in-ptp-removal.patch wifi-iwlwifi-mld-validate-sta_mask-before-ffs-in-ba-session-handlers.patch +f2fs-fix-missing-read-bio-submission-on-large-folio-error.patch +f2fs-pass-correct-iostat-type-for-single-node-writes.patch +f2fs-reject-setattr-size-changes-on-large-folio-files.patch +f2fs-fix-to-do-sanity-check-on-f2fs_get_node_folio_ra.patch +f2fs-validate-orphan-inode-entry-count.patch +f2fs-validate-compress-cache-inode-only-when-enabled.patch +f2fs-atomic-fix-uaf-issue-on-f2fs_inode_info.atomic_inode.patch +f2fs-fix-to-round-down-start-offset-of-fallocate-for-pin-file.patch +f2fs-bound-i_inline_xattr_size-for-non-inline-xattr-inodes.patch +f2fs-validate-acl-entry-sizes-in-f2fs_acl_from_disk.patch +revert-f2fs-remove-non-uptodate-folio-from-the-page-cache-in-move_data_block.patch +f2fs-fix-incorrect-fi_no_extent-handling-in-__destroy_extent_node.patch +f2fs-keep-atomic-write-retry-from-zeroing-original-data.patch +f2fs-read-cow-data-with-the-original-inode-during-atomic-write.patch +block-avoid-mounting-the-bdev-pseudo-filesystem-in-userspace.patch +bpf-use-kvfree-for-replaced-sysctl-write-buffer.patch +mips-dec-prevent-initial-console-buffer-from-landing-in-xkphys.patch +exfat-fix-potential-use-after-free-in-exfat_find_dir_entry.patch +kvm-x86-mmu-ensure-hugepage-is-in-by-slot-before-checking-max-mapping-level.patch +kvm-replace-guest-triggerable-bug_on-in-ioeventfd-datamatch-with-get_unaligned.patch +crypto-nx-fix-nx_crypto_ctx_exit-argument.patch