From: Greg Kroah-Hartman Date: Thu, 8 Jan 2026 11:13:02 +0000 (+0100) Subject: 6.6-stable patches X-Git-Tag: v6.1.160~53 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f29f530fd5cefc045e8bb9e59a135f2c8d17ca8;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches added patches: ext4-fix-error-message-when-rejecting-the-default-hash.patch ext4-fix-out-of-bound-read-in-ext4_xattr_inode_dec_ref_all.patch ext4-introduce-itail-helper.patch f2fs-drop-inode-from-the-donation-list-when-the-last-file-is-closed.patch f2fs-fix-to-avoid-updating-compression-context-during-writeback.patch f2fs-fix-to-detect-recoverable-inode-during-dryrun-of-find_fsync_dnodes.patch f2fs-fix-to-propagate-error-from-f2fs_enable_checkpoint.patch f2fs-keep-posix_fadv_noreuse-ranges.patch f2fs-remove-unused-gc_failure_pin.patch f2fs-use-global-inline_xattr_slab-instead-of-per-sb-slab-cache.patch genirq-irq_sim-initialize-work-context-pointers-properly.patch kvm-nvmx-immediately-refresh-apicv-controls-as-needed-on-nested-vm-exit.patch media-amphion-add-a-frame-flush-mode-for-decoder.patch media-amphion-make-some-vpu_v4l2-functions-static.patch media-amphion-remove-vpu_vb_is_codecconfig.patch media-mediatek-vcodec-use-spinlock-for-context-list-protection-lock.patch media-verisilicon-fix-cpu-stalls-on-g2-bus-error.patch media-verisilicon-g2-use-common-helpers-to-compute-chroma-and-mv-offsets.patch media-verisilicon-store-chroma-and-motion-vectors-offset.patch mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch mm-fix-arithmetic-for-bdi-min_ratio.patch mm-fix-arithmetic-for-max_prop_frac-when-setting-max_ratio.patch net-dsa-sja1105-fix-kasan-out-of-bounds-warning-in-sja1105_table_delete_entry.patch page_pool-fix-use-after-free-in-page_pool_recycle_in_ring.patch powerpc-64s-radix-kfence-map-__kfence_pool-at-page-granularity.patch powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch xfrm-state-fix-out-of-bounds-read-during-lookup.patch --- diff --git a/queue-6.6/ext4-fix-error-message-when-rejecting-the-default-hash.patch b/queue-6.6/ext4-fix-error-message-when-rejecting-the-default-hash.patch new file mode 100644 index 0000000000..e7f0c9645e --- /dev/null +++ b/queue-6.6/ext4-fix-error-message-when-rejecting-the-default-hash.patch @@ -0,0 +1,95 @@ +From stable+bounces-201041-greg=kroah.com@vger.kernel.org Mon Dec 15 14:40:38 2025 +From: Ankan Biswas +Date: Mon, 15 Dec 2025 19:09:57 +0530 +Subject: ext4: fix error message when rejecting the default hash +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, sashal@kernel.org, tytso@mit.edu, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org, skhan@linuxfoundation.org, khalid@kernel.org, david.hunter.linux@gmail.com, linux-kernel-mentees@vger.kernel.org, Gabriel Krisman Bertazi , Ankan Biswas +Message-ID: <20251215133957.4236-1-spyjetfayed@gmail.com> + +From: Gabriel Krisman Bertazi + +[ Upstream commit a2187431c395cdfbf144e3536f25468c64fc7cfa ] + +Commit 985b67cd8639 ("ext4: filesystems without casefold feature cannot +be mounted with siphash") properly rejects volumes where +s_def_hash_version is set to DX_HASH_SIPHASH, but the check and the +error message should not look into casefold setup - a filesystem should +never have DX_HASH_SIPHASH as the default hash. Fix it and, since we +are there, move the check to ext4_hash_info_init. + +Fixes:985b67cd8639 ("ext4: filesystems without casefold feature cannot +be mounted with siphash") + +Signed-off-by: Gabriel Krisman Bertazi +Link: https://patch.msgid.link/87jzg1en6j.fsf_-_@mailhost.krisman.be +Signed-off-by: Theodore Ts'o +[ The commit a2187431c395 intended to remove the if-block which was used + for an old SIPHASH rejection check. ] +Signed-off-by: Ankan Biswas +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/ext4.h | 1 + + fs/ext4/super.c | 20 +++++++++++++++++--- + 2 files changed, 18 insertions(+), 3 deletions(-) + +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -2459,6 +2459,7 @@ static inline __le16 ext4_rec_len_to_dis + #define DX_HASH_HALF_MD4_UNSIGNED 4 + #define DX_HASH_TEA_UNSIGNED 5 + #define DX_HASH_SIPHASH 6 ++#define DX_HASH_LAST DX_HASH_SIPHASH + + static inline u32 ext4_chksum(struct ext4_sb_info *sbi, u32 crc, + const void *address, unsigned int length) +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -5140,16 +5140,27 @@ out: + return ret; + } + +-static void ext4_hash_info_init(struct super_block *sb) ++static int ext4_hash_info_init(struct super_block *sb) + { + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_super_block *es = sbi->s_es; + unsigned int i; + ++ sbi->s_def_hash_version = es->s_def_hash_version; ++ ++ if (sbi->s_def_hash_version > DX_HASH_LAST) { ++ ext4_msg(sb, KERN_ERR, ++ "Invalid default hash set in the superblock"); ++ return -EINVAL; ++ } else if (sbi->s_def_hash_version == DX_HASH_SIPHASH) { ++ ext4_msg(sb, KERN_ERR, ++ "SIPHASH is not a valid default hash value"); ++ return -EINVAL; ++ } ++ + for (i = 0; i < 4; i++) + sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); + +- sbi->s_def_hash_version = es->s_def_hash_version; + if (ext4_has_feature_dir_index(sb)) { + i = le32_to_cpu(es->s_flags); + if (i & EXT2_FLAGS_UNSIGNED_HASH) +@@ -5167,6 +5178,7 @@ static void ext4_hash_info_init(struct s + #endif + } + } ++ return 0; + } + + static int ext4_block_group_meta_init(struct super_block *sb, int silent) +@@ -5311,7 +5323,9 @@ static int __ext4_fill_super(struct fs_c + if (err) + goto failed_mount; + +- ext4_hash_info_init(sb); ++ err = ext4_hash_info_init(sb); ++ if (err) ++ goto failed_mount; + + err = ext4_handle_clustersize(sb); + if (err) diff --git a/queue-6.6/ext4-fix-out-of-bound-read-in-ext4_xattr_inode_dec_ref_all.patch b/queue-6.6/ext4-fix-out-of-bound-read-in-ext4_xattr_inode_dec_ref_all.patch new file mode 100644 index 0000000000..8bb0be77e4 --- /dev/null +++ b/queue-6.6/ext4-fix-out-of-bound-read-in-ext4_xattr_inode_dec_ref_all.patch @@ -0,0 +1,194 @@ +From stable+bounces-201009-greg=kroah.com@vger.kernel.org Mon Dec 15 09:56:30 2025 +From: "David Nyström" +Date: Mon, 15 Dec 2025 09:52:57 +0100 +Subject: ext4: fix out-of-bound read in ext4_xattr_inode_dec_ref_all() +To: stable@vger.kernel.org +Cc: "Andreas Dilger" , "James Simmons" , "Ye Bin" , "David Nyström" , "Jan Kara" , "Theodore Ts'o" +Message-ID: <20251215-cve-2025-22121-v1-2-283f77b33397@est.tech> + +From: Ye Bin + +[ Upstream commit 5701875f9609b000d91351eaa6bfd97fe2f157f4 ] + +There's issue as follows: +BUG: KASAN: use-after-free in ext4_xattr_inode_dec_ref_all+0x6ff/0x790 +Read of size 4 at addr ffff88807b003000 by task syz-executor.0/15172 + +CPU: 3 PID: 15172 Comm: syz-executor.0 +Call Trace: + __dump_stack lib/dump_stack.c:82 [inline] + dump_stack+0xbe/0xfd lib/dump_stack.c:123 + print_address_description.constprop.0+0x1e/0x280 mm/kasan/report.c:400 + __kasan_report.cold+0x6c/0x84 mm/kasan/report.c:560 + kasan_report+0x3a/0x50 mm/kasan/report.c:585 + ext4_xattr_inode_dec_ref_all+0x6ff/0x790 fs/ext4/xattr.c:1137 + ext4_xattr_delete_inode+0x4c7/0xda0 fs/ext4/xattr.c:2896 + ext4_evict_inode+0xb3b/0x1670 fs/ext4/inode.c:323 + evict+0x39f/0x880 fs/inode.c:622 + iput_final fs/inode.c:1746 [inline] + iput fs/inode.c:1772 [inline] + iput+0x525/0x6c0 fs/inode.c:1758 + ext4_orphan_cleanup fs/ext4/super.c:3298 [inline] + ext4_fill_super+0x8c57/0xba40 fs/ext4/super.c:5300 + mount_bdev+0x355/0x410 fs/super.c:1446 + legacy_get_tree+0xfe/0x220 fs/fs_context.c:611 + vfs_get_tree+0x8d/0x2f0 fs/super.c:1576 + do_new_mount fs/namespace.c:2983 [inline] + path_mount+0x119a/0x1ad0 fs/namespace.c:3316 + do_mount+0xfc/0x110 fs/namespace.c:3329 + __do_sys_mount fs/namespace.c:3540 [inline] + __se_sys_mount+0x219/0x2e0 fs/namespace.c:3514 + do_syscall_64+0x33/0x40 arch/x86/entry/common.c:46 + entry_SYSCALL_64_after_hwframe+0x67/0xd1 + +Memory state around the buggy address: + ffff88807b002f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + ffff88807b002f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +>ffff88807b003000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ^ + ffff88807b003080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ffff88807b003100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + +Above issue happens as ext4_xattr_delete_inode() isn't check xattr +is valid if xattr is in inode. +To solve above issue call xattr_check_inode() check if xattr if valid +in inode. In fact, we can directly verify in ext4_iget_extra_inode(), +so that there is no divergent verification. + +Fixes: e50e5129f384 ("ext4: xattr-in-inode support") +Signed-off-by: Ye Bin +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20250208063141.1539283-3-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: David Nyström +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inode.c | 5 +++++ + fs/ext4/xattr.c | 26 +------------------------- + fs/ext4/xattr.h | 7 +++++++ + 3 files changed, 13 insertions(+), 25 deletions(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4728,6 +4728,11 @@ static inline int ext4_iget_extra_inode( + *magic == cpu_to_le32(EXT4_XATTR_MAGIC)) { + int err; + ++ err = xattr_check_inode(inode, IHDR(inode, raw_inode), ++ ITAIL(inode, raw_inode)); ++ if (err) ++ return err; ++ + ext4_set_inode_state(inode, EXT4_STATE_XATTR); + err = ext4_find_inline_data_nolock(inode); + if (!err && ext4_has_inline_data(inode)) +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -312,7 +312,7 @@ __ext4_xattr_check_block(struct inode *i + __ext4_xattr_check_block((inode), (bh), __func__, __LINE__) + + +-static inline int ++int + __xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, + void *end, const char *function, unsigned int line) + { +@@ -320,9 +320,6 @@ __xattr_check_inode(struct inode *inode, + function, line); + } + +-#define xattr_check_inode(inode, header, end) \ +- __xattr_check_inode((inode), (header), (end), __func__, __LINE__) +- + static int + xattr_find_entry(struct inode *inode, struct ext4_xattr_entry **pentry, + void *end, int name_index, const char *name, int sorted) +@@ -654,9 +651,6 @@ ext4_xattr_ibody_get(struct inode *inode + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); + end = ITAIL(inode, raw_inode); +- error = xattr_check_inode(inode, header, end); +- if (error) +- goto cleanup; + entry = IFIRST(header); + error = xattr_find_entry(inode, &entry, end, name_index, name, 0); + if (error) +@@ -787,7 +781,6 @@ ext4_xattr_ibody_list(struct dentry *den + struct ext4_xattr_ibody_header *header; + struct ext4_inode *raw_inode; + struct ext4_iloc iloc; +- void *end; + int error; + + if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) +@@ -797,14 +790,9 @@ ext4_xattr_ibody_list(struct dentry *den + return error; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); +- end = ITAIL(inode, raw_inode); +- error = xattr_check_inode(inode, header, end); +- if (error) +- goto cleanup; + error = ext4_xattr_list_entries(dentry, IFIRST(header), + buffer, buffer_size); + +-cleanup: + brelse(iloc.bh); + return error; + } +@@ -872,7 +860,6 @@ int ext4_get_inode_usage(struct inode *i + struct ext4_xattr_ibody_header *header; + struct ext4_xattr_entry *entry; + qsize_t ea_inode_refs = 0; +- void *end; + int ret; + + lockdep_assert_held_read(&EXT4_I(inode)->xattr_sem); +@@ -883,10 +870,6 @@ int ext4_get_inode_usage(struct inode *i + goto out; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); +- end = ITAIL(inode, raw_inode); +- ret = xattr_check_inode(inode, header, end); +- if (ret) +- goto out; + + for (entry = IFIRST(header); !IS_LAST_ENTRY(entry); + entry = EXT4_XATTR_NEXT(entry)) +@@ -2250,9 +2233,6 @@ int ext4_xattr_ibody_find(struct inode * + is->s.here = is->s.first; + is->s.end = ITAIL(inode, raw_inode); + if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { +- error = xattr_check_inode(inode, header, is->s.end); +- if (error) +- return error; + /* Find the named attribute. */ + error = xattr_find_entry(inode, &is->s.here, is->s.end, + i->name_index, i->name, 0); +@@ -2803,10 +2783,6 @@ retry: + min_offs = end - base; + total_ino = sizeof(struct ext4_xattr_ibody_header) + sizeof(u32); + +- error = xattr_check_inode(inode, header, end); +- if (error) +- goto cleanup; +- + ifree = ext4_xattr_free_space(base, &min_offs, base, &total_ino); + if (ifree >= isize_diff) + goto shift; +--- a/fs/ext4/xattr.h ++++ b/fs/ext4/xattr.h +@@ -210,6 +210,13 @@ extern int ext4_xattr_ibody_set(handle_t + extern struct mb_cache *ext4_xattr_create_cache(void); + extern void ext4_xattr_destroy_cache(struct mb_cache *); + ++extern int ++__xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, ++ void *end, const char *function, unsigned int line); ++ ++#define xattr_check_inode(inode, header, end) \ ++ __xattr_check_inode((inode), (header), (end), __func__, __LINE__) ++ + #ifdef CONFIG_EXT4_FS_SECURITY + extern int ext4_init_security(handle_t *handle, struct inode *inode, + struct inode *dir, const struct qstr *qstr); diff --git a/queue-6.6/ext4-introduce-itail-helper.patch b/queue-6.6/ext4-introduce-itail-helper.patch new file mode 100644 index 0000000000..6599bc331a --- /dev/null +++ b/queue-6.6/ext4-introduce-itail-helper.patch @@ -0,0 +1,84 @@ +From stable+bounces-201008-greg=kroah.com@vger.kernel.org Mon Dec 15 09:56:24 2025 +From: "David Nyström" +Date: Mon, 15 Dec 2025 09:52:56 +0100 +Subject: ext4: introduce ITAIL helper +To: stable@vger.kernel.org +Cc: "Andreas Dilger" , "James Simmons" , "Ye Bin" , "David Nyström" , "Jan Kara" , "Theodore Ts'o" +Message-ID: <20251215-cve-2025-22121-v1-1-283f77b33397@est.tech> + +From: Ye Bin + +[ Upstream commit 69f3a3039b0d0003de008659cafd5a1eaaa0a7a4 ] + +Introduce ITAIL helper to get the bound of xattr in inode. + +Signed-off-by: Ye Bin +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20250208063141.1539283-2-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: David Nyström +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/xattr.c | 10 +++++----- + fs/ext4/xattr.h | 3 +++ + 2 files changed, 8 insertions(+), 5 deletions(-) + +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -653,7 +653,7 @@ ext4_xattr_ibody_get(struct inode *inode + return error; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); +- end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; ++ end = ITAIL(inode, raw_inode); + error = xattr_check_inode(inode, header, end); + if (error) + goto cleanup; +@@ -797,7 +797,7 @@ ext4_xattr_ibody_list(struct dentry *den + return error; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); +- end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; ++ end = ITAIL(inode, raw_inode); + error = xattr_check_inode(inode, header, end); + if (error) + goto cleanup; +@@ -883,7 +883,7 @@ int ext4_get_inode_usage(struct inode *i + goto out; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); +- end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; ++ end = ITAIL(inode, raw_inode); + ret = xattr_check_inode(inode, header, end); + if (ret) + goto out; +@@ -2248,7 +2248,7 @@ int ext4_xattr_ibody_find(struct inode * + header = IHDR(inode, raw_inode); + is->s.base = is->s.first = IFIRST(header); + is->s.here = is->s.first; +- is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; ++ is->s.end = ITAIL(inode, raw_inode); + if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { + error = xattr_check_inode(inode, header, is->s.end); + if (error) +@@ -2799,7 +2799,7 @@ retry: + */ + + base = IFIRST(header); +- end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; ++ end = ITAIL(inode, raw_inode); + min_offs = end - base; + total_ino = sizeof(struct ext4_xattr_ibody_header) + sizeof(u32); + +--- a/fs/ext4/xattr.h ++++ b/fs/ext4/xattr.h +@@ -68,6 +68,9 @@ struct ext4_xattr_entry { + ((void *)raw_inode + \ + EXT4_GOOD_OLD_INODE_SIZE + \ + EXT4_I(inode)->i_extra_isize)) ++#define ITAIL(inode, raw_inode) \ ++ ((void *)(raw_inode) + \ ++ EXT4_SB((inode)->i_sb)->s_inode_size) + #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1)) + + /* diff --git a/queue-6.6/f2fs-drop-inode-from-the-donation-list-when-the-last-file-is-closed.patch b/queue-6.6/f2fs-drop-inode-from-the-donation-list-when-the-last-file-is-closed.patch new file mode 100644 index 0000000000..6f180b299e --- /dev/null +++ b/queue-6.6/f2fs-drop-inode-from-the-donation-list-when-the-last-file-is-closed.patch @@ -0,0 +1,90 @@ +From stable+bounces-204254-greg=kroah.com@vger.kernel.org Tue Dec 30 18:11:50 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 12:05:39 -0500 +Subject: f2fs: drop inode from the donation list when the last file is closed +To: stable@vger.kernel.org +Cc: Jaegeuk Kim , Chao Yu , Sasha Levin +Message-ID: <20251230170540.2336679-3-sashal@kernel.org> + +From: Jaegeuk Kim + +[ Upstream commit 078cad8212ce4f4ebbafcc0936475b8215e1ca2a ] + +Let's drop the inode from the donation list when there is no other +open file. + +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Stable-dep-of: 10b591e7fb7c ("f2fs: fix to avoid updating compression context during writeback") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/f2fs.h | 2 ++ + fs/f2fs/file.c | 8 +++++++- + fs/f2fs/inode.c | 2 +- + fs/f2fs/super.c | 1 + + 4 files changed, 11 insertions(+), 2 deletions(-) + +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -841,6 +841,7 @@ struct f2fs_inode_info { + /* linked in global inode list for cache donation */ + struct list_head gdonate_list; + pgoff_t donate_start, donate_end; /* inclusive */ ++ atomic_t open_count; /* # of open files */ + + struct task_struct *atomic_write_task; /* store atomic write task */ + struct extent_tree *extent_tree[NR_EXTENT_CACHES]; +@@ -3560,6 +3561,7 @@ int f2fs_try_to_free_nats(struct f2fs_sb + void f2fs_update_inode(struct inode *inode, struct page *node_page); + void f2fs_update_inode_page(struct inode *inode); + int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc); ++void f2fs_remove_donate_inode(struct inode *inode); + void f2fs_evict_inode(struct inode *inode); + void f2fs_handle_failed_inode(struct inode *inode); + +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -621,7 +621,10 @@ static int f2fs_file_open(struct inode * + if (err) + return err; + +- return finish_preallocate_blocks(inode); ++ err = finish_preallocate_blocks(inode); ++ if (!err) ++ atomic_inc(&F2FS_I(inode)->open_count); ++ return err; + } + + void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count) +@@ -1966,6 +1969,9 @@ out: + + static int f2fs_release_file(struct inode *inode, struct file *filp) + { ++ if (atomic_dec_and_test(&F2FS_I(inode)->open_count)) ++ f2fs_remove_donate_inode(inode); ++ + /* + * f2fs_release_file is called at every close calls. So we should + * not drop any inmemory pages by close called by other process. +--- a/fs/f2fs/inode.c ++++ b/fs/f2fs/inode.c +@@ -811,7 +811,7 @@ int f2fs_write_inode(struct inode *inode + return 0; + } + +-static void f2fs_remove_donate_inode(struct inode *inode) ++void f2fs_remove_donate_inode(struct inode *inode) + { + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1409,6 +1409,7 @@ static struct inode *f2fs_alloc_inode(st + /* Initialize f2fs-specific inode info */ + atomic_set(&fi->dirty_pages, 0); + atomic_set(&fi->i_compr_blocks, 0); ++ atomic_set(&fi->open_count, 0); + init_f2fs_rwsem(&fi->i_sem); + spin_lock_init(&fi->i_size_lock); + INIT_LIST_HEAD(&fi->dirty_list); diff --git a/queue-6.6/f2fs-fix-to-avoid-updating-compression-context-during-writeback.patch b/queue-6.6/f2fs-fix-to-avoid-updating-compression-context-during-writeback.patch new file mode 100644 index 0000000000..98459295dd --- /dev/null +++ b/queue-6.6/f2fs-fix-to-avoid-updating-compression-context-during-writeback.patch @@ -0,0 +1,164 @@ +From stable+bounces-204253-greg=kroah.com@vger.kernel.org Tue Dec 30 18:12:13 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 12:05:40 -0500 +Subject: f2fs: fix to avoid updating compression context during writeback +To: stable@vger.kernel.org +Cc: Chao Yu , stable@kernel.org, "Bai, Shuangpeng" , Jaegeuk Kim , Sasha Levin +Message-ID: <20251230170540.2336679-4-sashal@kernel.org> + +From: Chao Yu + +[ Upstream commit 10b591e7fb7cdc8c1e53e9c000dc0ef7069aaa76 ] + +Bai, Shuangpeng reported a bug as below: + +Oops: divide error: 0000 [#1] SMP KASAN PTI +CPU: 0 UID: 0 PID: 11441 Comm: syz.0.46 Not tainted 6.17.0 #1 PREEMPT(full) +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 +RIP: 0010:f2fs_all_cluster_page_ready+0x106/0x550 fs/f2fs/compress.c:857 +Call Trace: + + f2fs_write_cache_pages fs/f2fs/data.c:3078 [inline] + __f2fs_write_data_pages fs/f2fs/data.c:3290 [inline] + f2fs_write_data_pages+0x1c19/0x3600 fs/f2fs/data.c:3317 + do_writepages+0x38e/0x640 mm/page-writeback.c:2634 + filemap_fdatawrite_wbc mm/filemap.c:386 [inline] + __filemap_fdatawrite_range mm/filemap.c:419 [inline] + file_write_and_wait_range+0x2ba/0x3e0 mm/filemap.c:794 + f2fs_do_sync_file+0x6e6/0x1b00 fs/f2fs/file.c:294 + generic_write_sync include/linux/fs.h:3043 [inline] + f2fs_file_write_iter+0x76e/0x2700 fs/f2fs/file.c:5259 + new_sync_write fs/read_write.c:593 [inline] + vfs_write+0x7e9/0xe00 fs/read_write.c:686 + ksys_write+0x19d/0x2d0 fs/read_write.c:738 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0xf7/0x470 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +The bug was triggered w/ below race condition: + +fsync setattr ioctl +- f2fs_do_sync_file + - file_write_and_wait_range + - f2fs_write_cache_pages + : inode is non-compressed + : cc.cluster_size = + F2FS_I(inode)->i_cluster_size = 0 + - tag_pages_for_writeback + - f2fs_setattr + - truncate_setsize + - f2fs_truncate + - f2fs_fileattr_set + - f2fs_setflags_common + - set_compress_context + : F2FS_I(inode)->i_cluster_size = 4 + : set_inode_flag(inode, FI_COMPRESSED_FILE) + - f2fs_compressed_file + : return true + - f2fs_all_cluster_page_ready + : "pgidx % cc->cluster_size" trigger dividing 0 issue + +Let's change as below to fix this issue: +- introduce a new atomic type variable .writeback in structure f2fs_inode_info +to track the number of threads which calling f2fs_write_cache_pages(). +- use .i_sem lock to protect .writeback update. +- check .writeback before update compression context in f2fs_setflags_common() +to avoid race w/ ->writepages. + +Fixes: 4c8ff7095bef ("f2fs: support data compression") +Cc: stable@kernel.org +Reported-by: Bai, Shuangpeng +Tested-by: Bai, Shuangpeng +Closes: https://lore.kernel.org/lkml/44D8F7B3-68AD-425F-9915-65D27591F93F@psu.edu +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/data.c | 17 +++++++++++++++++ + fs/f2fs/f2fs.h | 3 ++- + fs/f2fs/file.c | 5 +++-- + fs/f2fs/super.c | 1 + + 4 files changed, 23 insertions(+), 3 deletions(-) + +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -3233,6 +3233,19 @@ static inline bool __should_serialize_io + return false; + } + ++static inline void account_writeback(struct inode *inode, bool inc) ++{ ++ if (!f2fs_sb_has_compression(F2FS_I_SB(inode))) ++ return; ++ ++ f2fs_down_read(&F2FS_I(inode)->i_sem); ++ if (inc) ++ atomic_inc(&F2FS_I(inode)->writeback); ++ else ++ atomic_dec(&F2FS_I(inode)->writeback); ++ f2fs_up_read(&F2FS_I(inode)->i_sem); ++} ++ + static int __f2fs_write_data_pages(struct address_space *mapping, + struct writeback_control *wbc, + enum iostat_type io_type) +@@ -3282,10 +3295,14 @@ static int __f2fs_write_data_pages(struc + locked = true; + } + ++ account_writeback(inode, true); ++ + blk_start_plug(&plug); + ret = f2fs_write_cache_pages(mapping, wbc, io_type); + blk_finish_plug(&plug); + ++ account_writeback(inode, false); ++ + if (locked) + mutex_unlock(&sbi->writepages); + +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -869,6 +869,7 @@ struct f2fs_inode_info { + unsigned char i_compress_level; /* compress level (lz4hc,zstd) */ + unsigned char i_compress_flag; /* compress flag */ + unsigned int i_cluster_size; /* cluster size */ ++ atomic_t writeback; /* count # of writeback thread */ + + unsigned int atomic_write_cnt; + loff_t original_i_size; /* original i_size before atomic write */ +@@ -4485,7 +4486,7 @@ static inline bool f2fs_disable_compress + f2fs_up_write(&F2FS_I(inode)->i_sem); + return true; + } +- if (f2fs_is_mmap_file(inode) || ++ if (f2fs_is_mmap_file(inode) || atomic_read(&fi->writeback) || + (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode))) { + f2fs_up_write(&F2FS_I(inode)->i_sem); + return false; +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -2045,8 +2045,9 @@ static int f2fs_setflags_common(struct i + + f2fs_down_write(&F2FS_I(inode)->i_sem); + if (!f2fs_may_compress(inode) || +- (S_ISREG(inode->i_mode) && +- F2FS_HAS_BLOCKS(inode))) { ++ atomic_read(&fi->writeback) || ++ (S_ISREG(inode->i_mode) && ++ F2FS_HAS_BLOCKS(inode))) { + f2fs_up_write(&F2FS_I(inode)->i_sem); + return -EINVAL; + } +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1410,6 +1410,7 @@ static struct inode *f2fs_alloc_inode(st + atomic_set(&fi->dirty_pages, 0); + atomic_set(&fi->i_compr_blocks, 0); + atomic_set(&fi->open_count, 0); ++ atomic_set(&fi->writeback, 0); + init_f2fs_rwsem(&fi->i_sem); + spin_lock_init(&fi->i_size_lock); + INIT_LIST_HEAD(&fi->dirty_list); diff --git a/queue-6.6/f2fs-fix-to-detect-recoverable-inode-during-dryrun-of-find_fsync_dnodes.patch b/queue-6.6/f2fs-fix-to-detect-recoverable-inode-during-dryrun-of-find_fsync_dnodes.patch new file mode 100644 index 0000000000..0b467c3bb6 --- /dev/null +++ b/queue-6.6/f2fs-fix-to-detect-recoverable-inode-during-dryrun-of-find_fsync_dnodes.patch @@ -0,0 +1,109 @@ +From stable+bounces-204277-greg=kroah.com@vger.kernel.org Tue Dec 30 19:53:39 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 13:53:24 -0500 +Subject: f2fs: fix to detect recoverable inode during dryrun of find_fsync_dnodes() +To: stable@vger.kernel.org +Cc: Chao Yu , stable@kernel.org, Jaegeuk Kim , Sasha Levin +Message-ID: <20251230185324.2411791-1-sashal@kernel.org> + +From: Chao Yu + +[ Upstream commit 68d05693f8c031257a0822464366e1c2a239a512 ] + +mkfs.f2fs -f /dev/vdd +mount /dev/vdd /mnt/f2fs +touch /mnt/f2fs/foo +sync # avoid CP_UMOUNT_FLAG in last f2fs_checkpoint.ckpt_flags +touch /mnt/f2fs/bar +f2fs_io fsync /mnt/f2fs/bar +f2fs_io shutdown 2 /mnt/f2fs +umount /mnt/f2fs +blockdev --setro /dev/vdd +mount /dev/vdd /mnt/f2fs +mount: /mnt/f2fs: WARNING: source write-protected, mounted read-only. + +For the case if we create and fsync a new inode before sudden power-cut, +without norecovery or disable_roll_forward mount option, the following +mount will succeed w/o recovering last fsynced inode. + +The problem here is that we only check inode_list list after +find_fsync_dnodes() in f2fs_recover_fsync_data() to find out whether +there is recoverable data in the iamge, but there is a missed case, if +last fsynced inode is not existing in last checkpoint, then, we will +fail to get its inode due to nat of inode node is not existing in last +checkpoint, so the inode won't be linked in inode_list. + +Let's detect such case in dyrun mode to fix this issue. + +After this change, mount will fail as expected below: +mount: /mnt/f2fs: cannot mount /dev/vdd read-only. + dmesg(1) may have more information after failed mount system call. +demsg: +F2FS-fs (vdd): Need to recover fsync data, but write access unavailable, please try mount w/ disable_roll_forward or norecovery + +Cc: stable@kernel.org +Fixes: 6781eabba1bd ("f2fs: give -EINVAL for norecovery and rw mount") +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ folio => page ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/recovery.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +--- a/fs/f2fs/recovery.c ++++ b/fs/f2fs/recovery.c +@@ -404,7 +404,7 @@ static int sanity_check_node_chain(struc + } + + static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head, +- bool check_only) ++ bool check_only, bool *new_inode) + { + struct curseg_info *curseg; + struct page *page = NULL; +@@ -451,16 +451,19 @@ static int find_fsync_dnodes(struct f2fs + quota_inode = true; + } + +- /* +- * CP | dnode(F) | inode(DF) +- * For this case, we should not give up now. +- */ + entry = add_fsync_inode(sbi, head, ino_of_node(page), + quota_inode); + if (IS_ERR(entry)) { + err = PTR_ERR(entry); +- if (err == -ENOENT) ++ /* ++ * CP | dnode(F) | inode(DF) ++ * For this case, we should not give up now. ++ */ ++ if (err == -ENOENT) { ++ if (check_only) ++ *new_inode = true; + goto next; ++ } + f2fs_put_page(page, 1); + break; + } +@@ -863,6 +866,7 @@ int f2fs_recover_fsync_data(struct f2fs_ + unsigned long s_flags = sbi->sb->s_flags; + bool need_writecp = false; + bool fix_curseg_write_pointer = false; ++ bool new_inode = false; + + if (is_sbi_flag_set(sbi, SBI_IS_WRITABLE)) + f2fs_info(sbi, "recover fsync data on readonly fs"); +@@ -875,8 +879,8 @@ int f2fs_recover_fsync_data(struct f2fs_ + f2fs_down_write(&sbi->cp_global_sem); + + /* step #1: find fsynced inode numbers */ +- err = find_fsync_dnodes(sbi, &inode_list, check_only); +- if (err || list_empty(&inode_list)) ++ err = find_fsync_dnodes(sbi, &inode_list, check_only, &new_inode); ++ if (err < 0 || (list_empty(&inode_list) && (!check_only || !new_inode))) + goto skip; + + if (check_only) { diff --git a/queue-6.6/f2fs-fix-to-propagate-error-from-f2fs_enable_checkpoint.patch b/queue-6.6/f2fs-fix-to-propagate-error-from-f2fs_enable_checkpoint.patch new file mode 100644 index 0000000000..5c7883c511 --- /dev/null +++ b/queue-6.6/f2fs-fix-to-propagate-error-from-f2fs_enable_checkpoint.patch @@ -0,0 +1,86 @@ +From stable+bounces-204261-greg=kroah.com@vger.kernel.org Tue Dec 30 18:21:01 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 12:20:55 -0500 +Subject: f2fs: fix to propagate error from f2fs_enable_checkpoint() +To: stable@vger.kernel.org +Cc: Chao Yu , stable@kernel.org, Jaegeuk Kim , Sasha Levin +Message-ID: <20251230172055.2345676-1-sashal@kernel.org> + +From: Chao Yu + +[ Upstream commit be112e7449a6e1b54aa9feac618825d154b3a5c7 ] + +In order to let userspace detect such error rather than suffering +silent failure. + +Fixes: 4354994f097d ("f2fs: checkpoint disabling") +Cc: stable@kernel.org +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ Adjust context, no rollback ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/super.c | 24 +++++++++++++++--------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -2267,9 +2267,10 @@ restore_flag: + return err; + } + +-static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) ++static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) + { + int retry = DEFAULT_RETRY_IO_COUNT; ++ int ret; + + /* we should flush all the data to keep data consistency */ + do { +@@ -2287,10 +2288,14 @@ static void f2fs_enable_checkpoint(struc + set_sbi_flag(sbi, SBI_IS_DIRTY); + f2fs_up_write(&sbi->gc_lock); + +- f2fs_sync_fs(sbi->sb, 1); ++ ret = f2fs_sync_fs(sbi->sb, 1); ++ if (ret) ++ f2fs_err(sbi, "%s sync_fs failed, ret: %d", __func__, ret); + + /* Let's ensure there's no pending checkpoint anymore */ + f2fs_flush_ckpt_thread(sbi); ++ ++ return ret; + } + + static int f2fs_remount(struct super_block *sb, int *flags, char *data) +@@ -2511,7 +2516,9 @@ static int f2fs_remount(struct super_blo + if (err) + goto restore_discard; + } else { +- f2fs_enable_checkpoint(sbi); ++ err = f2fs_enable_checkpoint(sbi); ++ if (err) ++ goto restore_discard; + } + } + +@@ -4689,13 +4696,12 @@ reset_checkpoint: + /* f2fs_recover_fsync_data() cleared this already */ + clear_sbi_flag(sbi, SBI_POR_DOING); + +- if (test_opt(sbi, DISABLE_CHECKPOINT)) { ++ if (test_opt(sbi, DISABLE_CHECKPOINT)) + err = f2fs_disable_checkpoint(sbi); +- if (err) +- goto sync_free_meta; +- } else if (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) { +- f2fs_enable_checkpoint(sbi); +- } ++ else if (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) ++ err = f2fs_enable_checkpoint(sbi); ++ if (err) ++ goto sync_free_meta; + + /* + * If filesystem is not mounted as read-only then diff --git a/queue-6.6/f2fs-keep-posix_fadv_noreuse-ranges.patch b/queue-6.6/f2fs-keep-posix_fadv_noreuse-ranges.patch new file mode 100644 index 0000000000..02ff31832d --- /dev/null +++ b/queue-6.6/f2fs-keep-posix_fadv_noreuse-ranges.patch @@ -0,0 +1,206 @@ +From stable+bounces-204252-greg=kroah.com@vger.kernel.org Tue Dec 30 18:12:48 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 12:05:38 -0500 +Subject: f2fs: keep POSIX_FADV_NOREUSE ranges +To: stable@vger.kernel.org +Cc: Jaegeuk Kim , Chao Yu , Sasha Levin +Message-ID: <20251230170540.2336679-2-sashal@kernel.org> + +From: Jaegeuk Kim + +[ Upstream commit ef0c333cad8d1940f132a7ce15f15920216a3bd5 ] + +This patch records POSIX_FADV_NOREUSE ranges for users to reclaim the caches +instantly off from LRU. + +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Stable-dep-of: 10b591e7fb7c ("f2fs: fix to avoid updating compression context during writeback") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/debug.c | 3 ++ + fs/f2fs/f2fs.h | 12 ++++++++++- + fs/f2fs/file.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++----- + fs/f2fs/inode.c | 14 +++++++++++++ + fs/f2fs/super.c | 1 + 5 files changed, 84 insertions(+), 6 deletions(-) + +--- a/fs/f2fs/debug.c ++++ b/fs/f2fs/debug.c +@@ -100,6 +100,7 @@ static void update_general_status(struct + si->ndirty_imeta = get_pages(sbi, F2FS_DIRTY_IMETA); + si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE]; + si->ndirty_files = sbi->ndirty_inode[FILE_INODE]; ++ si->ndonate_files = sbi->donate_files; + si->nquota_files = sbi->nquota_files; + si->ndirty_all = sbi->ndirty_inode[DIRTY_META]; + si->aw_cnt = atomic_read(&sbi->atomic_files); +@@ -436,6 +437,8 @@ static int stat_show(struct seq_file *s, + si->compr_inode, si->compr_blocks); + seq_printf(s, " - Swapfile Inode: %u\n", + si->swapfile_inode); ++ seq_printf(s, " - Donate Inode: %u\n", ++ si->ndonate_files); + seq_printf(s, " - Orphan/Append/Update Inode: %u, %u, %u\n", + si->orphans, si->append, si->update); + seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n", +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -837,6 +837,11 @@ struct f2fs_inode_info { + #endif + struct list_head dirty_list; /* dirty list for dirs and files */ + struct list_head gdirty_list; /* linked in global dirty list */ ++ ++ /* linked in global inode list for cache donation */ ++ struct list_head gdonate_list; ++ pgoff_t donate_start, donate_end; /* inclusive */ ++ + struct task_struct *atomic_write_task; /* store atomic write task */ + struct extent_tree *extent_tree[NR_EXTENT_CACHES]; + /* cached extent_tree entry */ +@@ -1261,6 +1266,7 @@ enum inode_type { + DIR_INODE, /* for dirty dir inode */ + FILE_INODE, /* for dirty regular/symlink inode */ + DIRTY_META, /* for all dirtied inode metadata */ ++ DONATE_INODE, /* for all inode to donate pages */ + NR_INODE_TYPE, + }; + +@@ -1613,6 +1619,9 @@ struct f2fs_sb_info { + unsigned int warm_data_age_threshold; + unsigned int last_age_weight; + ++ /* control donate caches */ ++ unsigned int donate_files; ++ + /* basic filesystem units */ + unsigned int log_sectors_per_block; /* log2 sectors per block */ + unsigned int log_blocksize; /* log2 block size */ +@@ -3948,7 +3957,8 @@ struct f2fs_stat_info { + unsigned long long allocated_data_blocks; + int ndirty_node, ndirty_dent, ndirty_meta, ndirty_imeta; + int ndirty_data, ndirty_qdata; +- unsigned int ndirty_dirs, ndirty_files, nquota_files, ndirty_all; ++ unsigned int ndirty_dirs, ndirty_files, ndirty_all; ++ unsigned int nquota_files, ndonate_files; + int nats, dirty_nats, sits, dirty_sits; + int free_nids, avail_nids, alloc_nids; + int total_count, utilization; +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -2435,6 +2435,52 @@ static int f2fs_ioc_shutdown(struct file + return ret; + } + ++static void f2fs_keep_noreuse_range(struct inode *inode, ++ loff_t offset, loff_t len) ++{ ++ struct f2fs_sb_info *sbi = F2FS_I_SB(inode); ++ u64 max_bytes = F2FS_BLK_TO_BYTES(max_file_blocks(inode)); ++ u64 start, end; ++ ++ if (!S_ISREG(inode->i_mode)) ++ return; ++ ++ if (offset >= max_bytes || len > max_bytes || ++ (offset + len) > max_bytes) ++ return; ++ ++ start = offset >> PAGE_SHIFT; ++ end = DIV_ROUND_UP(offset + len, PAGE_SIZE); ++ ++ inode_lock(inode); ++ if (f2fs_is_atomic_file(inode)) { ++ inode_unlock(inode); ++ return; ++ } ++ ++ spin_lock(&sbi->inode_lock[DONATE_INODE]); ++ /* let's remove the range, if len = 0 */ ++ if (!len) { ++ if (!list_empty(&F2FS_I(inode)->gdonate_list)) { ++ list_del_init(&F2FS_I(inode)->gdonate_list); ++ sbi->donate_files--; ++ } ++ } else { ++ if (list_empty(&F2FS_I(inode)->gdonate_list)) { ++ list_add_tail(&F2FS_I(inode)->gdonate_list, ++ &sbi->inode_list[DONATE_INODE]); ++ sbi->donate_files++; ++ } else { ++ list_move_tail(&F2FS_I(inode)->gdonate_list, ++ &sbi->inode_list[DONATE_INODE]); ++ } ++ F2FS_I(inode)->donate_start = start; ++ F2FS_I(inode)->donate_end = end - 1; ++ } ++ spin_unlock(&sbi->inode_lock[DONATE_INODE]); ++ inode_unlock(inode); ++} ++ + static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg) + { + struct inode *inode = file_inode(filp); +@@ -5078,12 +5124,16 @@ static int f2fs_file_fadvise(struct file + } + + err = generic_fadvise(filp, offset, len, advice); +- if (!err && advice == POSIX_FADV_DONTNEED && +- test_opt(F2FS_I_SB(inode), COMPRESS_CACHE) && +- f2fs_compressed_file(inode)) +- f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino); ++ if (err) ++ return err; + +- return err; ++ if (advice == POSIX_FADV_DONTNEED && ++ (test_opt(F2FS_I_SB(inode), COMPRESS_CACHE) && ++ f2fs_compressed_file(inode))) ++ f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino); ++ else if (advice == POSIX_FADV_NOREUSE) ++ f2fs_keep_noreuse_range(inode, offset, len); ++ return 0; + } + + #ifdef CONFIG_COMPAT +--- a/fs/f2fs/inode.c ++++ b/fs/f2fs/inode.c +@@ -811,6 +811,19 @@ int f2fs_write_inode(struct inode *inode + return 0; + } + ++static void f2fs_remove_donate_inode(struct inode *inode) ++{ ++ struct f2fs_sb_info *sbi = F2FS_I_SB(inode); ++ ++ if (list_empty(&F2FS_I(inode)->gdonate_list)) ++ return; ++ ++ spin_lock(&sbi->inode_lock[DONATE_INODE]); ++ list_del_init(&F2FS_I(inode)->gdonate_list); ++ sbi->donate_files--; ++ spin_unlock(&sbi->inode_lock[DONATE_INODE]); ++} ++ + /* + * Called at the last iput() if i_nlink is zero + */ +@@ -844,6 +857,7 @@ void f2fs_evict_inode(struct inode *inod + + f2fs_bug_on(sbi, get_dirty_pages(inode)); + f2fs_remove_dirty_inode(inode); ++ f2fs_remove_donate_inode(inode); + + f2fs_destroy_extent_tree(inode); + +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1413,6 +1413,7 @@ static struct inode *f2fs_alloc_inode(st + spin_lock_init(&fi->i_size_lock); + INIT_LIST_HEAD(&fi->dirty_list); + INIT_LIST_HEAD(&fi->gdirty_list); ++ INIT_LIST_HEAD(&fi->gdonate_list); + init_f2fs_rwsem(&fi->i_gc_rwsem[READ]); + init_f2fs_rwsem(&fi->i_gc_rwsem[WRITE]); + init_f2fs_rwsem(&fi->i_xattr_sem); diff --git a/queue-6.6/f2fs-remove-unused-gc_failure_pin.patch b/queue-6.6/f2fs-remove-unused-gc_failure_pin.patch new file mode 100644 index 0000000000..021cbf5409 --- /dev/null +++ b/queue-6.6/f2fs-remove-unused-gc_failure_pin.patch @@ -0,0 +1,139 @@ +From stable+bounces-204251-greg=kroah.com@vger.kernel.org Tue Dec 30 18:05:50 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 12:05:37 -0500 +Subject: f2fs: remove unused GC_FAILURE_PIN +To: stable@vger.kernel.org +Cc: Chao Yu , Jaegeuk Kim , Sasha Levin +Message-ID: <20251230170540.2336679-1-sashal@kernel.org> + +From: Chao Yu + +[ Upstream commit 968c4f72b23c0c8f1e94e942eab89b8c5a3022e7 ] + +After commit 3db1de0e582c ("f2fs: change the current atomic write way"), +we removed all GC_FAILURE_ATOMIC usage, let's change i_gc_failures[] +array to i_pin_failure for cleanup. + +Meanwhile, let's define i_current_depth and i_gc_failures as union +variable due to they won't be valid at the same time. + +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Stable-dep-of: 10b591e7fb7c ("f2fs: fix to avoid updating compression context during writeback") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/f2fs.h | 14 +++++--------- + fs/f2fs/file.c | 12 +++++------- + fs/f2fs/inode.c | 6 ++---- + fs/f2fs/recovery.c | 3 +-- + 4 files changed, 13 insertions(+), 22 deletions(-) + +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -762,11 +762,6 @@ enum { + + #define DEF_DIR_LEVEL 0 + +-enum { +- GC_FAILURE_PIN, +- MAX_GC_FAILURE +-}; +- + /* used for f2fs_inode_info->flags */ + enum { + FI_NEW_INODE, /* indicate newly allocated inode */ +@@ -814,9 +809,10 @@ struct f2fs_inode_info { + unsigned long i_flags; /* keep an inode flags for ioctl */ + unsigned char i_advise; /* use to give file attribute hints */ + unsigned char i_dir_level; /* use for dentry level for large dir */ +- unsigned int i_current_depth; /* only for directory depth */ +- /* for gc failure statistic */ +- unsigned int i_gc_failures[MAX_GC_FAILURE]; ++ union { ++ unsigned int i_current_depth; /* only for directory depth */ ++ unsigned int i_gc_failures; /* for gc failure statistic */ ++ }; + unsigned int i_pino; /* parent inode number */ + umode_t i_acl_mode; /* keep file acl mode temporarily */ + +@@ -3173,7 +3169,7 @@ static inline void f2fs_i_depth_write(st + static inline void f2fs_i_gc_failures_write(struct inode *inode, + unsigned int count) + { +- F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN] = count; ++ F2FS_I(inode)->i_gc_failures = count; + f2fs_mark_inode_dirty_sync(inode, true); + } + +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -3329,13 +3329,11 @@ int f2fs_pin_file_control(struct inode * + + /* Use i_gc_failures for normal file as a risk signal. */ + if (inc) +- f2fs_i_gc_failures_write(inode, +- fi->i_gc_failures[GC_FAILURE_PIN] + 1); ++ f2fs_i_gc_failures_write(inode, fi->i_gc_failures + 1); + +- if (fi->i_gc_failures[GC_FAILURE_PIN] > sbi->gc_pin_file_threshold) { ++ if (fi->i_gc_failures > sbi->gc_pin_file_threshold) { + f2fs_warn(sbi, "%s: Enable GC = ino %lx after %x GC trials", +- __func__, inode->i_ino, +- fi->i_gc_failures[GC_FAILURE_PIN]); ++ __func__, inode->i_ino, fi->i_gc_failures); + clear_inode_flag(inode, FI_PIN_FILE); + return -EAGAIN; + } +@@ -3404,7 +3402,7 @@ static int f2fs_ioc_set_pin_file(struct + } + + set_inode_flag(inode, FI_PIN_FILE); +- ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN]; ++ ret = F2FS_I(inode)->i_gc_failures; + done: + f2fs_update_time(sbi, REQ_TIME); + out: +@@ -3419,7 +3417,7 @@ static int f2fs_ioc_get_pin_file(struct + __u32 pin = 0; + + if (is_inode_flag_set(inode, FI_PIN_FILE)) +- pin = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN]; ++ pin = F2FS_I(inode)->i_gc_failures; + return put_user(pin, (u32 __user *)arg); + } + +--- a/fs/f2fs/inode.c ++++ b/fs/f2fs/inode.c +@@ -428,8 +428,7 @@ static int do_read_inode(struct inode *i + if (S_ISDIR(inode->i_mode)) + fi->i_current_depth = le32_to_cpu(ri->i_current_depth); + else if (S_ISREG(inode->i_mode)) +- fi->i_gc_failures[GC_FAILURE_PIN] = +- le16_to_cpu(ri->i_gc_failures); ++ fi->i_gc_failures = le16_to_cpu(ri->i_gc_failures); + fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid); + fi->i_flags = le32_to_cpu(ri->i_flags); + if (S_ISREG(inode->i_mode)) +@@ -691,8 +690,7 @@ void f2fs_update_inode(struct inode *ino + ri->i_current_depth = + cpu_to_le32(F2FS_I(inode)->i_current_depth); + else if (S_ISREG(inode->i_mode)) +- ri->i_gc_failures = +- cpu_to_le16(F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN]); ++ ri->i_gc_failures = cpu_to_le16(F2FS_I(inode)->i_gc_failures); + ri->i_xattr_nid = cpu_to_le32(F2FS_I(inode)->i_xattr_nid); + ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags); + ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino); +--- a/fs/f2fs/recovery.c ++++ b/fs/f2fs/recovery.c +@@ -330,8 +330,7 @@ static int recover_inode(struct inode *i + F2FS_I(inode)->i_advise = raw->i_advise; + F2FS_I(inode)->i_flags = le32_to_cpu(raw->i_flags); + f2fs_set_inode_flags(inode); +- F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN] = +- le16_to_cpu(raw->i_gc_failures); ++ F2FS_I(inode)->i_gc_failures = le16_to_cpu(raw->i_gc_failures); + + recover_inline_flags(inode, raw); + diff --git a/queue-6.6/f2fs-use-global-inline_xattr_slab-instead-of-per-sb-slab-cache.patch b/queue-6.6/f2fs-use-global-inline_xattr_slab-instead-of-per-sb-slab-cache.patch new file mode 100644 index 0000000000..386a466c11 --- /dev/null +++ b/queue-6.6/f2fs-use-global-inline_xattr_slab-instead-of-per-sb-slab-cache.patch @@ -0,0 +1,239 @@ +From stable+bounces-204270-greg=kroah.com@vger.kernel.org Tue Dec 30 19:19:47 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 13:19:39 -0500 +Subject: f2fs: use global inline_xattr_slab instead of per-sb slab cache +To: stable@vger.kernel.org +Cc: Chao Yu , stable@kernel.org, Hong Yun , Jaegeuk Kim , Sasha Levin +Message-ID: <20251230181939.2384947-1-sashal@kernel.org> + +From: Chao Yu + +[ Upstream commit 1f27ef42bb0b7c0740c5616ec577ec188b8a1d05 ] + +As Hong Yun reported in mailing list: + +loop7: detected capacity change from 0 to 131072 +------------[ cut here ]------------ +kmem_cache of name 'f2fs_xattr_entry-7:7' already exists +WARNING: CPU: 0 PID: 24426 at mm/slab_common.c:110 kmem_cache_sanity_check mm/slab_common.c:109 [inline] +WARNING: CPU: 0 PID: 24426 at mm/slab_common.c:110 __kmem_cache_create_args+0xa6/0x320 mm/slab_common.c:307 +CPU: 0 UID: 0 PID: 24426 Comm: syz.7.1370 Not tainted 6.17.0-rc4 #1 PREEMPT(full) +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 +RIP: 0010:kmem_cache_sanity_check mm/slab_common.c:109 [inline] +RIP: 0010:__kmem_cache_create_args+0xa6/0x320 mm/slab_common.c:307 +Call Trace: + __kmem_cache_create include/linux/slab.h:353 [inline] + f2fs_kmem_cache_create fs/f2fs/f2fs.h:2943 [inline] + f2fs_init_xattr_caches+0xa5/0xe0 fs/f2fs/xattr.c:843 + f2fs_fill_super+0x1645/0x2620 fs/f2fs/super.c:4918 + get_tree_bdev_flags+0x1fb/0x260 fs/super.c:1692 + vfs_get_tree+0x43/0x140 fs/super.c:1815 + do_new_mount+0x201/0x550 fs/namespace.c:3808 + do_mount fs/namespace.c:4136 [inline] + __do_sys_mount fs/namespace.c:4347 [inline] + __se_sys_mount+0x298/0x2f0 fs/namespace.c:4324 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x8e/0x3a0 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +The bug can be reproduced w/ below scripts: +- mount /dev/vdb /mnt1 +- mount /dev/vdc /mnt2 +- umount /mnt1 +- mounnt /dev/vdb /mnt1 + +The reason is if we created two slab caches, named f2fs_xattr_entry-7:3 +and f2fs_xattr_entry-7:7, and they have the same slab size. Actually, +slab system will only create one slab cache core structure which has +slab name of "f2fs_xattr_entry-7:3", and two slab caches share the same +structure and cache address. + +So, if we destroy f2fs_xattr_entry-7:3 cache w/ cache address, it will +decrease reference count of slab cache, rather than release slab cache +entirely, since there is one more user has referenced the cache. + +Then, if we try to create slab cache w/ name "f2fs_xattr_entry-7:3" again, +slab system will find that there is existed cache which has the same name +and trigger the warning. + +Let's changes to use global inline_xattr_slab instead of per-sb slab cache +for fixing. + +Fixes: a999150f4fe3 ("f2fs: use kmem_cache pool during inline xattr lookups") +Cc: stable@kernel.org +Reported-by: Hong Yun +Tested-by: Hong Yun +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ folio => page ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/f2fs.h | 3 --- + fs/f2fs/super.c | 17 ++++++++--------- + fs/f2fs/xattr.c | 30 ++++++++++-------------------- + fs/f2fs/xattr.h | 10 ++++++---- + 4 files changed, 24 insertions(+), 36 deletions(-) + +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -1778,9 +1778,6 @@ struct f2fs_sb_info { + spinlock_t error_lock; /* protect errors/stop_reason array */ + bool error_dirty; /* errors of sb is dirty */ + +- struct kmem_cache *inline_xattr_slab; /* inline xattr entry */ +- unsigned int inline_xattr_slab_size; /* default inline xattr slab size */ +- + /* For reclaimed segs statistics per each GC mode */ + unsigned int gc_segment_mode; /* GC state for reclaimed segments */ + unsigned int gc_reclaimed_segs[MAX_GC_MODE]; /* Reclaimed segs for each mode */ +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1683,7 +1683,6 @@ static void f2fs_put_super(struct super_ + + destroy_device_list(sbi); + f2fs_destroy_page_array_cache(sbi); +- f2fs_destroy_xattr_caches(sbi); + #ifdef CONFIG_QUOTA + for (i = 0; i < MAXQUOTAS; i++) + kfree(F2FS_OPTION(sbi).s_qf_names[i]); +@@ -4464,13 +4463,9 @@ try_onemore: + if (err) + goto free_iostat; + +- /* init per sbi slab cache */ +- err = f2fs_init_xattr_caches(sbi); +- if (err) +- goto free_percpu; + err = f2fs_init_page_array_cache(sbi); + if (err) +- goto free_xattr_cache; ++ goto free_percpu; + + /* get an inode for meta space */ + sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi)); +@@ -4787,8 +4782,6 @@ free_meta_inode: + sbi->meta_inode = NULL; + free_page_array_cache: + f2fs_destroy_page_array_cache(sbi); +-free_xattr_cache: +- f2fs_destroy_xattr_caches(sbi); + free_percpu: + destroy_percpu_info(sbi); + free_iostat: +@@ -4949,10 +4942,15 @@ static int __init init_f2fs_fs(void) + err = f2fs_create_casefold_cache(); + if (err) + goto free_compress_cache; +- err = register_filesystem(&f2fs_fs_type); ++ err = f2fs_init_xattr_cache(); + if (err) + goto free_casefold_cache; ++ err = register_filesystem(&f2fs_fs_type); ++ if (err) ++ goto free_xattr_cache; + return 0; ++free_xattr_cache: ++ f2fs_destroy_xattr_cache(); + free_casefold_cache: + f2fs_destroy_casefold_cache(); + free_compress_cache: +@@ -4993,6 +4991,7 @@ fail: + static void __exit exit_f2fs_fs(void) + { + unregister_filesystem(&f2fs_fs_type); ++ f2fs_destroy_xattr_cache(); + f2fs_destroy_casefold_cache(); + f2fs_destroy_compress_cache(); + f2fs_destroy_compress_mempool(); +--- a/fs/f2fs/xattr.c ++++ b/fs/f2fs/xattr.c +@@ -23,11 +23,12 @@ + #include "xattr.h" + #include "segment.h" + ++static struct kmem_cache *inline_xattr_slab; + static void *xattr_alloc(struct f2fs_sb_info *sbi, int size, bool *is_inline) + { +- if (likely(size == sbi->inline_xattr_slab_size)) { ++ if (likely(size == DEFAULT_XATTR_SLAB_SIZE)) { + *is_inline = true; +- return f2fs_kmem_cache_alloc(sbi->inline_xattr_slab, ++ return f2fs_kmem_cache_alloc(inline_xattr_slab, + GFP_F2FS_ZERO, false, sbi); + } + *is_inline = false; +@@ -38,7 +39,7 @@ static void xattr_free(struct f2fs_sb_in + bool is_inline) + { + if (is_inline) +- kmem_cache_free(sbi->inline_xattr_slab, xattr_addr); ++ kmem_cache_free(inline_xattr_slab, xattr_addr); + else + kfree(xattr_addr); + } +@@ -830,25 +831,14 @@ int f2fs_setxattr(struct inode *inode, i + return err; + } + +-int f2fs_init_xattr_caches(struct f2fs_sb_info *sbi) ++int __init f2fs_init_xattr_cache(void) + { +- dev_t dev = sbi->sb->s_bdev->bd_dev; +- char slab_name[32]; +- +- sprintf(slab_name, "f2fs_xattr_entry-%u:%u", MAJOR(dev), MINOR(dev)); +- +- sbi->inline_xattr_slab_size = F2FS_OPTION(sbi).inline_xattr_size * +- sizeof(__le32) + XATTR_PADDING_SIZE; +- +- sbi->inline_xattr_slab = f2fs_kmem_cache_create(slab_name, +- sbi->inline_xattr_slab_size); +- if (!sbi->inline_xattr_slab) +- return -ENOMEM; +- +- return 0; ++ inline_xattr_slab = f2fs_kmem_cache_create("f2fs_xattr_entry", ++ DEFAULT_XATTR_SLAB_SIZE); ++ return inline_xattr_slab ? 0 : -ENOMEM; + } + +-void f2fs_destroy_xattr_caches(struct f2fs_sb_info *sbi) ++void f2fs_destroy_xattr_cache(void) + { +- kmem_cache_destroy(sbi->inline_xattr_slab); ++ kmem_cache_destroy(inline_xattr_slab); + } +--- a/fs/f2fs/xattr.h ++++ b/fs/f2fs/xattr.h +@@ -89,6 +89,8 @@ struct f2fs_xattr_entry { + F2FS_TOTAL_EXTRA_ATTR_SIZE / sizeof(__le32) - \ + DEF_INLINE_RESERVED_SIZE - \ + MIN_INLINE_DENTRY_SIZE / sizeof(__le32)) ++#define DEFAULT_XATTR_SLAB_SIZE (DEFAULT_INLINE_XATTR_ADDRS * \ ++ sizeof(__le32) + XATTR_PADDING_SIZE) + + /* + * On-disk structure of f2fs_xattr +@@ -132,8 +134,8 @@ extern int f2fs_setxattr(struct inode *, + extern int f2fs_getxattr(struct inode *, int, const char *, void *, + size_t, struct page *); + extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t); +-extern int f2fs_init_xattr_caches(struct f2fs_sb_info *); +-extern void f2fs_destroy_xattr_caches(struct f2fs_sb_info *); ++extern int __init f2fs_init_xattr_cache(void); ++extern void f2fs_destroy_xattr_cache(void); + #else + + #define f2fs_xattr_handlers NULL +@@ -150,8 +152,8 @@ static inline int f2fs_getxattr(struct i + { + return -EOPNOTSUPP; + } +-static inline int f2fs_init_xattr_caches(struct f2fs_sb_info *sbi) { return 0; } +-static inline void f2fs_destroy_xattr_caches(struct f2fs_sb_info *sbi) { } ++static inline int __init f2fs_init_xattr_cache(void) { return 0; } ++static inline void f2fs_destroy_xattr_cache(void) { } + #endif + + #ifdef CONFIG_F2FS_FS_SECURITY diff --git a/queue-6.6/genirq-irq_sim-initialize-work-context-pointers-properly.patch b/queue-6.6/genirq-irq_sim-initialize-work-context-pointers-properly.patch new file mode 100644 index 0000000000..6ca21191cb --- /dev/null +++ b/queue-6.6/genirq-irq_sim-initialize-work-context-pointers-properly.patch @@ -0,0 +1,39 @@ +From stable+bounces-203411-greg=kroah.com@vger.kernel.org Fri Dec 26 02:54:13 2025 +From: Rahul Sharma +Date: Fri, 26 Dec 2025 09:53:07 +0800 +Subject: genirq/irq_sim: Initialize work context pointers properly +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: linux-kernel@vger.kernel.org, Gyeyoung Baek , Thomas Gleixner , Rahul Sharma +Message-ID: <20251226015307.1660054-1-black.hawk@163.com> + +From: Gyeyoung Baek + +[ Upstream commit 8a2277a3c9e4cc5398f80821afe7ecbe9bdf2819 ] + +Initialize `ops` member's pointers properly by using kzalloc() instead of +kmalloc() when allocating the simulation work context. Otherwise the +pointers contain random content leading to invalid dereferencing. + +Signed-off-by: Gyeyoung Baek +Signed-off-by: Thomas Gleixner +Link: https://lore.kernel.org/all/20250612124827.63259-1-gye976@gmail.com +[ The context change is due to the commit 011f583781fa +("genirq/irq_sim: add an extended irq_sim initializer") +which is irrelevant to the logic of this patch. ] +Signed-off-by: Rahul Sharma +Signed-off-by: Greg Kroah-Hartman +--- + kernel/irq/irq_sim.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/kernel/irq/irq_sim.c ++++ b/kernel/irq/irq_sim.c +@@ -166,7 +166,7 @@ struct irq_domain *irq_domain_create_sim + { + struct irq_sim_work_ctx *work_ctx; + +- work_ctx = kmalloc(sizeof(*work_ctx), GFP_KERNEL); ++ work_ctx = kzalloc(sizeof(*work_ctx), GFP_KERNEL); + if (!work_ctx) + goto err_out; + diff --git a/queue-6.6/kvm-nvmx-immediately-refresh-apicv-controls-as-needed-on-nested-vm-exit.patch b/queue-6.6/kvm-nvmx-immediately-refresh-apicv-controls-as-needed-on-nested-vm-exit.patch new file mode 100644 index 0000000000..b2f41f71d9 --- /dev/null +++ b/queue-6.6/kvm-nvmx-immediately-refresh-apicv-controls-as-needed-on-nested-vm-exit.patch @@ -0,0 +1,93 @@ +From stable+bounces-204362-greg=kroah.com@vger.kernel.org Wed Dec 31 16:05:40 2025 +From: Sasha Levin +Date: Wed, 31 Dec 2025 10:05:34 -0500 +Subject: KVM: nVMX: Immediately refresh APICv controls as needed on nested VM-Exit +To: stable@vger.kernel.org +Cc: Dongli Zhang , Chao Gao , Sean Christopherson , Sasha Levin +Message-ID: <20251231150534.3104156-1-sashal@kernel.org> + +From: Dongli Zhang + +[ Upstream commit 29763138830916f46daaa50e83e7f4f907a3236b ] + +If an APICv status updated was pended while L2 was active, immediately +refresh vmcs01's controls instead of pending KVM_REQ_APICV_UPDATE as +kvm_vcpu_update_apicv() only calls into vendor code if a change is +necessary. + +E.g. if APICv is inhibited, and then activated while L2 is running: + + kvm_vcpu_update_apicv() + | + -> __kvm_vcpu_update_apicv() + | + -> apic->apicv_active = true + | + -> vmx_refresh_apicv_exec_ctrl() + | + -> vmx->nested.update_vmcs01_apicv_status = true + | + -> return + +Then L2 exits to L1: + + __nested_vmx_vmexit() + | + -> kvm_make_request(KVM_REQ_APICV_UPDATE) + + vcpu_enter_guest(): KVM_REQ_APICV_UPDATE + -> kvm_vcpu_update_apicv() + | + -> __kvm_vcpu_update_apicv() + | + -> return // because if (apic->apicv_active == activate) + +Reported-by: Chao Gao +Closes: https://lore.kernel.org/all/aQ2jmnN8wUYVEawF@intel.com +Fixes: 7c69661e225c ("KVM: nVMX: Defer APICv updates while L2 is active until L1 is active") +Cc: stable@vger.kernel.org +Signed-off-by: Dongli Zhang +[sean: write changelog] +Link: https://patch.msgid.link/20251205231913.441872-3-seanjc@google.com +Signed-off-by: Sean Christopherson +[ exported vmx_refresh_apicv_exec_ctrl() and added declaration in vmx.h ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/vmx/nested.c | 2 +- + arch/x86/kvm/vmx/vmx.c | 2 +- + arch/x86/kvm/vmx/vmx.h | 1 + + 3 files changed, 3 insertions(+), 2 deletions(-) + +--- a/arch/x86/kvm/vmx/nested.c ++++ b/arch/x86/kvm/vmx/nested.c +@@ -4908,7 +4908,7 @@ void nested_vmx_vmexit(struct kvm_vcpu * + + if (vmx->nested.update_vmcs01_apicv_status) { + vmx->nested.update_vmcs01_apicv_status = false; +- kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu); ++ vmx_refresh_apicv_exec_ctrl(vcpu); + } + + if (vmx->nested.update_vmcs01_hwapic_isr) { +--- a/arch/x86/kvm/vmx/vmx.c ++++ b/arch/x86/kvm/vmx/vmx.c +@@ -4451,7 +4451,7 @@ static u32 vmx_vmexit_ctrl(void) + ~(VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | VM_EXIT_LOAD_IA32_EFER); + } + +-static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) ++void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) + { + struct vcpu_vmx *vmx = to_vmx(vcpu); + +--- a/arch/x86/kvm/vmx/vmx.h ++++ b/arch/x86/kvm/vmx/vmx.h +@@ -395,6 +395,7 @@ void __vmx_set_segment(struct kvm_vcpu * + u64 construct_eptp(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_level); + + bool vmx_guest_inject_ac(struct kvm_vcpu *vcpu); ++void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu); + void vmx_update_exception_bitmap(struct kvm_vcpu *vcpu); + bool vmx_nmi_blocked(struct kvm_vcpu *vcpu); + bool __vmx_interrupt_blocked(struct kvm_vcpu *vcpu); diff --git a/queue-6.6/media-amphion-add-a-frame-flush-mode-for-decoder.patch b/queue-6.6/media-amphion-add-a-frame-flush-mode-for-decoder.patch new file mode 100644 index 0000000000..33d3cdc22f --- /dev/null +++ b/queue-6.6/media-amphion-add-a-frame-flush-mode-for-decoder.patch @@ -0,0 +1,64 @@ +From stable+bounces-204936-greg=kroah.com@vger.kernel.org Mon Jan 5 22:21:33 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:18:07 -0500 +Subject: media: amphion: Add a frame flush mode for decoder +To: stable@vger.kernel.org +Cc: Ming Qian , Nicolas Dufresne , Sebastian Fricke , Hans Verkuil , Sasha Levin +Message-ID: <20260105211809.2802485-1-sashal@kernel.org> + +From: Ming Qian + +[ Upstream commit 9ea16ba6eaf93f25f61855751f71e2e701709ddf ] + +By default the amphion decoder will pre-parse 3 frames before starting +to decode the first frame. Alternatively, a block of flush padding data +can be appended to the frame, which will ensure that the decoder can +start decoding immediately after parsing the flush padding data, thus +potentially reducing decoding latency. + +This mode was previously only enabled, when the display delay was set to +0. Allow the user to manually toggle the use of that mode via a module +parameter called low_latency, which enables the mode without +changing the display order. + +Signed-off-by: Ming Qian +Reviewed-by: Nicolas Dufresne +Signed-off-by: Sebastian Fricke +Signed-off-by: Hans Verkuil +Stable-dep-of: 634c2cd17bd0 ("media: amphion: Remove vpu_vb_is_codecconfig") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/amphion/vpu_malone.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +--- a/drivers/media/platform/amphion/vpu_malone.c ++++ b/drivers/media/platform/amphion/vpu_malone.c +@@ -25,6 +25,10 @@ + #include "vpu_imx8q.h" + #include "vpu_malone.h" + ++static bool low_latency; ++module_param(low_latency, bool, 0644); ++MODULE_PARM_DESC(low_latency, "Set low latency frame flush mode: 0 (disable) or 1 (enable)"); ++ + #define CMD_SIZE 25600 + #define MSG_SIZE 25600 + #define CODEC_SIZE 0x1000 +@@ -1567,7 +1571,15 @@ static int vpu_malone_input_frame_data(s + + vpu_malone_update_wptr(str_buf, wptr); + +- if (disp_imm && !vpu_vb_is_codecconfig(vbuf)) { ++ /* ++ * Enable the low latency flush mode if display delay is set to 0 ++ * or the low latency frame flush mode if it is set to 1. ++ * The low latency flush mode requires some padding data to be appended to each frame, ++ * but there must not be any padding data between the sequence header and the frame. ++ * This module is currently only supported for the H264 and HEVC formats, ++ * for other formats, vpu_malone_add_scode() will return 0. ++ */ ++ if ((disp_imm || low_latency) && !vpu_vb_is_codecconfig(vbuf)) { + ret = vpu_malone_add_scode(inst->core->iface, + inst->id, + &inst->stream_buffer, diff --git a/queue-6.6/media-amphion-make-some-vpu_v4l2-functions-static.patch b/queue-6.6/media-amphion-make-some-vpu_v4l2-functions-static.patch new file mode 100644 index 0000000000..5dcf818303 --- /dev/null +++ b/queue-6.6/media-amphion-make-some-vpu_v4l2-functions-static.patch @@ -0,0 +1,98 @@ +From stable+bounces-204937-greg=kroah.com@vger.kernel.org Mon Jan 5 22:18:14 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:18:08 -0500 +Subject: media: amphion: Make some vpu_v4l2 functions static +To: stable@vger.kernel.org +Cc: Laurent Pinchart , Ming Qian , Hans Verkuil , Sasha Levin +Message-ID: <20260105211809.2802485-2-sashal@kernel.org> + +From: Laurent Pinchart + +[ Upstream commit 5d1e54bb4dc6741284a3ed587e994308ddee2f16 ] + +Some functions defined in vpu_v4l2.c are never used outside of that +compilation unit. Make them static. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Ming Qian +Signed-off-by: Hans Verkuil +Stable-dep-of: 634c2cd17bd0 ("media: amphion: Remove vpu_vb_is_codecconfig") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/amphion/vpu_v4l2.c | 12 +++++++++--- + drivers/media/platform/amphion/vpu_v4l2.h | 8 -------- + 2 files changed, 9 insertions(+), 11 deletions(-) + +--- a/drivers/media/platform/amphion/vpu_v4l2.c ++++ b/drivers/media/platform/amphion/vpu_v4l2.c +@@ -24,6 +24,11 @@ + #include "vpu_msgs.h" + #include "vpu_helpers.h" + ++static char *vpu_type_name(u32 type) ++{ ++ return V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture"; ++} ++ + void vpu_inst_lock(struct vpu_inst *inst) + { + mutex_lock(&inst->lock); +@@ -42,7 +47,7 @@ dma_addr_t vpu_get_vb_phy_addr(struct vb + vb->planes[plane_no].data_offset; + } + +-unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no) ++static unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no) + { + if (plane_no >= vb->num_planes) + return 0; +@@ -74,7 +79,7 @@ void vpu_v4l2_set_error(struct vpu_inst + vpu_inst_unlock(inst); + } + +-int vpu_notify_eos(struct vpu_inst *inst) ++static int vpu_notify_eos(struct vpu_inst *inst) + { + static const struct v4l2_event ev = { + .id = 0, +@@ -546,7 +551,8 @@ static void vpu_vb2_buf_finish(struct vb + call_void_vop(inst, on_queue_empty, q->type); + } + +-void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state) ++static void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, ++ enum vb2_buffer_state state) + { + struct vb2_v4l2_buffer *buf; + +--- a/drivers/media/platform/amphion/vpu_v4l2.h ++++ b/drivers/media/platform/amphion/vpu_v4l2.h +@@ -25,15 +25,12 @@ void vpu_skip_frame(struct vpu_inst *ins + struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence); + struct vb2_v4l2_buffer *vpu_find_buf_by_idx(struct vpu_inst *inst, u32 type, u32 idx); + void vpu_v4l2_set_error(struct vpu_inst *inst); +-int vpu_notify_eos(struct vpu_inst *inst); + int vpu_notify_source_change(struct vpu_inst *inst); + int vpu_set_last_buffer_dequeued(struct vpu_inst *inst, bool eos); +-void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state); + int vpu_get_num_buffers(struct vpu_inst *inst, u32 type); + bool vpu_is_source_empty(struct vpu_inst *inst); + + dma_addr_t vpu_get_vb_phy_addr(struct vb2_buffer *vb, u32 plane_no); +-unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no); + static inline struct vpu_format *vpu_get_format(struct vpu_inst *inst, u32 type) + { + if (V4L2_TYPE_IS_OUTPUT(type)) +@@ -42,11 +39,6 @@ static inline struct vpu_format *vpu_get + return &inst->cap_format; + } + +-static inline char *vpu_type_name(u32 type) +-{ +- return V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture"; +-} +- + static inline int vpu_vb_is_codecconfig(struct vb2_v4l2_buffer *vbuf) + { + #ifdef V4L2_BUF_FLAG_CODECCONFIG diff --git a/queue-6.6/media-amphion-remove-vpu_vb_is_codecconfig.patch b/queue-6.6/media-amphion-remove-vpu_vb_is_codecconfig.patch new file mode 100644 index 0000000000..8decce3e58 --- /dev/null +++ b/queue-6.6/media-amphion-remove-vpu_vb_is_codecconfig.patch @@ -0,0 +1,142 @@ +From stable+bounces-204938-greg=kroah.com@vger.kernel.org Mon Jan 5 22:18:15 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:18:09 -0500 +Subject: media: amphion: Remove vpu_vb_is_codecconfig +To: stable@vger.kernel.org +Cc: Ming Qian , Nicolas Dufresne , Hans Verkuil , Sasha Levin +Message-ID: <20260105211809.2802485-3-sashal@kernel.org> + +From: Ming Qian + +[ Upstream commit 634c2cd17bd021487c57b95973bddb14be8002ff ] + +Currently the function vpu_vb_is_codecconfig() always returns 0. +Delete it and its related code. + +Fixes: 3cd084519c6f ("media: amphion: add vpu v4l2 m2m support") +Cc: stable@vger.kernel.org +Signed-off-by: Ming Qian +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/amphion/vpu_malone.c | 23 +++-------------------- + drivers/media/platform/amphion/vpu_v4l2.c | 10 ---------- + drivers/media/platform/amphion/vpu_v4l2.h | 10 ---------- + 3 files changed, 3 insertions(+), 40 deletions(-) + +--- a/drivers/media/platform/amphion/vpu_malone.c ++++ b/drivers/media/platform/amphion/vpu_malone.c +@@ -1320,22 +1320,18 @@ static int vpu_malone_insert_scode_vc1_g + { + if (!scode->inst->total_input_count) + return 0; +- if (vpu_vb_is_codecconfig(to_vb2_v4l2_buffer(scode->vb))) +- scode->need_data = 0; + return 0; + } + + static int vpu_malone_insert_scode_vc1_g_pic(struct malone_scode_t *scode) + { +- struct vb2_v4l2_buffer *vbuf; + u8 nal_hdr[MALONE_VC1_NAL_HEADER_LEN]; + u32 *data = NULL; + int ret; + +- vbuf = to_vb2_v4l2_buffer(scode->vb); + data = vb2_plane_vaddr(scode->vb, 0); + +- if (scode->inst->total_input_count == 0 || vpu_vb_is_codecconfig(vbuf)) ++ if (scode->inst->total_input_count == 0) + return 0; + if (MALONE_VC1_CONTAIN_NAL(*data)) + return 0; +@@ -1356,8 +1352,6 @@ static int vpu_malone_insert_scode_vc1_l + int size = 0; + u8 rcv_seqhdr[MALONE_VC1_RCV_SEQ_HEADER_LEN]; + +- if (vpu_vb_is_codecconfig(to_vb2_v4l2_buffer(scode->vb))) +- scode->need_data = 0; + if (scode->inst->total_input_count) + return 0; + scode->need_data = 0; +@@ -1543,7 +1537,7 @@ static int vpu_malone_input_frame_data(s + scode.vb = vb; + scode.wptr = wptr; + scode.need_data = 1; +- if (vbuf->sequence == 0 || vpu_vb_is_codecconfig(vbuf)) ++ if (vbuf->sequence == 0) + ret = vpu_malone_insert_scode(&scode, SCODE_SEQUENCE); + + if (ret < 0) +@@ -1579,7 +1573,7 @@ static int vpu_malone_input_frame_data(s + * This module is currently only supported for the H264 and HEVC formats, + * for other formats, vpu_malone_add_scode() will return 0. + */ +- if ((disp_imm || low_latency) && !vpu_vb_is_codecconfig(vbuf)) { ++ if (disp_imm || low_latency) { + ret = vpu_malone_add_scode(inst->core->iface, + inst->id, + &inst->stream_buffer, +@@ -1626,7 +1620,6 @@ int vpu_malone_input_frame(struct vpu_sh + struct vpu_inst *inst, struct vb2_buffer *vb) + { + struct vpu_dec_ctrl *hc = shared->priv; +- struct vb2_v4l2_buffer *vbuf; + struct vpu_malone_str_buffer __iomem *str_buf = hc->str_buf[inst->id]; + u32 disp_imm = hc->codec_param[inst->id].disp_imm; + u32 size; +@@ -1640,16 +1633,6 @@ int vpu_malone_input_frame(struct vpu_sh + return ret; + size = ret; + +- /* +- * if buffer only contain codec data, and the timestamp is invalid, +- * don't put the invalid timestamp to resync +- * merge the data to next frame +- */ +- vbuf = to_vb2_v4l2_buffer(vb); +- if (vpu_vb_is_codecconfig(vbuf)) { +- inst->extra_size += size; +- return 0; +- } + if (inst->extra_size) { + size += inst->extra_size; + inst->extra_size = 0; +--- a/drivers/media/platform/amphion/vpu_v4l2.c ++++ b/drivers/media/platform/amphion/vpu_v4l2.c +@@ -342,16 +342,6 @@ struct vb2_v4l2_buffer *vpu_next_src_buf + if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) + return NULL; + +- while (vpu_vb_is_codecconfig(src_buf)) { +- v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx); +- vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); +- v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); +- +- src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx); +- if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) +- return NULL; +- } +- + return src_buf; + } + +--- a/drivers/media/platform/amphion/vpu_v4l2.h ++++ b/drivers/media/platform/amphion/vpu_v4l2.h +@@ -38,14 +38,4 @@ static inline struct vpu_format *vpu_get + else + return &inst->cap_format; + } +- +-static inline int vpu_vb_is_codecconfig(struct vb2_v4l2_buffer *vbuf) +-{ +-#ifdef V4L2_BUF_FLAG_CODECCONFIG +- return (vbuf->flags & V4L2_BUF_FLAG_CODECCONFIG) ? 1 : 0; +-#else +- return 0; +-#endif +-} +- + #endif diff --git a/queue-6.6/media-mediatek-vcodec-use-spinlock-for-context-list-protection-lock.patch b/queue-6.6/media-mediatek-vcodec-use-spinlock-for-context-list-protection-lock.patch new file mode 100644 index 0000000000..39481a36d5 --- /dev/null +++ b/queue-6.6/media-mediatek-vcodec-use-spinlock-for-context-list-protection-lock.patch @@ -0,0 +1,256 @@ +From stable+bounces-204963-greg=kroah.com@vger.kernel.org Tue Jan 6 01:31:59 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 19:31:50 -0500 +Subject: media: mediatek: vcodec: Use spinlock for context list protection lock +To: stable@vger.kernel.org +Cc: Chen-Yu Tsai , Yunfei Dong , Fei Shao , Tomasz Figa , Nicolas Dufresne , Hans Verkuil , Sasha Levin +Message-ID: <20260106003150.2858570-1-sashal@kernel.org> + +From: Chen-Yu Tsai + +[ Upstream commit a5844227e0f030d2af2d85d4aed10c5eca6ca176 ] + +Previously a mutex was added to protect the encoder and decoder context +lists from unexpected changes originating from the SCP IP block, causing +the context pointer to go invalid, resulting in a NULL pointer +dereference in the IPI handler. + +Turns out on the MT8173, the VPU IPI handler is called from hard IRQ +context. This causes a big warning from the scheduler. This was first +reported downstream on the ChromeOS kernels, but is also reproducible +on mainline using Fluster with the FFmpeg v4l2m2m decoders. Even though +the actual capture format is not supported, the affected code paths +are triggered. + +Since this lock just protects the context list and operations on it are +very fast, it should be OK to switch to a spinlock. + +Fixes: 6467cda18c9f ("media: mediatek: vcodec: adding lock to protect decoder context list") +Fixes: afaaf3a0f647 ("media: mediatek: vcodec: adding lock to protect encoder context list") +Cc: Yunfei Dong +Cc: stable@vger.kernel.org +Signed-off-by: Chen-Yu Tsai +Reviewed-by: Fei Shao +Reviewed-by: Tomasz Figa +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +[ adapted file_to_dec_ctx() and file_to_enc_ctx() helper calls to equivalent fh_to_dec_ctx(file->private_data) and fh_to_enc_ctx(file->private_data) pattern ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c | 10 +++++--- + drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c | 12 +++++----- + drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h | 2 - + drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c | 5 ++-- + drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c | 12 +++++----- + drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h | 2 - + drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c | 5 ++-- + 7 files changed, 28 insertions(+), 20 deletions(-) + +--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c ++++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c +@@ -47,30 +47,32 @@ static void mtk_vcodec_vpu_reset_dec_han + { + struct mtk_vcodec_dec_dev *dev = priv; + struct mtk_vcodec_dec_ctx *ctx; ++ unsigned long flags; + + dev_err(&dev->plat_dev->dev, "Watchdog timeout!!"); + +- mutex_lock(&dev->dev_ctx_lock); ++ spin_lock_irqsave(&dev->dev_ctx_lock, flags); + list_for_each_entry(ctx, &dev->ctx_list, list) { + ctx->state = MTK_STATE_ABORT; + mtk_v4l2_vdec_dbg(0, ctx, "[%d] Change to state MTK_STATE_ABORT", ctx->id); + } +- mutex_unlock(&dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); + } + + static void mtk_vcodec_vpu_reset_enc_handler(void *priv) + { + struct mtk_vcodec_enc_dev *dev = priv; + struct mtk_vcodec_enc_ctx *ctx; ++ unsigned long flags; + + dev_err(&dev->plat_dev->dev, "Watchdog timeout!!"); + +- mutex_lock(&dev->dev_ctx_lock); ++ spin_lock_irqsave(&dev->dev_ctx_lock, flags); + list_for_each_entry(ctx, &dev->ctx_list, list) { + ctx->state = MTK_STATE_ABORT; + mtk_v4l2_vdec_dbg(0, ctx, "[%d] Change to state MTK_STATE_ABORT", ctx->id); + } +- mutex_unlock(&dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); + } + + static const struct mtk_vcodec_fw_ops mtk_vcodec_vpu_msg = { +--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c ++++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c +@@ -198,6 +198,7 @@ static int fops_vcodec_open(struct file + struct mtk_vcodec_dec_ctx *ctx = NULL; + int ret = 0, i, hw_count; + struct vb2_queue *src_vq; ++ unsigned long flags; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) +@@ -268,9 +269,9 @@ static int fops_vcodec_open(struct file + + ctx->dev->vdec_pdata->init_vdec_params(ctx); + +- mutex_lock(&dev->dev_ctx_lock); ++ spin_lock_irqsave(&dev->dev_ctx_lock, flags); + list_add(&ctx->list, &dev->ctx_list); +- mutex_unlock(&dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); + mtk_vcodec_dbgfs_create(ctx); + + mutex_unlock(&dev->dev_mutex); +@@ -295,6 +296,7 @@ static int fops_vcodec_release(struct fi + { + struct mtk_vcodec_dec_dev *dev = video_drvdata(file); + struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(file->private_data); ++ unsigned long flags; + + mtk_v4l2_vdec_dbg(0, ctx, "[%d] decoder", ctx->id); + mutex_lock(&dev->dev_mutex); +@@ -313,9 +315,9 @@ static int fops_vcodec_release(struct fi + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); + + mtk_vcodec_dbgfs_remove(dev, ctx->id); +- mutex_lock(&dev->dev_ctx_lock); ++ spin_lock_irqsave(&dev->dev_ctx_lock, flags); + list_del_init(&ctx->list); +- mutex_unlock(&dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); + kfree(ctx); + mutex_unlock(&dev->dev_mutex); + return 0; +@@ -382,7 +384,7 @@ static int mtk_vcodec_probe(struct platf + for (i = 0; i < MTK_VDEC_HW_MAX; i++) + mutex_init(&dev->dec_mutex[i]); + mutex_init(&dev->dev_mutex); +- mutex_init(&dev->dev_ctx_lock); ++ spin_lock_init(&dev->dev_ctx_lock); + spin_lock_init(&dev->irqlock); + + snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", +--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h ++++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h +@@ -271,7 +271,7 @@ struct mtk_vcodec_dec_dev { + /* decoder hardware mutex lock */ + struct mutex dec_mutex[MTK_VDEC_HW_MAX]; + struct mutex dev_mutex; +- struct mutex dev_ctx_lock; ++ spinlock_t dev_ctx_lock; + struct workqueue_struct *decode_workqueue; + + spinlock_t irqlock; +--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c ++++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c +@@ -75,16 +75,17 @@ static void handle_get_param_msg_ack(con + static bool vpu_dec_check_ap_inst(struct mtk_vcodec_dec_dev *dec_dev, struct vdec_vpu_inst *vpu) + { + struct mtk_vcodec_dec_ctx *ctx; ++ unsigned long flags; + int ret = false; + +- mutex_lock(&dec_dev->dev_ctx_lock); ++ spin_lock_irqsave(&dec_dev->dev_ctx_lock, flags); + list_for_each_entry(ctx, &dec_dev->ctx_list, list) { + if (!IS_ERR_OR_NULL(ctx) && ctx->vpu_inst == vpu) { + ret = true; + break; + } + } +- mutex_unlock(&dec_dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dec_dev->dev_ctx_lock, flags); + + return ret; + } +--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c ++++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c +@@ -117,6 +117,7 @@ static int fops_vcodec_open(struct file + struct mtk_vcodec_enc_ctx *ctx = NULL; + int ret = 0; + struct vb2_queue *src_vq; ++ unsigned long flags; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) +@@ -177,9 +178,9 @@ static int fops_vcodec_open(struct file + mtk_v4l2_venc_dbg(2, ctx, "Create instance [%d]@%p m2m_ctx=%p ", + ctx->id, ctx, ctx->m2m_ctx); + +- mutex_lock(&dev->dev_ctx_lock); ++ spin_lock_irqsave(&dev->dev_ctx_lock, flags); + list_add(&ctx->list, &dev->ctx_list); +- mutex_unlock(&dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); + + mutex_unlock(&dev->dev_mutex); + mtk_v4l2_venc_dbg(0, ctx, "%s encoder [%d]", dev_name(&dev->plat_dev->dev), +@@ -204,6 +205,7 @@ static int fops_vcodec_release(struct fi + { + struct mtk_vcodec_enc_dev *dev = video_drvdata(file); + struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(file->private_data); ++ unsigned long flags; + + mtk_v4l2_venc_dbg(1, ctx, "[%d] encoder", ctx->id); + mutex_lock(&dev->dev_mutex); +@@ -214,9 +216,9 @@ static int fops_vcodec_release(struct fi + v4l2_fh_exit(&ctx->fh); + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); + +- mutex_lock(&dev->dev_ctx_lock); ++ spin_lock_irqsave(&dev->dev_ctx_lock, flags); + list_del_init(&ctx->list); +- mutex_unlock(&dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); + kfree(ctx); + mutex_unlock(&dev->dev_mutex); + return 0; +@@ -298,7 +300,7 @@ static int mtk_vcodec_probe(struct platf + + mutex_init(&dev->enc_mutex); + mutex_init(&dev->dev_mutex); +- mutex_init(&dev->dev_ctx_lock); ++ spin_lock_init(&dev->dev_ctx_lock); + spin_lock_init(&dev->irqlock); + + snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", +--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h ++++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h +@@ -206,7 +206,7 @@ struct mtk_vcodec_enc_dev { + /* encoder hardware mutex lock */ + struct mutex enc_mutex; + struct mutex dev_mutex; +- struct mutex dev_ctx_lock; ++ spinlock_t dev_ctx_lock; + struct workqueue_struct *encode_workqueue; + + int enc_irq; +--- a/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c ++++ b/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c +@@ -45,16 +45,17 @@ static void handle_enc_encode_msg(struct + static bool vpu_enc_check_ap_inst(struct mtk_vcodec_enc_dev *enc_dev, struct venc_vpu_inst *vpu) + { + struct mtk_vcodec_enc_ctx *ctx; ++ unsigned long flags; + int ret = false; + +- mutex_lock(&enc_dev->dev_ctx_lock); ++ spin_lock_irqsave(&enc_dev->dev_ctx_lock, flags); + list_for_each_entry(ctx, &enc_dev->ctx_list, list) { + if (!IS_ERR_OR_NULL(ctx) && ctx->vpu_inst == vpu) { + ret = true; + break; + } + } +- mutex_unlock(&enc_dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&enc_dev->dev_ctx_lock, flags); + + return ret; + } diff --git a/queue-6.6/media-verisilicon-fix-cpu-stalls-on-g2-bus-error.patch b/queue-6.6/media-verisilicon-fix-cpu-stalls-on-g2-bus-error.patch new file mode 100644 index 0000000000..aa05d87988 --- /dev/null +++ b/queue-6.6/media-verisilicon-fix-cpu-stalls-on-g2-bus-error.patch @@ -0,0 +1,239 @@ +From stable+bounces-204859-greg=kroah.com@vger.kernel.org Mon Jan 5 18:07:47 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 11:49:00 -0500 +Subject: media: verisilicon: Fix CPU stalls on G2 bus error +To: stable@vger.kernel.org +Cc: Nicolas Dufresne , Benjamin Gaignard , Hans Verkuil , Sasha Levin +Message-ID: <20260105164900.2676927-3-sashal@kernel.org> + +From: Nicolas Dufresne + +[ Upstream commit 19c286b755072a22a063052f530a6b1fac8a1f63 ] + +In some seek stress tests, we are getting IRQ from the G2 decoder where +the dec_bus_int and the dec_e bits are high, meaning the decoder is +still running despite the error. + +Fix this by reworking the IRQ handler to only finish the job once we +have reached completion and move the software reset to when our software +watchdog triggers. + +This way, we let the hardware continue on errors when it did not self +reset and in worse case scenario the hardware timeout will +automatically stop it. The actual error will be fixed in a follow up +patch. + +Fixes: 3385c514ecc5a ("media: hantro: Convert imx8m_vpu_g2_irq to helper") +Cc: stable@vger.kernel.org +Reviewed-by: Benjamin Gaignard +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/verisilicon/hantro_g2.c | 84 ++++++++++++---- + drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c | 2 + drivers/media/platform/verisilicon/hantro_g2_regs.h | 13 ++ + drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c | 2 + drivers/media/platform/verisilicon/hantro_hw.h | 1 + drivers/media/platform/verisilicon/imx8m_vpu_hw.c | 2 + 6 files changed, 83 insertions(+), 21 deletions(-) + +--- a/drivers/media/platform/verisilicon/hantro_g2.c ++++ b/drivers/media/platform/verisilicon/hantro_g2.c +@@ -5,43 +5,93 @@ + * Copyright (C) 2021 Collabora Ltd, Andrzej Pietrasiewicz + */ + ++#include + #include "hantro_hw.h" + #include "hantro_g2_regs.h" + + #define G2_ALIGN 16 + +-void hantro_g2_check_idle(struct hantro_dev *vpu) ++static bool hantro_g2_active(struct hantro_ctx *ctx) + { +- int i; ++ struct hantro_dev *vpu = ctx->dev; ++ u32 status; ++ ++ status = vdpu_read(vpu, G2_REG_INTERRUPT); ++ ++ return (status & G2_REG_INTERRUPT_DEC_E); ++} + +- for (i = 0; i < 3; i++) { +- u32 status; ++/** ++ * hantro_g2_reset: ++ * @ctx: the hantro context ++ * ++ * Emulates a reset using Hantro abort function. Failing this procedure would ++ * results in programming a running IP which leads to CPU hang. ++ * ++ * Using a hard reset procedure instead is prefferred. ++ */ ++void hantro_g2_reset(struct hantro_ctx *ctx) ++{ ++ struct hantro_dev *vpu = ctx->dev; ++ u32 status; + +- /* Make sure the VPU is idle */ +- status = vdpu_read(vpu, G2_REG_INTERRUPT); +- if (status & G2_REG_INTERRUPT_DEC_E) { +- dev_warn(vpu->dev, "device still running, aborting"); +- status |= G2_REG_INTERRUPT_DEC_ABORT_E | G2_REG_INTERRUPT_DEC_IRQ_DIS; +- vdpu_write(vpu, status, G2_REG_INTERRUPT); +- } ++ status = vdpu_read(vpu, G2_REG_INTERRUPT); ++ if (status & G2_REG_INTERRUPT_DEC_E) { ++ dev_warn_ratelimited(vpu->dev, "device still running, aborting"); ++ status |= G2_REG_INTERRUPT_DEC_ABORT_E | G2_REG_INTERRUPT_DEC_IRQ_DIS; ++ vdpu_write(vpu, status, G2_REG_INTERRUPT); ++ ++ do { ++ mdelay(1); ++ } while (hantro_g2_active(ctx)); + } + } + + irqreturn_t hantro_g2_irq(int irq, void *dev_id) + { + struct hantro_dev *vpu = dev_id; +- enum vb2_buffer_state state; + u32 status; + + status = vdpu_read(vpu, G2_REG_INTERRUPT); +- state = (status & G2_REG_INTERRUPT_DEC_RDY_INT) ? +- VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + +- vdpu_write(vpu, 0, G2_REG_INTERRUPT); +- vdpu_write(vpu, G2_REG_CONFIG_DEC_CLK_GATE_E, G2_REG_CONFIG); ++ if (!(status & G2_REG_INTERRUPT_DEC_IRQ)) ++ return IRQ_NONE; ++ ++ hantro_reg_write(vpu, &g2_dec_irq, 0); ++ hantro_reg_write(vpu, &g2_dec_int_stat, 0); ++ hantro_reg_write(vpu, &g2_clk_gate_e, 1); ++ ++ if (status & G2_REG_INTERRUPT_DEC_RDY_INT) { ++ hantro_irq_done(vpu, VB2_BUF_STATE_DONE); ++ return IRQ_HANDLED; ++ } ++ ++ if (status & G2_REG_INTERRUPT_DEC_ABORT_INT) { ++ /* disabled on abort, though lets be safe and handle it */ ++ dev_warn_ratelimited(vpu->dev, "decode operation aborted."); ++ return IRQ_HANDLED; ++ } ++ ++ if (status & G2_REG_INTERRUPT_DEC_LAST_SLICE_INT) ++ dev_warn_ratelimited(vpu->dev, "not all macroblocks were decoded."); ++ ++ if (status & G2_REG_INTERRUPT_DEC_BUS_INT) ++ dev_warn_ratelimited(vpu->dev, "bus error detected."); ++ ++ if (status & G2_REG_INTERRUPT_DEC_ERROR_INT) ++ dev_warn_ratelimited(vpu->dev, "decode error detected."); + +- hantro_irq_done(vpu, state); ++ if (status & G2_REG_INTERRUPT_DEC_TIMEOUT) ++ dev_warn_ratelimited(vpu->dev, "frame decode timed out."); ++ ++ /** ++ * If the decoding haven't stopped, let it continue. The hardware timeout ++ * will trigger if it is trully stuck. ++ */ ++ if (status & G2_REG_INTERRUPT_DEC_E) ++ return IRQ_HANDLED; + ++ hantro_irq_done(vpu, VB2_BUF_STATE_ERROR); + return IRQ_HANDLED; + } + +--- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c ++++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c +@@ -578,8 +578,6 @@ int hantro_g2_hevc_dec_run(struct hantro + struct hantro_dev *vpu = ctx->dev; + int ret; + +- hantro_g2_check_idle(vpu); +- + /* Prepare HEVC decoder context. */ + ret = hantro_hevc_dec_prepare_run(ctx); + if (ret) +--- a/drivers/media/platform/verisilicon/hantro_g2_regs.h ++++ b/drivers/media/platform/verisilicon/hantro_g2_regs.h +@@ -22,7 +22,14 @@ + #define G2_REG_VERSION G2_SWREG(0) + + #define G2_REG_INTERRUPT G2_SWREG(1) ++#define G2_REG_INTERRUPT_DEC_LAST_SLICE_INT BIT(19) ++#define G2_REG_INTERRUPT_DEC_TIMEOUT BIT(18) ++#define G2_REG_INTERRUPT_DEC_ERROR_INT BIT(16) ++#define G2_REG_INTERRUPT_DEC_BUF_INT BIT(14) ++#define G2_REG_INTERRUPT_DEC_BUS_INT BIT(13) + #define G2_REG_INTERRUPT_DEC_RDY_INT BIT(12) ++#define G2_REG_INTERRUPT_DEC_ABORT_INT BIT(11) ++#define G2_REG_INTERRUPT_DEC_IRQ BIT(8) + #define G2_REG_INTERRUPT_DEC_ABORT_E BIT(5) + #define G2_REG_INTERRUPT_DEC_IRQ_DIS BIT(4) + #define G2_REG_INTERRUPT_DEC_E BIT(0) +@@ -35,6 +42,9 @@ + #define BUS_WIDTH_128 2 + #define BUS_WIDTH_256 3 + ++#define g2_dec_int_stat G2_DEC_REG(1, 11, 0xf) ++#define g2_dec_irq G2_DEC_REG(1, 8, 0x1) ++ + #define g2_strm_swap G2_DEC_REG(2, 28, 0xf) + #define g2_strm_swap_old G2_DEC_REG(2, 27, 0x1f) + #define g2_pic_swap G2_DEC_REG(2, 22, 0x1f) +@@ -225,6 +235,9 @@ + #define vp9_filt_level_seg5 G2_DEC_REG(19, 8, 0x3f) + #define vp9_quant_seg5 G2_DEC_REG(19, 0, 0xff) + ++#define g2_timemout_override_e G2_DEC_REG(45, 31, 0x1) ++#define g2_timemout_cycles G2_DEC_REG(45, 0, 0x7fffffff) ++ + #define hevc_cur_poc_00 G2_DEC_REG(46, 24, 0xff) + #define hevc_cur_poc_01 G2_DEC_REG(46, 16, 0xff) + #define hevc_cur_poc_02 G2_DEC_REG(46, 8, 0xff) +--- a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c ++++ b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c +@@ -893,8 +893,6 @@ int hantro_g2_vp9_dec_run(struct hantro_ + struct vb2_v4l2_buffer *dst; + int ret; + +- hantro_g2_check_idle(ctx->dev); +- + ret = start_prepare_run(ctx, &decode_params); + if (ret) { + hantro_end_prepare_run(ctx); +--- a/drivers/media/platform/verisilicon/hantro_hw.h ++++ b/drivers/media/platform/verisilicon/hantro_hw.h +@@ -541,6 +541,7 @@ void hantro_g2_vp9_dec_done(struct hantr + int hantro_vp9_dec_init(struct hantro_ctx *ctx); + void hantro_vp9_dec_exit(struct hantro_ctx *ctx); + void hantro_g2_check_idle(struct hantro_dev *vpu); ++void hantro_g2_reset(struct hantro_ctx *ctx); + irqreturn_t hantro_g2_irq(int irq, void *dev_id); + + #endif /* HANTRO_HW_H_ */ +--- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c ++++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c +@@ -312,11 +312,13 @@ static const struct hantro_codec_ops imx + static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = { + [HANTRO_MODE_HEVC_DEC] = { + .run = hantro_g2_hevc_dec_run, ++ .reset = hantro_g2_reset, + .init = hantro_hevc_dec_init, + .exit = hantro_hevc_dec_exit, + }, + [HANTRO_MODE_VP9_DEC] = { + .run = hantro_g2_vp9_dec_run, ++ .reset = hantro_g2_reset, + .done = hantro_g2_vp9_dec_done, + .init = hantro_vp9_dec_init, + .exit = hantro_vp9_dec_exit, diff --git a/queue-6.6/media-verisilicon-g2-use-common-helpers-to-compute-chroma-and-mv-offsets.patch b/queue-6.6/media-verisilicon-g2-use-common-helpers-to-compute-chroma-and-mv-offsets.patch new file mode 100644 index 0000000000..f2cb51e3d5 --- /dev/null +++ b/queue-6.6/media-verisilicon-g2-use-common-helpers-to-compute-chroma-and-mv-offsets.patch @@ -0,0 +1,163 @@ +From stable+bounces-204858-greg=kroah.com@vger.kernel.org Mon Jan 5 17:50:22 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 11:48:59 -0500 +Subject: media: verisilicon: g2: Use common helpers to compute chroma and mv offsets +To: stable@vger.kernel.org +Cc: Benjamin Gaignard , Andrzej Pietrasiewicz , Ezequiel Garcia , Philipp Zabel , Hans Verkuil , Mauro Carvalho Chehab , Sasha Levin +Message-ID: <20260105164900.2676927-2-sashal@kernel.org> + +From: Benjamin Gaignard + +[ Upstream commit 3eeaee737dcee3c32e256870dbc2687a2a6fe970 ] + +HEVC and VP9 are running on the same hardware and share the same +chroma and motion vectors offset constraint. +Create common helpers functions for these computation. +Source and destination buffer height may not be the same because +alignment constraint are different so use destination height to +compute chroma offset because we target this buffer as hardware +output. +To be able to use the helpers in both VP9 HEVC code remove dec_params +and use context->bit_depth instead. + +Signed-off-by: Benjamin Gaignard +Reviewed-by: Andrzej Pietrasiewicz +CC: Ezequiel Garcia +CC: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Stable-dep-of: 19c286b75507 ("media: verisilicon: Fix CPU stalls on G2 bus error") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/verisilicon/hantro_g2.c | 14 ++++++++ + drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c | 18 +---------- + drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c | 26 ++-------------- + drivers/media/platform/verisilicon/hantro_hw.h | 3 + + 4 files changed, 23 insertions(+), 38 deletions(-) + +--- a/drivers/media/platform/verisilicon/hantro_g2.c ++++ b/drivers/media/platform/verisilicon/hantro_g2.c +@@ -8,6 +8,8 @@ + #include "hantro_hw.h" + #include "hantro_g2_regs.h" + ++#define G2_ALIGN 16 ++ + void hantro_g2_check_idle(struct hantro_dev *vpu) + { + int i; +@@ -42,3 +44,15 @@ irqreturn_t hantro_g2_irq(int irq, void + + return IRQ_HANDLED; + } ++ ++size_t hantro_g2_chroma_offset(struct hantro_ctx *ctx) ++{ ++ return ctx->dst_fmt.width * ctx->dst_fmt.height * ctx->bit_depth / 8; ++} ++ ++size_t hantro_g2_motion_vectors_offset(struct hantro_ctx *ctx) ++{ ++ size_t cr_offset = hantro_g2_chroma_offset(ctx); ++ ++ return ALIGN((cr_offset * 3) / 2, G2_ALIGN); ++} +--- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c ++++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c +@@ -8,20 +8,6 @@ + #include "hantro_hw.h" + #include "hantro_g2_regs.h" + +-#define G2_ALIGN 16 +- +-static size_t hantro_hevc_chroma_offset(struct hantro_ctx *ctx) +-{ +- return ctx->dst_fmt.width * ctx->dst_fmt.height * ctx->bit_depth / 8; +-} +- +-static size_t hantro_hevc_motion_vectors_offset(struct hantro_ctx *ctx) +-{ +- size_t cr_offset = hantro_hevc_chroma_offset(ctx); +- +- return ALIGN((cr_offset * 3) / 2, G2_ALIGN); +-} +- + static void prepare_tile_info_buffer(struct hantro_ctx *ctx) + { + struct hantro_dev *vpu = ctx->dev; +@@ -395,8 +381,8 @@ static int set_ref(struct hantro_ctx *ct + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; + struct hantro_decoded_buffer *dst; +- size_t cr_offset = hantro_hevc_chroma_offset(ctx); +- size_t mv_offset = hantro_hevc_motion_vectors_offset(ctx); ++ size_t cr_offset = hantro_g2_chroma_offset(ctx); ++ size_t mv_offset = hantro_g2_motion_vectors_offset(ctx); + u32 max_ref_frames; + u16 dpb_longterm_e; + static const struct hantro_reg cur_poc[] = { +--- a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c ++++ b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c +@@ -16,8 +16,6 @@ + #include "hantro_vp9.h" + #include "hantro_g2_regs.h" + +-#define G2_ALIGN 16 +- + enum hantro_ref_frames { + INTRA_FRAME = 0, + LAST_FRAME = 1, +@@ -90,22 +88,6 @@ static int start_prepare_run(struct hant + return 0; + } + +-static size_t chroma_offset(const struct hantro_ctx *ctx, +- const struct v4l2_ctrl_vp9_frame *dec_params) +-{ +- int bytes_per_pixel = dec_params->bit_depth == 8 ? 1 : 2; +- +- return ctx->src_fmt.width * ctx->src_fmt.height * bytes_per_pixel; +-} +- +-static size_t mv_offset(const struct hantro_ctx *ctx, +- const struct v4l2_ctrl_vp9_frame *dec_params) +-{ +- size_t cr_offset = chroma_offset(ctx, dec_params); +- +- return ALIGN((cr_offset * 3) / 2, G2_ALIGN); +-} +- + static struct hantro_decoded_buffer * + get_ref_buf(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp) + { +@@ -156,13 +138,13 @@ static void config_output(struct hantro_ + luma_addr = hantro_get_dec_buf_addr(ctx, &dst->base.vb.vb2_buf); + hantro_write_addr(ctx->dev, G2_OUT_LUMA_ADDR, luma_addr); + +- chroma_addr = luma_addr + chroma_offset(ctx, dec_params); ++ chroma_addr = luma_addr + hantro_g2_chroma_offset(ctx); + hantro_write_addr(ctx->dev, G2_OUT_CHROMA_ADDR, chroma_addr); +- dst->vp9.chroma_offset = chroma_offset(ctx, dec_params); ++ dst->vp9.chroma_offset = hantro_g2_chroma_offset(ctx); + +- mv_addr = luma_addr + mv_offset(ctx, dec_params); ++ mv_addr = luma_addr + hantro_g2_motion_vectors_offset(ctx); + hantro_write_addr(ctx->dev, G2_OUT_MV_ADDR, mv_addr); +- dst->vp9.mv_offset = mv_offset(ctx, dec_params); ++ dst->vp9.mv_offset = hantro_g2_motion_vectors_offset(ctx); + } + + struct hantro_vp9_ref_reg { +--- a/drivers/media/platform/verisilicon/hantro_hw.h ++++ b/drivers/media/platform/verisilicon/hantro_hw.h +@@ -519,6 +519,9 @@ hantro_av1_mv_size(unsigned int width, u + return ALIGN(num_sbs * 384, 16) * 2 + 512; + } + ++size_t hantro_g2_chroma_offset(struct hantro_ctx *ctx); ++size_t hantro_g2_motion_vectors_offset(struct hantro_ctx *ctx); ++ + int hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx); + int rockchip_vpu2_mpeg2_dec_run(struct hantro_ctx *ctx); + void hantro_mpeg2_dec_copy_qtable(u8 *qtable, diff --git a/queue-6.6/media-verisilicon-store-chroma-and-motion-vectors-offset.patch b/queue-6.6/media-verisilicon-store-chroma-and-motion-vectors-offset.patch new file mode 100644 index 0000000000..aa7a8f3c36 --- /dev/null +++ b/queue-6.6/media-verisilicon-store-chroma-and-motion-vectors-offset.patch @@ -0,0 +1,73 @@ +From stable+bounces-204857-greg=kroah.com@vger.kernel.org Mon Jan 5 18:07:45 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 11:48:58 -0500 +Subject: media: verisilicon: Store chroma and motion vectors offset +To: stable@vger.kernel.org +Cc: Benjamin Gaignard , Andrzej Pietrasiewicz , Ezequiel Garcia , Philipp Zabel , Hans Verkuil , Mauro Carvalho Chehab , Sasha Levin +Message-ID: <20260105164900.2676927-1-sashal@kernel.org> + +From: Benjamin Gaignard + +[ Upstream commit 545bf944f978b7468d3a6bd668d9ff6953bc542e ] + +Store computed values of chroma and motion vectors offset because +they depends on width and height values which change if the resolution +change. + +Signed-off-by: Benjamin Gaignard +Reviewed-by: Andrzej Pietrasiewicz +CC: Ezequiel Garcia +CC: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Stable-dep-of: 19c286b75507 ("media: verisilicon: Fix CPU stalls on G2 bus error") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/verisilicon/hantro.h | 2 ++ + drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c | 6 ++++-- + 2 files changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/media/platform/verisilicon/hantro.h ++++ b/drivers/media/platform/verisilicon/hantro.h +@@ -328,6 +328,8 @@ struct hantro_vp9_decoded_buffer_info { + /* Info needed when the decoded frame serves as a reference frame. */ + unsigned short width; + unsigned short height; ++ size_t chroma_offset; ++ size_t mv_offset; + u32 bit_depth : 4; + }; + +--- a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c ++++ b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c +@@ -158,9 +158,11 @@ static void config_output(struct hantro_ + + chroma_addr = luma_addr + chroma_offset(ctx, dec_params); + hantro_write_addr(ctx->dev, G2_OUT_CHROMA_ADDR, chroma_addr); ++ dst->vp9.chroma_offset = chroma_offset(ctx, dec_params); + + mv_addr = luma_addr + mv_offset(ctx, dec_params); + hantro_write_addr(ctx->dev, G2_OUT_MV_ADDR, mv_addr); ++ dst->vp9.mv_offset = mv_offset(ctx, dec_params); + } + + struct hantro_vp9_ref_reg { +@@ -195,7 +197,7 @@ static void config_ref(struct hantro_ctx + luma_addr = hantro_get_dec_buf_addr(ctx, &buf->base.vb.vb2_buf); + hantro_write_addr(ctx->dev, ref_reg->y_base, luma_addr); + +- chroma_addr = luma_addr + chroma_offset(ctx, dec_params); ++ chroma_addr = luma_addr + buf->vp9.chroma_offset; + hantro_write_addr(ctx->dev, ref_reg->c_base, chroma_addr); + } + +@@ -238,7 +240,7 @@ static void config_ref_registers(struct + config_ref(ctx, dst, &ref_regs[2], dec_params, dec_params->alt_frame_ts); + + mv_addr = hantro_get_dec_buf_addr(ctx, &mv_ref->base.vb.vb2_buf) + +- mv_offset(ctx, dec_params); ++ mv_ref->vp9.mv_offset; + hantro_write_addr(ctx->dev, G2_REF_MV_ADDR(0), mv_addr); + + hantro_reg_write(ctx->dev, &vp9_last_sign_bias, diff --git a/queue-6.6/mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch b/queue-6.6/mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch new file mode 100644 index 0000000000..649bd07569 --- /dev/null +++ b/queue-6.6/mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch @@ -0,0 +1,225 @@ +From sashal@kernel.org Mon Jan 5 18:52:24 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 12:52:11 -0500 +Subject: mm/balloon_compaction: convert balloon_page_delete() to balloon_page_finalize() +To: stable@vger.kernel.org +Cc: "David Hildenbrand" , "Lorenzo Stoakes" , "Alistair Popple" , "Al Viro" , "Arnd Bergmann" , "Brendan Jackman" , "Byungchul Park" , "Chengming Zhou" , "Christian Brauner" , "Christophe Leroy" , "Eugenio Pé rez" , "Greg Kroah-Hartman" , "Gregory Price" , "Harry Yoo" , "Huang, Ying" , "Jan Kara" , "Jason Gunthorpe" , "Jason Wang" , "Jerrin Shaji George" , "Johannes Weiner" , "John Hubbard" , "Jonathan Corbet" , "Joshua Hahn" , "Liam Howlett" , "Madhavan Srinivasan" , "Mathew Brost" , "Matthew Wilcox (Oracle)" , "Miaohe Lin" , "Michael Ellerman" , "Michael S. Tsirkin" , "Michal Hocko" , "Mike Rapoport" , "Minchan Kim" , "Naoya Horiguchi" , "Nicholas Piggin" , "Oscar Salvador" , "Peter Xu" , "Qi Zheng" , "Rakie Kim" , "Rik van Riel" , "Sergey Senozhatsky" , "Shakeel Butt" , "Suren Baghdasaryan" , "Vlastimil Babka" , "Xuan Zhuo" , "xu xin" , "Zi Yan" , "Andrew Morton" , "Sasha Levin" +Message-ID: <20260105175213.2699504-2-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit 15504b1163007bbfbd9a63460d5c14737c16e96d ] + +Let's move the removal of the page from the balloon list into the single +caller, to remove the dependency on the PG_isolated flag and clarify +locking requirements. + +Note that for now, balloon_page_delete() was used on two paths: + +(1) Removing a page from the balloon for deflation through + balloon_page_list_dequeue() +(2) Removing an isolated page from the balloon for migration in the + per-driver migration handlers. Isolated pages were already removed from + the balloon list during isolation. + +So instead of relying on the flag, we can just distinguish both cases +directly and handle it accordingly in the caller. + +We'll shuffle the operations a bit such that they logically make more +sense (e.g., remove from the list before clearing flags). + +In balloon migration functions we can now move the balloon_page_finalize() +out of the balloon lock and perform the finalization just before dropping +the balloon reference. + +Document that the page lock is currently required when modifying the +movability aspects of a page; hopefully we can soon decouple this from the +page lock. + +Link: https://lkml.kernel.org/r/20250704102524.326966-3-david@redhat.com +Signed-off-by: David Hildenbrand +Reviewed-by: Lorenzo Stoakes +Cc: Alistair Popple +Cc: Al Viro +Cc: Arnd Bergmann +Cc: Brendan Jackman +Cc: Byungchul Park +Cc: Chengming Zhou +Cc: Christian Brauner +Cc: Christophe Leroy +Cc: Eugenio Pé rez +Cc: Greg Kroah-Hartman +Cc: Gregory Price +Cc: Harry Yoo +Cc: "Huang, Ying" +Cc: Jan Kara +Cc: Jason Gunthorpe +Cc: Jason Wang +Cc: Jerrin Shaji George +Cc: Johannes Weiner +Cc: John Hubbard +Cc: Jonathan Corbet +Cc: Joshua Hahn +Cc: Liam Howlett +Cc: Madhavan Srinivasan +Cc: Mathew Brost +Cc: Matthew Wilcox (Oracle) +Cc: Miaohe Lin +Cc: Michael Ellerman +Cc: "Michael S. Tsirkin" +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Minchan Kim +Cc: Naoya Horiguchi +Cc: Nicholas Piggin +Cc: Oscar Salvador +Cc: Peter Xu +Cc: Qi Zheng +Cc: Rakie Kim +Cc: Rik van Riel +Cc: Sergey Senozhatsky +Cc: Shakeel Butt +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: Xuan Zhuo +Cc: xu xin +Cc: Zi Yan +Signed-off-by: Andrew Morton +Stable-dep-of: 0da2ba35c0d5 ("powerpc/pseries/cmm: adjust BALLOON_MIGRATE when migrating pages") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/platforms/pseries/cmm.c | 2 - + drivers/misc/vmw_balloon.c | 3 -- + drivers/virtio/virtio_balloon.c | 4 --- + include/linux/balloon_compaction.h | 43 +++++++++++++---------------------- + mm/balloon_compaction.c | 3 +- + 5 files changed, 21 insertions(+), 34 deletions(-) + +--- a/arch/powerpc/platforms/pseries/cmm.c ++++ b/arch/powerpc/platforms/pseries/cmm.c +@@ -532,7 +532,6 @@ static int cmm_migratepage(struct balloo + + spin_lock_irqsave(&b_dev_info->pages_lock, flags); + balloon_page_insert(b_dev_info, newpage); +- balloon_page_delete(page); + b_dev_info->isolated_pages--; + spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); + +@@ -542,6 +541,7 @@ static int cmm_migratepage(struct balloo + */ + plpar_page_set_active(page); + ++ balloon_page_finalize(page); + /* balloon page list reference */ + put_page(page); + +--- a/drivers/misc/vmw_balloon.c ++++ b/drivers/misc/vmw_balloon.c +@@ -1789,8 +1789,7 @@ static int vmballoon_migratepage(struct + * @pages_lock . We keep holding @comm_lock since we will need it in a + * second. + */ +- balloon_page_delete(page); +- ++ balloon_page_finalize(page); + put_page(page); + + /* Inflate */ +--- a/drivers/virtio/virtio_balloon.c ++++ b/drivers/virtio/virtio_balloon.c +@@ -789,15 +789,13 @@ static int virtballoon_migratepage(struc + tell_host(vb, vb->inflate_vq); + + /* balloon's page migration 2nd step -- deflate "page" */ +- spin_lock_irqsave(&vb_dev_info->pages_lock, flags); +- balloon_page_delete(page); +- spin_unlock_irqrestore(&vb_dev_info->pages_lock, flags); + vb->num_pfns = VIRTIO_BALLOON_PAGES_PER_PAGE; + set_page_pfns(vb, vb->pfns, page); + tell_host(vb, vb->deflate_vq); + + mutex_unlock(&vb->balloon_lock); + ++ balloon_page_finalize(page); + put_page(page); /* balloon reference */ + + return MIGRATEPAGE_SUCCESS; +--- a/include/linux/balloon_compaction.h ++++ b/include/linux/balloon_compaction.h +@@ -98,27 +98,6 @@ static inline void balloon_page_insert(s + } + + /* +- * balloon_page_delete - delete a page from balloon's page list and clear +- * the page->private assignement accordingly. +- * @page : page to be released from balloon's page list +- * +- * Caller must ensure the page is locked and the spin_lock protecting balloon +- * pages list is held before deleting a page from the balloon device. +- */ +-static inline void balloon_page_delete(struct page *page) +-{ +- __ClearPageOffline(page); +- __ClearPageMovable(page); +- set_page_private(page, 0); +- /* +- * No touch page.lru field once @page has been isolated +- * because VM is using the field. +- */ +- if (!PageIsolated(page)) +- list_del(&page->lru); +-} +- +-/* + * balloon_page_device - get the b_dev_info descriptor for the balloon device + * that enqueues the given page. + */ +@@ -141,12 +120,6 @@ static inline void balloon_page_insert(s + list_add(&page->lru, &balloon->pages); + } + +-static inline void balloon_page_delete(struct page *page) +-{ +- __ClearPageOffline(page); +- list_del(&page->lru); +-} +- + static inline gfp_t balloon_mapping_gfp_mask(void) + { + return GFP_HIGHUSER; +@@ -155,6 +128,22 @@ static inline gfp_t balloon_mapping_gfp_ + #endif /* CONFIG_BALLOON_COMPACTION */ + + /* ++ * balloon_page_finalize - prepare a balloon page that was removed from the ++ * balloon list for release to the page allocator ++ * @page: page to be released to the page allocator ++ * ++ * Caller must ensure that the page is locked. ++ */ ++static inline void balloon_page_finalize(struct page *page) ++{ ++ if (IS_ENABLED(CONFIG_BALLOON_COMPACTION)) { ++ __ClearPageMovable(page); ++ set_page_private(page, 0); ++ } ++ __ClearPageOffline(page); ++} ++ ++/* + * balloon_page_push - insert a page into a page list. + * @head : pointer to list + * @page : page to be added +--- a/mm/balloon_compaction.c ++++ b/mm/balloon_compaction.c +@@ -93,7 +93,8 @@ size_t balloon_page_list_dequeue(struct + if (!trylock_page(page)) + continue; + +- balloon_page_delete(page); ++ list_del(&page->lru); ++ balloon_page_finalize(page); + __count_vm_event(BALLOON_DEFLATE); + list_add(&page->lru, pages); + unlock_page(page); diff --git a/queue-6.6/mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch b/queue-6.6/mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch new file mode 100644 index 0000000000..7b7bc53c92 --- /dev/null +++ b/queue-6.6/mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch @@ -0,0 +1,109 @@ +From sashal@kernel.org Mon Jan 5 18:52:20 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 12:52:10 -0500 +Subject: mm/balloon_compaction: we cannot have isolated pages in the balloon list +To: stable@vger.kernel.org +Cc: "David Hildenbrand" , "Zi Yan" , "Lorenzo Stoakes" , "Alistair Popple" , "Al Viro" , "Arnd Bergmann" , "Brendan Jackman" , "Byungchul Park" , "Chengming Zhou" , "Christian Brauner" , "Christophe Leroy" , "Eugenio Pé rez" , "Greg Kroah-Hartman" , "Gregory Price" , "Huang, Ying" , "Jan Kara" , "Jason Gunthorpe" , "Jason Wang" , "Jerrin Shaji George" , "Johannes Weiner" , "John Hubbard" , "Jonathan Corbet" , "Joshua Hahn" , "Liam Howlett" , "Madhavan Srinivasan" , "Mathew Brost" , "Matthew Wilcox (Oracle)" , "Miaohe Lin" , "Michael Ellerman" , "Michael S. Tsirkin" , "Michal Hocko" , "Mike Rapoport" , "Minchan Kim" , "Naoya Horiguchi" , "Nicholas Piggin" , "Oscar Salvador" , "Peter Xu" , "Qi Zheng" , "Rakie Kim" , "Rik van Riel" , "Sergey Senozhatsky" , "Shakeel Butt" , "Suren Baghdasaryan" , "Vlastimil Babka" , "Xuan Zhuo" , "xu xin" , "Harry Yoo" , "Andrew Morton" , "Sasha Levin" +Message-ID: <20260105175213.2699504-1-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit fb05f992b6bbb4702307d96f00703ee637b24dbf ] + +Patch series "mm/migration: rework movable_ops page migration (part 1)", +v2. + +In the future, as we decouple "struct page" from "struct folio", pages +that support "non-lru page migration" -- movable_ops page migration such +as memory balloons and zsmalloc -- will no longer be folios. They will +not have ->mapping, ->lru, and likely no refcount and no page lock. But +they will have a type and flags 🙂 + +This is the first part (other parts not written yet) of decoupling +movable_ops page migration from folio migration. + +In this series, we get rid of the ->mapping usage, and start cleaning up +the code + separating it from folio migration. + +Migration core will have to be further reworked to not treat movable_ops +pages like folios. This is the first step into that direction. + +This patch (of 29): + +The core will set PG_isolated only after mops->isolate_page() was called. +In case of the balloon, that is where we will remove it from the balloon +list. So we cannot have isolated pages in the balloon list. + +Let's drop this unnecessary check. + +Link: https://lkml.kernel.org/r/20250704102524.326966-2-david@redhat.com +Signed-off-by: David Hildenbrand +Acked-by: Zi Yan +Reviewed-by: Lorenzo Stoakes +Cc: Alistair Popple +Cc: Al Viro +Cc: Arnd Bergmann +Cc: Brendan Jackman +Cc: Byungchul Park +Cc: Chengming Zhou +Cc: Christian Brauner +Cc: Christophe Leroy +Cc: Eugenio Pé rez +Cc: Greg Kroah-Hartman +Cc: Gregory Price +Cc: "Huang, Ying" +Cc: Jan Kara +Cc: Jason Gunthorpe +Cc: Jason Wang +Cc: Jerrin Shaji George +Cc: Johannes Weiner +Cc: John Hubbard +Cc: Jonathan Corbet +Cc: Joshua Hahn +Cc: Liam Howlett +Cc: Madhavan Srinivasan +Cc: Mathew Brost +Cc: Matthew Wilcox (Oracle) +Cc: Miaohe Lin +Cc: Michael Ellerman +Cc: "Michael S. Tsirkin" +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Minchan Kim +Cc: Naoya Horiguchi +Cc: Nicholas Piggin +Cc: Oscar Salvador +Cc: Peter Xu +Cc: Qi Zheng +Cc: Rakie Kim +Cc: Rik van Riel +Cc: Sergey Senozhatsky +Cc: Shakeel Butt +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: Xuan Zhuo +Cc: xu xin +Cc: Harry Yoo +Signed-off-by: Andrew Morton +Stable-dep-of: 0da2ba35c0d5 ("powerpc/pseries/cmm: adjust BALLOON_MIGRATE when migrating pages") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/balloon_compaction.c | 6 ------ + 1 file changed, 6 deletions(-) + +--- a/mm/balloon_compaction.c ++++ b/mm/balloon_compaction.c +@@ -93,12 +93,6 @@ size_t balloon_page_list_dequeue(struct + if (!trylock_page(page)) + continue; + +- if (IS_ENABLED(CONFIG_BALLOON_COMPACTION) && +- PageIsolated(page)) { +- /* raced with isolation */ +- unlock_page(page); +- continue; +- } + balloon_page_delete(page); + __count_vm_event(BALLOON_DEFLATE); + list_add(&page->lru, pages); diff --git a/queue-6.6/mm-fix-arithmetic-for-bdi-min_ratio.patch b/queue-6.6/mm-fix-arithmetic-for-bdi-min_ratio.patch new file mode 100644 index 0000000000..cfaa20dd93 --- /dev/null +++ b/queue-6.6/mm-fix-arithmetic-for-bdi-min_ratio.patch @@ -0,0 +1,46 @@ +From jefflexu@linux.alibaba.com Thu Dec 11 03:35:23 2025 +From: Jingbo Xu +Date: Thu, 11 Dec 2025 10:35:06 +0800 +Subject: mm: fix arithmetic for bdi min_ratio +To: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org +Cc: jefflexu@linux.alibaba.com +Message-ID: <20251211023507.82177-2-jefflexu@linux.alibaba.com> + +From: Jingbo Xu + +commit e0646b7590084a5bf3b056d3ad871d9379d2c25a upstream. + +Since now bdi->min_ratio is part per million, fix the wrong arithmetic. +Otherwise it will fail with -EINVAL when setting a reasonable min_ratio, +as it tries to set min_ratio to (min_ratio * BDI_RATIO_SCALE) in +percentage unit, which exceeds 100% anyway. + + # cat /sys/class/bdi/253\:0/min_ratio + 0 + # cat /sys/class/bdi/253\:0/max_ratio + 100 + # echo 1 > /sys/class/bdi/253\:0/min_ratio + -bash: echo: write error: Invalid argument + +Link: https://lkml.kernel.org/r/20231219142508.86265-2-jefflexu@linux.alibaba.com +Fixes: 8021fb3232f2 ("mm: split off __bdi_set_min_ratio() function") +Signed-off-by: Jingbo Xu +Reported-by: Joseph Qi +Cc: Matthew Wilcox (Oracle) +Cc: Stefan Roesch +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/page-writeback.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/mm/page-writeback.c ++++ b/mm/page-writeback.c +@@ -714,7 +714,6 @@ static int __bdi_set_min_ratio(struct ba + + if (min_ratio > 100 * BDI_RATIO_SCALE) + return -EINVAL; +- min_ratio *= BDI_RATIO_SCALE; + + spin_lock_bh(&bdi_lock); + if (min_ratio > bdi->max_ratio) { diff --git a/queue-6.6/mm-fix-arithmetic-for-max_prop_frac-when-setting-max_ratio.patch b/queue-6.6/mm-fix-arithmetic-for-max_prop_frac-when-setting-max_ratio.patch new file mode 100644 index 0000000000..b4744d6033 --- /dev/null +++ b/queue-6.6/mm-fix-arithmetic-for-max_prop_frac-when-setting-max_ratio.patch @@ -0,0 +1,41 @@ +From stable+bounces-200760-greg=kroah.com@vger.kernel.org Thu Dec 11 03:35:48 2025 +From: Jingbo Xu +Date: Thu, 11 Dec 2025 10:35:07 +0800 +Subject: mm: fix arithmetic for max_prop_frac when setting max_ratio +To: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org +Cc: jefflexu@linux.alibaba.com +Message-ID: <20251211023507.82177-3-jefflexu@linux.alibaba.com> + +From: Jingbo Xu + +commit fa151a39a6879144b587f35c0dfcc15e1be9450f upstream. + +Since now bdi->max_ratio is part per million, fix the wrong arithmetic for +max_prop_frac when setting max_ratio. Otherwise the miscalculated +max_prop_frac will affect the incrementing of writeout completion count +when max_ratio is not 100%. + +Link: https://lkml.kernel.org/r/20231219142508.86265-3-jefflexu@linux.alibaba.com +Fixes: efc3e6ad53ea ("mm: split off __bdi_set_max_ratio() function") +Signed-off-by: Jingbo Xu +Cc: Joseph Qi +Cc: Matthew Wilcox (Oracle) +Cc: Stefan Roesch +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/page-writeback.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/mm/page-writeback.c ++++ b/mm/page-writeback.c +@@ -750,7 +750,8 @@ static int __bdi_set_max_ratio(struct ba + ret = -EINVAL; + } else { + bdi->max_ratio = max_ratio; +- bdi->max_prop_frac = (FPROP_FRAC_BASE * max_ratio) / 100; ++ bdi->max_prop_frac = (FPROP_FRAC_BASE * max_ratio) / ++ (100 * BDI_RATIO_SCALE); + } + spin_unlock_bh(&bdi_lock); + diff --git a/queue-6.6/net-dsa-sja1105-fix-kasan-out-of-bounds-warning-in-sja1105_table_delete_entry.patch b/queue-6.6/net-dsa-sja1105-fix-kasan-out-of-bounds-warning-in-sja1105_table_delete_entry.patch new file mode 100644 index 0000000000..1c363a3186 --- /dev/null +++ b/queue-6.6/net-dsa-sja1105-fix-kasan-out-of-bounds-warning-in-sja1105_table_delete_entry.patch @@ -0,0 +1,49 @@ +From stable+bounces-200101-greg=kroah.com@vger.kernel.org Fri Dec 5 04:13:57 2025 +From: Chen Yu +Date: Fri, 5 Dec 2025 11:12:23 +0800 +Subject: net: dsa: sja1105: fix kasan out-of-bounds warning in sja1105_table_delete_entry() +To: vladimir.oltean@nxp.com, horms@kernel.org, kuba@kernel.org +Cc: stable@vger.kernel.org +Message-ID: <20251205031223.2563-1-xnguchen@sina.cn> + +From: Vladimir Oltean + +[ Upstream commit 5f2b28b79d2d1946ee36ad8b3dc0066f73c90481 ] + +There are actually 2 problems: +- deleting the last element doesn't require the memmove of elements + [i + 1, end) over it. Actually, element i+1 is out of bounds. +- The memmove itself should move size - i - 1 elements, because the last + element is out of bounds. + +The out-of-bounds element still remains out of bounds after being +accessed, so the problem is only that we touch it, not that it becomes +in active use. But I suppose it can lead to issues if the out-of-bounds +element is part of an unmapped page. + +Fixes: 6666cebc5e30 ("net: dsa: sja1105: Add support for VLAN operations") +Signed-off-by: Vladimir Oltean +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20250318115716.2124395-4-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Chen Yu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/dsa/sja1105/sja1105_static_config.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/net/dsa/sja1105/sja1105_static_config.c ++++ b/drivers/net/dsa/sja1105/sja1105_static_config.c +@@ -1921,8 +1921,10 @@ int sja1105_table_delete_entry(struct sj + if (i > table->entry_count) + return -ERANGE; + +- memmove(entries + i * entry_size, entries + (i + 1) * entry_size, +- (table->entry_count - i) * entry_size); ++ if (i + 1 < table->entry_count) { ++ memmove(entries + i * entry_size, entries + (i + 1) * entry_size, ++ (table->entry_count - i - 1) * entry_size); ++ } + + table->entry_count--; + diff --git a/queue-6.6/page_pool-fix-use-after-free-in-page_pool_recycle_in_ring.patch b/queue-6.6/page_pool-fix-use-after-free-in-page_pool_recycle_in_ring.patch new file mode 100644 index 0000000000..f063ce828e --- /dev/null +++ b/queue-6.6/page_pool-fix-use-after-free-in-page_pool_recycle_in_ring.patch @@ -0,0 +1,146 @@ +From stable+bounces-200717-greg=kroah.com@vger.kernel.org Wed Dec 10 13:15:44 2025 +From: ruohanlan@aliyun.com +Date: Wed, 10 Dec 2025 12:15:02 +0000 +Subject: page_pool: Fix use-after-free in page_pool_recycle_in_ring +To: stable@vger.kernel.org +Cc: "Dong Chenchen" , "Jakub Kicinski" , syzbot+204a4382fcb3311f3858@syzkaller.appspotmail.com, "Toke Høiland-Jørgensen" , "Mina Almasry" , "Ruohan Lan" +Message-ID: <20251210121502.5066-1-ruohanlan@aliyun.com> + +From: Dong Chenchen + +[ Upstream commit 271683bb2cf32e5126c592b5d5e6a756fa374fd9 ] + +syzbot reported a uaf in page_pool_recycle_in_ring: + +BUG: KASAN: slab-use-after-free in lock_release+0x151/0xa30 kernel/locking/lockdep.c:5862 +Read of size 8 at addr ffff8880286045a0 by task syz.0.284/6943 + +CPU: 0 UID: 0 PID: 6943 Comm: syz.0.284 Not tainted 6.13.0-rc3-syzkaller-gdfa94ce54f41 #0 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/13/2024 +Call Trace: + + __dump_stack lib/dump_stack.c:94 [inline] + dump_stack_lvl+0x241/0x360 lib/dump_stack.c:120 + print_address_description mm/kasan/report.c:378 [inline] + print_report+0x169/0x550 mm/kasan/report.c:489 + kasan_report+0x143/0x180 mm/kasan/report.c:602 + lock_release+0x151/0xa30 kernel/locking/lockdep.c:5862 + __raw_spin_unlock_bh include/linux/spinlock_api_smp.h:165 [inline] + _raw_spin_unlock_bh+0x1b/0x40 kernel/locking/spinlock.c:210 + spin_unlock_bh include/linux/spinlock.h:396 [inline] + ptr_ring_produce_bh include/linux/ptr_ring.h:164 [inline] + page_pool_recycle_in_ring net/core/page_pool.c:707 [inline] + page_pool_put_unrefed_netmem+0x748/0xb00 net/core/page_pool.c:826 + page_pool_put_netmem include/net/page_pool/helpers.h:323 [inline] + page_pool_put_full_netmem include/net/page_pool/helpers.h:353 [inline] + napi_pp_put_page+0x149/0x2b0 net/core/skbuff.c:1036 + skb_pp_recycle net/core/skbuff.c:1047 [inline] + skb_free_head net/core/skbuff.c:1094 [inline] + skb_release_data+0x6c4/0x8a0 net/core/skbuff.c:1125 + skb_release_all net/core/skbuff.c:1190 [inline] + __kfree_skb net/core/skbuff.c:1204 [inline] + sk_skb_reason_drop+0x1c9/0x380 net/core/skbuff.c:1242 + kfree_skb_reason include/linux/skbuff.h:1263 [inline] + __skb_queue_purge_reason include/linux/skbuff.h:3343 [inline] + +root cause is: + +page_pool_recycle_in_ring + ptr_ring_produce + spin_lock(&r->producer_lock); + WRITE_ONCE(r->queue[r->producer++], ptr) + //recycle last page to pool + page_pool_release + page_pool_scrub + page_pool_empty_ring + ptr_ring_consume + page_pool_return_page //release all page + __page_pool_destroy + free_percpu(pool->recycle_stats); + free(pool) //free + + spin_unlock(&r->producer_lock); //pool->ring uaf read + recycle_stat_inc(pool, ring); + +page_pool can be free while page pool recycle the last page in ring. +Add producer-lock barrier to page_pool_release to prevent the page +pool from being free before all pages have been recycled. + +recycle_stat_inc() is empty when CONFIG_PAGE_POOL_STATS is not +enabled, which will trigger Wempty-body build warning. Add definition +for pool stat macro to fix warning. + +Suggested-by: Jakub Kicinski +Link: https://lore.kernel.org/netdev/20250513083123.3514193-1-dongchenchen2@huawei.com +Fixes: ff7d6b27f894 ("page_pool: refurbish version of page_pool code") +Reported-by: syzbot+204a4382fcb3311f3858@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=204a4382fcb3311f3858 +Signed-off-by: Dong Chenchen +Reviewed-by: Toke Høiland-Jørgensen +Reviewed-by: Mina Almasry +Link: https://patch.msgid.link/20250527114152.3119109-1-dongchenchen2@huawei.com +Signed-off-by: Jakub Kicinski +[ Minor context change fixed. ] +Signed-off-by: Ruohan Lan +Signed-off-by: Greg Kroah-Hartman +--- + net/core/page_pool.c | 27 ++++++++++++++------------- + 1 file changed, 14 insertions(+), 13 deletions(-) + +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -140,9 +140,9 @@ u64 *page_pool_ethtool_stats_get(u64 *da + EXPORT_SYMBOL(page_pool_ethtool_stats_get); + + #else +-#define alloc_stat_inc(pool, __stat) +-#define recycle_stat_inc(pool, __stat) +-#define recycle_stat_add(pool, __stat, val) ++#define alloc_stat_inc(...) do { } while (0) ++#define recycle_stat_inc(...) do { } while (0) ++#define recycle_stat_add(...) do { } while (0) + #endif + + static bool page_pool_producer_lock(struct page_pool *pool) +@@ -549,19 +549,16 @@ skip_dma_unmap: + + static bool page_pool_recycle_in_ring(struct page_pool *pool, struct page *page) + { +- int ret; +- /* BH protection not needed if current is softirq */ +- if (in_softirq()) +- ret = ptr_ring_produce(&pool->ring, page); +- else +- ret = ptr_ring_produce_bh(&pool->ring, page); ++ bool in_softirq, ret; + +- if (!ret) { ++ /* BH protection not needed if current is softirq */ ++ in_softirq = page_pool_producer_lock(pool); ++ ret = !__ptr_ring_produce(&pool->ring, page); ++ if (ret) + recycle_stat_inc(pool, ring); +- return true; +- } ++ page_pool_producer_unlock(pool, in_softirq); + +- return false; ++ return ret; + } + + /* Only allow direct recycling in special circumstances, into the +@@ -850,10 +847,14 @@ static void page_pool_scrub(struct page_ + + static int page_pool_release(struct page_pool *pool) + { ++ bool in_softirq; + int inflight; + + page_pool_scrub(pool); + inflight = page_pool_inflight(pool); ++ /* Acquire producer lock to make sure producers have exited. */ ++ in_softirq = page_pool_producer_lock(pool); ++ page_pool_producer_unlock(pool, in_softirq); + if (!inflight) + page_pool_free(pool); + diff --git a/queue-6.6/powerpc-64s-radix-kfence-map-__kfence_pool-at-page-granularity.patch b/queue-6.6/powerpc-64s-radix-kfence-map-__kfence_pool-at-page-granularity.patch new file mode 100644 index 0000000000..0dad86c3f5 --- /dev/null +++ b/queue-6.6/powerpc-64s-radix-kfence-map-__kfence_pool-at-page-granularity.patch @@ -0,0 +1,228 @@ +From 353d7a84c214f184d5a6b62acdec8b4424159b7c Mon Sep 17 00:00:00 2001 +From: Hari Bathini +Date: Mon, 1 Jul 2024 18:30:21 +0530 +Subject: powerpc/64s/radix/kfence: map __kfence_pool at page granularity + +From: Hari Bathini + +commit 353d7a84c214f184d5a6b62acdec8b4424159b7c upstream. + +When KFENCE is enabled, total system memory is mapped at page level +granularity. But in radix MMU mode, ~3GB additional memory is needed +to map 100GB of system memory at page level granularity when compared +to using 2MB direct mapping.This is not desired considering KFENCE is +designed to be enabled in production kernels [1]. + +Mapping only the memory allocated for KFENCE pool at page granularity is +sufficient to enable KFENCE support. So, allocate __kfence_pool during +bootup and map it at page granularity instead of mapping all system +memory at page granularity. + +Without patch: + # cat /proc/meminfo + MemTotal: 101201920 kB + +With patch: + # cat /proc/meminfo + MemTotal: 104483904 kB + +Note that enabling KFENCE at runtime is disabled for radix MMU for now, +as it depends on the ability to split page table mappings and such APIs +are not currently implemented for radix MMU. + +All kfence_test.c testcases passed with this patch. + +[1] https://lore.kernel.org/all/20201103175841.3495947-2-elver@google.com/ + +Signed-off-by: Hari Bathini +Signed-off-by: Michael Ellerman +Link: https://msgid.link/20240701130021.578240-1-hbathini@linux.ibm.com +Cc: Aboorva Devarajan +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/include/asm/kfence.h | 11 +++- + arch/powerpc/mm/book3s64/radix_pgtable.c | 84 +++++++++++++++++++++++++++++-- + arch/powerpc/mm/init-common.c | 3 + + 3 files changed, 93 insertions(+), 5 deletions(-) + +--- a/arch/powerpc/include/asm/kfence.h ++++ b/arch/powerpc/include/asm/kfence.h +@@ -15,10 +15,19 @@ + #define ARCH_FUNC_PREFIX "." + #endif + ++#ifdef CONFIG_KFENCE ++extern bool kfence_disabled; ++ ++static inline void disable_kfence(void) ++{ ++ kfence_disabled = true; ++} ++ + static inline bool arch_kfence_init_pool(void) + { +- return true; ++ return !kfence_disabled; + } ++#endif + + #ifdef CONFIG_PPC64 + static inline bool kfence_protect_page(unsigned long addr, bool protect) +--- a/arch/powerpc/mm/book3s64/radix_pgtable.c ++++ b/arch/powerpc/mm/book3s64/radix_pgtable.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -31,6 +32,7 @@ + #include + #include + #include ++#include + + #include + +@@ -293,7 +295,8 @@ static unsigned long next_boundary(unsig + + static int __meminit create_physical_mapping(unsigned long start, + unsigned long end, +- int nid, pgprot_t _prot) ++ int nid, pgprot_t _prot, ++ unsigned long mapping_sz_limit) + { + unsigned long vaddr, addr, mapping_size = 0; + bool prev_exec, exec = false; +@@ -301,7 +304,10 @@ static int __meminit create_physical_map + int psize; + unsigned long max_mapping_size = memory_block_size; + +- if (debug_pagealloc_enabled_or_kfence()) ++ if (mapping_sz_limit < max_mapping_size) ++ max_mapping_size = mapping_sz_limit; ++ ++ if (debug_pagealloc_enabled()) + max_mapping_size = PAGE_SIZE; + + start = ALIGN(start, PAGE_SIZE); +@@ -356,8 +362,74 @@ static int __meminit create_physical_map + return 0; + } + ++#ifdef CONFIG_KFENCE ++static bool __ro_after_init kfence_early_init = !!CONFIG_KFENCE_SAMPLE_INTERVAL; ++ ++static int __init parse_kfence_early_init(char *arg) ++{ ++ int val; ++ ++ if (get_option(&arg, &val)) ++ kfence_early_init = !!val; ++ return 0; ++} ++early_param("kfence.sample_interval", parse_kfence_early_init); ++ ++static inline phys_addr_t alloc_kfence_pool(void) ++{ ++ phys_addr_t kfence_pool; ++ ++ /* ++ * TODO: Support to enable KFENCE after bootup depends on the ability to ++ * split page table mappings. As such support is not currently ++ * implemented for radix pagetables, support enabling KFENCE ++ * only at system startup for now. ++ * ++ * After support for splitting mappings is available on radix, ++ * alloc_kfence_pool() & map_kfence_pool() can be dropped and ++ * mapping for __kfence_pool memory can be ++ * split during arch_kfence_init_pool(). ++ */ ++ if (!kfence_early_init) ++ goto no_kfence; ++ ++ kfence_pool = memblock_phys_alloc(KFENCE_POOL_SIZE, PAGE_SIZE); ++ if (!kfence_pool) ++ goto no_kfence; ++ ++ memblock_mark_nomap(kfence_pool, KFENCE_POOL_SIZE); ++ return kfence_pool; ++ ++no_kfence: ++ disable_kfence(); ++ return 0; ++} ++ ++static inline void map_kfence_pool(phys_addr_t kfence_pool) ++{ ++ if (!kfence_pool) ++ return; ++ ++ if (create_physical_mapping(kfence_pool, kfence_pool + KFENCE_POOL_SIZE, ++ -1, PAGE_KERNEL, PAGE_SIZE)) ++ goto err; ++ ++ memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE); ++ __kfence_pool = __va(kfence_pool); ++ return; ++ ++err: ++ memblock_phys_free(kfence_pool, KFENCE_POOL_SIZE); ++ disable_kfence(); ++} ++#else ++static inline phys_addr_t alloc_kfence_pool(void) { return 0; } ++static inline void map_kfence_pool(phys_addr_t kfence_pool) { } ++#endif ++ + static void __init radix_init_pgtable(void) + { ++ phys_addr_t kfence_pool; + unsigned long rts_field; + phys_addr_t start, end; + u64 i; +@@ -365,6 +437,8 @@ static void __init radix_init_pgtable(vo + /* We don't support slb for radix */ + slb_set_size(0); + ++ kfence_pool = alloc_kfence_pool(); ++ + /* + * Create the linear mapping + */ +@@ -381,9 +455,11 @@ static void __init radix_init_pgtable(vo + } + + WARN_ON(create_physical_mapping(start, end, +- -1, PAGE_KERNEL)); ++ -1, PAGE_KERNEL, ~0UL)); + } + ++ map_kfence_pool(kfence_pool); ++ + if (!cpu_has_feature(CPU_FTR_HVMODE) && + cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG)) { + /* +@@ -875,7 +951,7 @@ int __meminit radix__create_section_mapp + } + + return create_physical_mapping(__pa(start), __pa(end), +- nid, prot); ++ nid, prot, ~0UL); + } + + int __meminit radix__remove_section_mapping(unsigned long start, unsigned long end) +--- a/arch/powerpc/mm/init-common.c ++++ b/arch/powerpc/mm/init-common.c +@@ -31,6 +31,9 @@ EXPORT_SYMBOL_GPL(kernstart_virt_addr); + + bool disable_kuep = !IS_ENABLED(CONFIG_PPC_KUEP); + bool disable_kuap = !IS_ENABLED(CONFIG_PPC_KUAP); ++#ifdef CONFIG_KFENCE ++bool __ro_after_init kfence_disabled; ++#endif + + static int __init parse_nosmep(char *p) + { diff --git a/queue-6.6/powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch b/queue-6.6/powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch new file mode 100644 index 0000000000..4ecd5c0b54 --- /dev/null +++ b/queue-6.6/powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch @@ -0,0 +1,45 @@ +From stable+bounces-204882-greg=kroah.com@vger.kernel.org Mon Jan 5 18:52:38 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 12:52:12 -0500 +Subject: powerpc/pseries/cmm: adjust BALLOON_MIGRATE when migrating pages +To: stable@vger.kernel.org +Cc: David Hildenbrand , "Ritesh Harjani (IBM)" , Christophe Leroy , Madhavan Srinivasan , Michael Ellerman , Nicholas Piggin , Andrew Morton , Sasha Levin +Message-ID: <20260105175213.2699504-3-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit 0da2ba35c0d532ca0fe7af698b17d74c4d084b9a ] + +Let's properly adjust BALLOON_MIGRATE like the other drivers. + +Note that the INFLATE/DEFLATE events are triggered from the core when +enqueueing/dequeueing pages. + +This was found by code inspection. + +Link: https://lkml.kernel.org/r/20251021100606.148294-3-david@redhat.com +Fixes: fe030c9b85e6 ("powerpc/pseries/cmm: Implement balloon compaction") +Signed-off-by: David Hildenbrand +Reviewed-by: Ritesh Harjani (IBM) +Cc: Christophe Leroy +Cc: Madhavan Srinivasan +Cc: Michael Ellerman +Cc: Nicholas Piggin +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/platforms/pseries/cmm.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/powerpc/platforms/pseries/cmm.c ++++ b/arch/powerpc/platforms/pseries/cmm.c +@@ -532,6 +532,7 @@ static int cmm_migratepage(struct balloo + + spin_lock_irqsave(&b_dev_info->pages_lock, flags); + balloon_page_insert(b_dev_info, newpage); ++ __count_vm_event(BALLOON_MIGRATE); + b_dev_info->isolated_pages--; + spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); + diff --git a/queue-6.6/series b/queue-6.6/series index 156a673c64..5443c67f89 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -671,3 +671,31 @@ usb-xhci-apply-the-link-chain-quirk-on-nec-isoc-endpoints.patch net-remove-rtnl-dance-for-siocbraddif-and-siocbrdelif.patch drm-amd-display-fix-null-pointer-deref-in-dcn20_resource.c.patch loongarch-refactor-register-restoration-in-ftrace_common_return.patch +powerpc-64s-radix-kfence-map-__kfence_pool-at-page-granularity.patch +ext4-fix-error-message-when-rejecting-the-default-hash.patch +ext4-introduce-itail-helper.patch +ext4-fix-out-of-bound-read-in-ext4_xattr_inode_dec_ref_all.patch +xfrm-state-fix-out-of-bounds-read-during-lookup.patch +page_pool-fix-use-after-free-in-page_pool_recycle_in_ring.patch +net-dsa-sja1105-fix-kasan-out-of-bounds-warning-in-sja1105_table_delete_entry.patch +mm-fix-arithmetic-for-bdi-min_ratio.patch +mm-fix-arithmetic-for-max_prop_frac-when-setting-max_ratio.patch +genirq-irq_sim-initialize-work-context-pointers-properly.patch +f2fs-remove-unused-gc_failure_pin.patch +f2fs-keep-posix_fadv_noreuse-ranges.patch +f2fs-drop-inode-from-the-donation-list-when-the-last-file-is-closed.patch +f2fs-fix-to-avoid-updating-compression-context-during-writeback.patch +f2fs-fix-to-propagate-error-from-f2fs_enable_checkpoint.patch +f2fs-use-global-inline_xattr_slab-instead-of-per-sb-slab-cache.patch +f2fs-fix-to-detect-recoverable-inode-during-dryrun-of-find_fsync_dnodes.patch +media-verisilicon-store-chroma-and-motion-vectors-offset.patch +media-verisilicon-g2-use-common-helpers-to-compute-chroma-and-mv-offsets.patch +media-verisilicon-fix-cpu-stalls-on-g2-bus-error.patch +mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch +mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch +powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch +kvm-nvmx-immediately-refresh-apicv-controls-as-needed-on-nested-vm-exit.patch +media-amphion-add-a-frame-flush-mode-for-decoder.patch +media-amphion-make-some-vpu_v4l2-functions-static.patch +media-amphion-remove-vpu_vb_is_codecconfig.patch +media-mediatek-vcodec-use-spinlock-for-context-list-protection-lock.patch diff --git a/queue-6.6/xfrm-state-fix-out-of-bounds-read-during-lookup.patch b/queue-6.6/xfrm-state-fix-out-of-bounds-read-during-lookup.patch new file mode 100644 index 0000000000..644d90cbde --- /dev/null +++ b/queue-6.6/xfrm-state-fix-out-of-bounds-read-during-lookup.patch @@ -0,0 +1,275 @@ +From stable+bounces-200772-greg=kroah.com@vger.kernel.org Thu Dec 11 07:38:41 2025 +From: Rajani Kantha <681739313@139.com> +Date: Thu, 11 Dec 2025 14:34:41 +0800 +Subject: xfrm: state: fix out-of-bounds read during lookup +To: dvyukov@google.com, fw@strlen.de, steffen.klassert@secunet.com +Cc: stable@vger.kernel.org +Message-ID: <20251211063441.6680-1-681739313@139.com> + +From: Florian Westphal + +[ Upstream commit e952837f3ddb0ff726d5b582aa1aad9aa38d024d ] + +lookup and resize can run in parallel. + +The xfrm_state_hash_generation seqlock ensures a retry, but the hash +functions can observe a hmask value that is too large for the new hlist +array. + +rehash does: + rcu_assign_pointer(net->xfrm.state_bydst, ndst) [..] + net->xfrm.state_hmask = nhashmask; + +While state lookup does: + h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); + hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) { + +This is only safe in case the update to state_bydst is larger than +net->xfrm.xfrm_state_hmask (or if the lookup function gets +serialized via state spinlock again). + +Fix this by prefetching state_hmask and the associated pointers. +The xfrm_state_hash_generation seqlock retry will ensure that the pointer +and the hmask will be consistent. + +The existing helpers, like xfrm_dst_hash(), are now unsafe for RCU side, +add lockdep assertions to document that they are only safe for insert +side. + +xfrm_state_lookup_byaddr() uses the spinlock rather than RCU. +AFAICS this is an oversight from back when state lookup was converted to +RCU, this lock should be replaced with RCU in a future patch. + +Reported-by: syzbot+5f9f31cb7d985f584d8e@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/CACT4Y+azwfrE3uz6A5ZErov5YN2LYBN5KrsymBerT36VU8qzBA@mail.gmail.com/ +Diagnosed-by: Dmitry Vyukov +Fixes: c2f672fc9464 ("xfrm: state lookup can be lockless") +Signed-off-by: Florian Westphal +Signed-off-by: Steffen Klassert +[ Minor context change fixed ] +Signed-off-by: Rajani Kantha <681739313@139.com> +Signed-off-by: Greg Kroah-Hartman +--- + net/xfrm/xfrm_state.c | 84 +++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 66 insertions(+), 18 deletions(-) + +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -34,6 +34,8 @@ + + #define xfrm_state_deref_prot(table, net) \ + rcu_dereference_protected((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock)) ++#define xfrm_state_deref_check(table, net) \ ++ rcu_dereference_check((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock)) + + static void xfrm_state_gc_task(struct work_struct *work); + +@@ -62,6 +64,8 @@ static inline unsigned int xfrm_dst_hash + u32 reqid, + unsigned short family) + { ++ lockdep_assert_held(&net->xfrm.xfrm_state_lock); ++ + return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask); + } + +@@ -70,6 +74,8 @@ static inline unsigned int xfrm_src_hash + const xfrm_address_t *saddr, + unsigned short family) + { ++ lockdep_assert_held(&net->xfrm.xfrm_state_lock); ++ + return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask); + } + +@@ -77,11 +83,15 @@ static inline unsigned int + xfrm_spi_hash(struct net *net, const xfrm_address_t *daddr, + __be32 spi, u8 proto, unsigned short family) + { ++ lockdep_assert_held(&net->xfrm.xfrm_state_lock); ++ + return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask); + } + + static unsigned int xfrm_seq_hash(struct net *net, u32 seq) + { ++ lockdep_assert_held(&net->xfrm.xfrm_state_lock); ++ + return __xfrm_seq_hash(seq, net->xfrm.state_hmask); + } + +@@ -1025,16 +1035,38 @@ xfrm_init_tempstate(struct xfrm_state *x + x->props.family = tmpl->encap_family; + } + +-static struct xfrm_state *__xfrm_state_lookup_all(struct net *net, u32 mark, ++struct xfrm_hash_state_ptrs { ++ const struct hlist_head *bydst; ++ const struct hlist_head *bysrc; ++ const struct hlist_head *byspi; ++ unsigned int hmask; ++}; ++ ++static void xfrm_hash_ptrs_get(const struct net *net, struct xfrm_hash_state_ptrs *ptrs) ++{ ++ unsigned int sequence; ++ ++ do { ++ sequence = read_seqcount_begin(&net->xfrm.xfrm_state_hash_generation); ++ ++ ptrs->bydst = xfrm_state_deref_check(net->xfrm.state_bydst, net); ++ ptrs->bysrc = xfrm_state_deref_check(net->xfrm.state_bysrc, net); ++ ptrs->byspi = xfrm_state_deref_check(net->xfrm.state_byspi, net); ++ ptrs->hmask = net->xfrm.state_hmask; ++ } while (read_seqcount_retry(&net->xfrm.xfrm_state_hash_generation, sequence)); ++} ++ ++static struct xfrm_state *__xfrm_state_lookup_all(const struct xfrm_hash_state_ptrs *state_ptrs, ++ u32 mark, + const xfrm_address_t *daddr, + __be32 spi, u8 proto, + unsigned short family, + struct xfrm_dev_offload *xdo) + { +- unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); ++ unsigned int h = __xfrm_spi_hash(daddr, spi, proto, family, state_ptrs->hmask); + struct xfrm_state *x; + +- hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) { ++ hlist_for_each_entry_rcu(x, state_ptrs->byspi + h, byspi) { + #ifdef CONFIG_XFRM_OFFLOAD + if (xdo->type == XFRM_DEV_OFFLOAD_PACKET) { + if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) +@@ -1068,15 +1100,16 @@ static struct xfrm_state *__xfrm_state_l + return NULL; + } + +-static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, ++static struct xfrm_state *__xfrm_state_lookup(const struct xfrm_hash_state_ptrs *state_ptrs, ++ u32 mark, + const xfrm_address_t *daddr, + __be32 spi, u8 proto, + unsigned short family) + { +- unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); ++ unsigned int h = __xfrm_spi_hash(daddr, spi, proto, family, state_ptrs->hmask); + struct xfrm_state *x; + +- hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) { ++ hlist_for_each_entry_rcu(x, state_ptrs->byspi + h, byspi) { + if (x->props.family != family || + x->id.spi != spi || + x->id.proto != proto || +@@ -1093,15 +1126,16 @@ static struct xfrm_state *__xfrm_state_l + return NULL; + } + +-static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark, ++static struct xfrm_state *__xfrm_state_lookup_byaddr(const struct xfrm_hash_state_ptrs *state_ptrs, ++ u32 mark, + const xfrm_address_t *daddr, + const xfrm_address_t *saddr, + u8 proto, unsigned short family) + { +- unsigned int h = xfrm_src_hash(net, daddr, saddr, family); ++ unsigned int h = __xfrm_src_hash(daddr, saddr, family, state_ptrs->hmask); + struct xfrm_state *x; + +- hlist_for_each_entry_rcu(x, net->xfrm.state_bysrc + h, bysrc) { ++ hlist_for_each_entry_rcu(x, state_ptrs->bysrc + h, bysrc) { + if (x->props.family != family || + x->id.proto != proto || + !xfrm_addr_equal(&x->id.daddr, daddr, family) || +@@ -1121,14 +1155,17 @@ static struct xfrm_state *__xfrm_state_l + static inline struct xfrm_state * + __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) + { ++ struct xfrm_hash_state_ptrs state_ptrs; + struct net *net = xs_net(x); + u32 mark = x->mark.v & x->mark.m; + ++ xfrm_hash_ptrs_get(net, &state_ptrs); ++ + if (use_spi) +- return __xfrm_state_lookup(net, mark, &x->id.daddr, ++ return __xfrm_state_lookup(&state_ptrs, mark, &x->id.daddr, + x->id.spi, x->id.proto, family); + else +- return __xfrm_state_lookup_byaddr(net, mark, ++ return __xfrm_state_lookup_byaddr(&state_ptrs, mark, + &x->id.daddr, + &x->props.saddr, + x->id.proto, family); +@@ -1191,6 +1228,7 @@ xfrm_state_find(const xfrm_address_t *da + unsigned short family, u32 if_id) + { + static xfrm_address_t saddr_wildcard = { }; ++ struct xfrm_hash_state_ptrs state_ptrs; + struct net *net = xp_net(pol); + unsigned int h, h_wildcard; + struct xfrm_state *x, *x0, *to_put; +@@ -1207,8 +1245,10 @@ xfrm_state_find(const xfrm_address_t *da + sequence = read_seqcount_begin(&net->xfrm.xfrm_state_hash_generation); + + rcu_read_lock(); +- h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); +- hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) { ++ xfrm_hash_ptrs_get(net, &state_ptrs); ++ ++ h = __xfrm_dst_hash(daddr, saddr, tmpl->reqid, encap_family, state_ptrs.hmask); ++ hlist_for_each_entry_rcu(x, state_ptrs.bydst + h, bydst) { + #ifdef CONFIG_XFRM_OFFLOAD + if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) { + if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) +@@ -1241,8 +1281,9 @@ xfrm_state_find(const xfrm_address_t *da + if (best || acquire_in_progress) + goto found; + +- h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family); +- hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) { ++ h_wildcard = __xfrm_dst_hash(daddr, &saddr_wildcard, tmpl->reqid, ++ encap_family, state_ptrs.hmask); ++ hlist_for_each_entry_rcu(x, state_ptrs.bydst + h_wildcard, bydst) { + #ifdef CONFIG_XFRM_OFFLOAD + if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) { + if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) +@@ -1277,7 +1318,7 @@ found: + x = best; + if (!x && !error && !acquire_in_progress) { + if (tmpl->id.spi && +- (x0 = __xfrm_state_lookup_all(net, mark, daddr, ++ (x0 = __xfrm_state_lookup_all(&state_ptrs, mark, daddr, + tmpl->id.spi, tmpl->id.proto, + encap_family, + &pol->xdo)) != NULL) { +@@ -2032,10 +2073,13 @@ struct xfrm_state * + xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi, + u8 proto, unsigned short family) + { ++ struct xfrm_hash_state_ptrs state_ptrs; + struct xfrm_state *x; + + rcu_read_lock(); +- x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); ++ xfrm_hash_ptrs_get(net, &state_ptrs); ++ ++ x = __xfrm_state_lookup(&state_ptrs, mark, daddr, spi, proto, family); + rcu_read_unlock(); + return x; + } +@@ -2046,10 +2090,14 @@ xfrm_state_lookup_byaddr(struct net *net + const xfrm_address_t *daddr, const xfrm_address_t *saddr, + u8 proto, unsigned short family) + { ++ struct xfrm_hash_state_ptrs state_ptrs; + struct xfrm_state *x; + + spin_lock_bh(&net->xfrm.xfrm_state_lock); +- x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); ++ ++ xfrm_hash_ptrs_get(net, &state_ptrs); ++ ++ x = __xfrm_state_lookup_byaddr(&state_ptrs, mark, daddr, saddr, proto, family); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); + return x; + }