]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.6-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 8 Jan 2026 11:13:02 +0000 (12:13 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 8 Jan 2026 11:13:02 +0000 (12:13 +0100)
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

29 files changed:
queue-6.6/ext4-fix-error-message-when-rejecting-the-default-hash.patch [new file with mode: 0644]
queue-6.6/ext4-fix-out-of-bound-read-in-ext4_xattr_inode_dec_ref_all.patch [new file with mode: 0644]
queue-6.6/ext4-introduce-itail-helper.patch [new file with mode: 0644]
queue-6.6/f2fs-drop-inode-from-the-donation-list-when-the-last-file-is-closed.patch [new file with mode: 0644]
queue-6.6/f2fs-fix-to-avoid-updating-compression-context-during-writeback.patch [new file with mode: 0644]
queue-6.6/f2fs-fix-to-detect-recoverable-inode-during-dryrun-of-find_fsync_dnodes.patch [new file with mode: 0644]
queue-6.6/f2fs-fix-to-propagate-error-from-f2fs_enable_checkpoint.patch [new file with mode: 0644]
queue-6.6/f2fs-keep-posix_fadv_noreuse-ranges.patch [new file with mode: 0644]
queue-6.6/f2fs-remove-unused-gc_failure_pin.patch [new file with mode: 0644]
queue-6.6/f2fs-use-global-inline_xattr_slab-instead-of-per-sb-slab-cache.patch [new file with mode: 0644]
queue-6.6/genirq-irq_sim-initialize-work-context-pointers-properly.patch [new file with mode: 0644]
queue-6.6/kvm-nvmx-immediately-refresh-apicv-controls-as-needed-on-nested-vm-exit.patch [new file with mode: 0644]
queue-6.6/media-amphion-add-a-frame-flush-mode-for-decoder.patch [new file with mode: 0644]
queue-6.6/media-amphion-make-some-vpu_v4l2-functions-static.patch [new file with mode: 0644]
queue-6.6/media-amphion-remove-vpu_vb_is_codecconfig.patch [new file with mode: 0644]
queue-6.6/media-mediatek-vcodec-use-spinlock-for-context-list-protection-lock.patch [new file with mode: 0644]
queue-6.6/media-verisilicon-fix-cpu-stalls-on-g2-bus-error.patch [new file with mode: 0644]
queue-6.6/media-verisilicon-g2-use-common-helpers-to-compute-chroma-and-mv-offsets.patch [new file with mode: 0644]
queue-6.6/media-verisilicon-store-chroma-and-motion-vectors-offset.patch [new file with mode: 0644]
queue-6.6/mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch [new file with mode: 0644]
queue-6.6/mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch [new file with mode: 0644]
queue-6.6/mm-fix-arithmetic-for-bdi-min_ratio.patch [new file with mode: 0644]
queue-6.6/mm-fix-arithmetic-for-max_prop_frac-when-setting-max_ratio.patch [new file with mode: 0644]
queue-6.6/net-dsa-sja1105-fix-kasan-out-of-bounds-warning-in-sja1105_table_delete_entry.patch [new file with mode: 0644]
queue-6.6/page_pool-fix-use-after-free-in-page_pool_recycle_in_ring.patch [new file with mode: 0644]
queue-6.6/powerpc-64s-radix-kfence-map-__kfence_pool-at-page-granularity.patch [new file with mode: 0644]
queue-6.6/powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch [new file with mode: 0644]
queue-6.6/series
queue-6.6/xfrm-state-fix-out-of-bounds-read-during-lookup.patch [new file with mode: 0644]

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 (file)
index 0000000..e7f0c96
--- /dev/null
@@ -0,0 +1,95 @@
+From stable+bounces-201041-greg=kroah.com@vger.kernel.org Mon Dec 15 14:40:38 2025
+From: Ankan Biswas <spyjetfayed@gmail.com>
+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 <krisman@suse.de>, Ankan Biswas <spyjetfayed@gmail.com>
+Message-ID: <20251215133957.4236-1-spyjetfayed@gmail.com>
+
+From: Gabriel Krisman Bertazi <krisman@suse.de>
+
+[ 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 <krisman@suse.de>
+Link: https://patch.msgid.link/87jzg1en6j.fsf_-_@mailhost.krisman.be
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+[ The commit a2187431c395 intended to remove the if-block which was used
+  for an old SIPHASH rejection check. ]
+Signed-off-by: Ankan Biswas <spyjetfayed@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..8bb0be7
--- /dev/null
@@ -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" <david.nystrom@est.tech>
+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" <adilger.kernel@dilger.ca>, "James Simmons" <uja.ornl@gmail.com>, "Ye Bin" <yebin10@huawei.com>, "David Nyström" <david.nystrom@est.tech>, "Jan Kara" <jack@suse.cz>, "Theodore Ts'o" <tytso@mit.edu>
+Message-ID: <20251215-cve-2025-22121-v1-2-283f77b33397@est.tech>
+
+From: Ye Bin <yebin10@huawei.com>
+
+[ 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 <yebin10@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://patch.msgid.link/20250208063141.1539283-3-yebin@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: David Nyström <david.nystrom@est.tech>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..6599bc3
--- /dev/null
@@ -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" <david.nystrom@est.tech>
+Date: Mon, 15 Dec 2025 09:52:56 +0100
+Subject: ext4: introduce ITAIL helper
+To: stable@vger.kernel.org
+Cc: "Andreas Dilger" <adilger.kernel@dilger.ca>, "James Simmons" <uja.ornl@gmail.com>, "Ye Bin" <yebin10@huawei.com>, "David Nyström" <david.nystrom@est.tech>, "Jan Kara" <jack@suse.cz>, "Theodore Ts'o" <tytso@mit.edu>
+Message-ID: <20251215-cve-2025-22121-v1-1-283f77b33397@est.tech>
+
+From: Ye Bin <yebin10@huawei.com>
+
+[ Upstream commit 69f3a3039b0d0003de008659cafd5a1eaaa0a7a4 ]
+
+Introduce ITAIL helper to get the bound of xattr in inode.
+
+Signed-off-by: Ye Bin <yebin10@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://patch.msgid.link/20250208063141.1539283-2-yebin@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: David Nyström <david.nystrom@est.tech>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..6f180b2
--- /dev/null
@@ -0,0 +1,90 @@
+From stable+bounces-204254-greg=kroah.com@vger.kernel.org Tue Dec 30 18:11:50 2025
+From: Sasha Levin <sashal@kernel.org>
+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 <jaegeuk@kernel.org>, Chao Yu <chao@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251230170540.2336679-3-sashal@kernel.org>
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+[ Upstream commit 078cad8212ce4f4ebbafcc0936475b8215e1ca2a ]
+
+Let's drop the inode from the donation list when there is no other
+open file.
+
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Stable-dep-of: 10b591e7fb7c ("f2fs: fix to avoid updating compression context during writeback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..9845929
--- /dev/null
@@ -0,0 +1,164 @@
+From stable+bounces-204253-greg=kroah.com@vger.kernel.org Tue Dec 30 18:12:13 2025
+From: Sasha Levin <sashal@kernel.org>
+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 <chao@kernel.org>, stable@kernel.org, "Bai, Shuangpeng" <sjb7183@psu.edu>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251230170540.2336679-4-sashal@kernel.org>
+
+From: Chao Yu <chao@kernel.org>
+
+[ Upstream commit 10b591e7fb7cdc8c1e53e9c000dc0ef7069aaa76 ]
+
+Bai, Shuangpeng <sjb7183@psu.edu> 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:
+ <TASK>
+ 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 <sjb7183@psu.edu>
+Tested-by: Bai, Shuangpeng <sjb7183@psu.edu>
+Closes: https://lore.kernel.org/lkml/44D8F7B3-68AD-425F-9915-65D27591F93F@psu.edu
+Signed-off-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[ Adjust context ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..0b467c3
--- /dev/null
@@ -0,0 +1,109 @@
+From stable+bounces-204277-greg=kroah.com@vger.kernel.org Tue Dec 30 19:53:39 2025
+From: Sasha Levin <sashal@kernel.org>
+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 <chao@kernel.org>, stable@kernel.org, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251230185324.2411791-1-sashal@kernel.org>
+
+From: Chao Yu <chao@kernel.org>
+
+[ 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 <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[ folio => page ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..5c7883c
--- /dev/null
@@ -0,0 +1,86 @@
+From stable+bounces-204261-greg=kroah.com@vger.kernel.org Tue Dec 30 18:21:01 2025
+From: Sasha Levin <sashal@kernel.org>
+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 <chao@kernel.org>, stable@kernel.org, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251230172055.2345676-1-sashal@kernel.org>
+
+From: Chao Yu <chao@kernel.org>
+
+[ 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 <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[ Adjust context, no rollback ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..02ff318
--- /dev/null
@@ -0,0 +1,206 @@
+From stable+bounces-204252-greg=kroah.com@vger.kernel.org Tue Dec 30 18:12:48 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 Dec 2025 12:05:38 -0500
+Subject: f2fs: keep POSIX_FADV_NOREUSE ranges
+To: stable@vger.kernel.org
+Cc: Jaegeuk Kim <jaegeuk@kernel.org>, Chao Yu <chao@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251230170540.2336679-2-sashal@kernel.org>
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+[ Upstream commit ef0c333cad8d1940f132a7ce15f15920216a3bd5 ]
+
+This patch records POSIX_FADV_NOREUSE ranges for users to reclaim the caches
+instantly off from LRU.
+
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Stable-dep-of: 10b591e7fb7c ("f2fs: fix to avoid updating compression context during writeback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..021cbf5
--- /dev/null
@@ -0,0 +1,139 @@
+From stable+bounces-204251-greg=kroah.com@vger.kernel.org Tue Dec 30 18:05:50 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 Dec 2025 12:05:37 -0500
+Subject: f2fs: remove unused GC_FAILURE_PIN
+To: stable@vger.kernel.org
+Cc: Chao Yu <chao@kernel.org>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251230170540.2336679-1-sashal@kernel.org>
+
+From: Chao Yu <chao@kernel.org>
+
+[ 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 <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Stable-dep-of: 10b591e7fb7c ("f2fs: fix to avoid updating compression context during writeback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..386a466
--- /dev/null
@@ -0,0 +1,239 @@
+From stable+bounces-204270-greg=kroah.com@vger.kernel.org Tue Dec 30 19:19:47 2025
+From: Sasha Levin <sashal@kernel.org>
+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 <chao@kernel.org>, stable@kernel.org, Hong Yun <yhong@link.cuhk.edu.hk>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251230181939.2384947-1-sashal@kernel.org>
+
+From: Chao Yu <chao@kernel.org>
+
+[ 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 <yhong@link.cuhk.edu.hk>
+Tested-by: Hong Yun <yhong@link.cuhk.edu.hk>
+Signed-off-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[ folio => page ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..6ca2119
--- /dev/null
@@ -0,0 +1,39 @@
+From stable+bounces-203411-greg=kroah.com@vger.kernel.org Fri Dec 26 02:54:13 2025
+From: Rahul Sharma <black.hawk@163.com>
+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 <gye976@gmail.com>, Thomas Gleixner <tglx@linutronix.de>, Rahul Sharma <black.hawk@163.com>
+Message-ID: <20251226015307.1660054-1-black.hawk@163.com>
+
+From: Gyeyoung Baek <gye976@gmail.com>
+
+[ 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 <gye976@gmail.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+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 <black.hawk@163.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..b2f41f7
--- /dev/null
@@ -0,0 +1,93 @@
+From stable+bounces-204362-greg=kroah.com@vger.kernel.org Wed Dec 31 16:05:40 2025
+From: Sasha Levin <sashal@kernel.org>
+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 <dongli.zhang@oracle.com>, Chao Gao <chao.gao@intel.com>, Sean Christopherson <seanjc@google.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251231150534.3104156-1-sashal@kernel.org>
+
+From: Dongli Zhang <dongli.zhang@oracle.com>
+
+[ 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 <chao.gao@intel.com>
+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 <dongli.zhang@oracle.com>
+[sean: write changelog]
+Link: https://patch.msgid.link/20251205231913.441872-3-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+[ exported vmx_refresh_apicv_exec_ctrl() and added declaration in vmx.h ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..33d3cdc
--- /dev/null
@@ -0,0 +1,64 @@
+From stable+bounces-204936-greg=kroah.com@vger.kernel.org Mon Jan  5 22:21:33 2026
+From: Sasha Levin <sashal@kernel.org>
+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 <ming.qian@oss.nxp.com>, Nicolas Dufresne <nicolas.dufresne@collabora.com>, Sebastian Fricke <sebastian.fricke@collabora.com>, Hans Verkuil <hverkuil@xs4all.nl>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260105211809.2802485-1-sashal@kernel.org>
+
+From: Ming Qian <ming.qian@oss.nxp.com>
+
+[ 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 <ming.qian@oss.nxp.com>
+Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+Signed-off-by: Sebastian Fricke <sebastian.fricke@collabora.com>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Stable-dep-of: 634c2cd17bd0 ("media: amphion: Remove vpu_vb_is_codecconfig")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..5dcf818
--- /dev/null
@@ -0,0 +1,98 @@
+From stable+bounces-204937-greg=kroah.com@vger.kernel.org Mon Jan  5 22:18:14 2026
+From: Sasha Levin <sashal@kernel.org>
+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 <laurent.pinchart+renesas@ideasonboard.com>, Ming Qian <ming.qian@oss.nxp.com>, Hans Verkuil <hverkuil+cisco@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260105211809.2802485-2-sashal@kernel.org>
+
+From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
+
+[ 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 <laurent.pinchart+renesas@ideasonboard.com>
+Reviewed-by: Ming Qian <ming.qian@oss.nxp.com>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+Stable-dep-of: 634c2cd17bd0 ("media: amphion: Remove vpu_vb_is_codecconfig")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..8decce3
--- /dev/null
@@ -0,0 +1,142 @@
+From stable+bounces-204938-greg=kroah.com@vger.kernel.org Mon Jan  5 22:18:15 2026
+From: Sasha Levin <sashal@kernel.org>
+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 <ming.qian@oss.nxp.com>, Nicolas Dufresne <nicolas.dufresne@collabora.com>, Hans Verkuil <hverkuil+cisco@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260105211809.2802485-3-sashal@kernel.org>
+
+From: Ming Qian <ming.qian@oss.nxp.com>
+
+[ 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 <ming.qian@oss.nxp.com>
+Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..39481a3
--- /dev/null
@@ -0,0 +1,256 @@
+From stable+bounces-204963-greg=kroah.com@vger.kernel.org Tue Jan  6 01:31:59 2026
+From: Sasha Levin <sashal@kernel.org>
+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 <wenst@chromium.org>, Yunfei Dong <yunfei.dong@mediatek.com>, Fei Shao <fshao@chromium.org>, Tomasz Figa <tfiga@chromium.org>, Nicolas Dufresne <nicolas.dufresne@collabora.com>, Hans Verkuil <hverkuil+cisco@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260106003150.2858570-1-sashal@kernel.org>
+
+From: Chen-Yu Tsai <wenst@chromium.org>
+
+[ 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 <yunfei.dong@mediatek.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
+Reviewed-by: Fei Shao <fshao@chromium.org>
+Reviewed-by: Tomasz Figa <tfiga@chromium.org>
+Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+[ 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 <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..aa05d87
--- /dev/null
@@ -0,0 +1,239 @@
+From stable+bounces-204859-greg=kroah.com@vger.kernel.org Mon Jan  5 18:07:47 2026
+From: Sasha Levin <sashal@kernel.org>
+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 <nicolas.dufresne@collabora.com>, Benjamin Gaignard <benjamin.gaignard@collabora.com>, Hans Verkuil <hverkuil+cisco@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260105164900.2676927-3-sashal@kernel.org>
+
+From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+[ 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 <benjamin.gaignard@collabora.com>
+Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <andrzej.p@collabora.com>
+  */
++#include <linux/delay.h>
+ #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 (file)
index 0000000..f2cb51e
--- /dev/null
@@ -0,0 +1,163 @@
+From stable+bounces-204858-greg=kroah.com@vger.kernel.org Mon Jan  5 17:50:22 2026
+From: Sasha Levin <sashal@kernel.org>
+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 <benjamin.gaignard@collabora.com>, Andrzej Pietrasiewicz <andrzej.p@collabora.com>, Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>, Philipp Zabel <p.zabel@pengutronix.de>, Hans Verkuil <hverkuil-cisco@xs4all.nl>, Mauro Carvalho Chehab <mchehab@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260105164900.2676927-2-sashal@kernel.org>
+
+From: Benjamin Gaignard <benjamin.gaignard@collabora.com>
+
+[ 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 <benjamin.gaignard@collabora.com>
+Reviewed-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+CC: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
+CC: Philipp Zabel <p.zabel@pengutronix.de>
+Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
+Stable-dep-of: 19c286b75507 ("media: verisilicon: Fix CPU stalls on G2 bus error")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..aa7a8f3
--- /dev/null
@@ -0,0 +1,73 @@
+From stable+bounces-204857-greg=kroah.com@vger.kernel.org Mon Jan  5 18:07:45 2026
+From: Sasha Levin <sashal@kernel.org>
+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 <benjamin.gaignard@collabora.com>, Andrzej Pietrasiewicz <andrzej.p@collabora.com>, Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>, Philipp Zabel <p.zabel@pengutronix.de>, Hans Verkuil <hverkuil-cisco@xs4all.nl>, Mauro Carvalho Chehab <mchehab@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260105164900.2676927-1-sashal@kernel.org>
+
+From: Benjamin Gaignard <benjamin.gaignard@collabora.com>
+
+[ 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 <benjamin.gaignard@collabora.com>
+Reviewed-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+CC: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
+CC: Philipp Zabel <p.zabel@pengutronix.de>
+Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
+Stable-dep-of: 19c286b75507 ("media: verisilicon: Fix CPU stalls on G2 bus error")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..649bd07
--- /dev/null
@@ -0,0 +1,225 @@
+From sashal@kernel.org Mon Jan  5 18:52:24 2026
+From: Sasha Levin <sashal@kernel.org>
+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" <david@redhat.com>, "Lorenzo Stoakes" <lorenzo.stoakes@oracle.com>, "Alistair Popple" <apopple@nvidia.com>, "Al Viro" <viro@zeniv.linux.org.uk>, "Arnd Bergmann" <arnd@arndb.de>, "Brendan Jackman" <jackmanb@google.com>, "Byungchul Park" <byungchul@sk.com>, "Chengming Zhou" <chengming.zhou@linux.dev>, "Christian Brauner" <brauner@kernel.org>, "Christophe Leroy" <christophe.leroy@csgroup.eu>, "Eugenio Pé rez" <eperezma@redhat.com>, "Greg Kroah-Hartman" <gregkh@linuxfoundation.org>, "Gregory Price" <gourry@gourry.net>, "Harry Yoo" <harry.yoo@oracle.com>, "Huang, Ying" <ying.huang@linux.alibaba.com>, "Jan Kara" <jack@suse.cz>, "Jason Gunthorpe" <jgg@ziepe.ca>, "Jason Wang" <jasowang@redhat.com>, "Jerrin Shaji George" <jerrin.shaji-george@broadcom.com>, "Johannes Weiner" <hannes@cmpxchg.org>, "John Hubbard" <jhubbard@nvidia.com>, "Jonathan Corbet" <corbet@lwn.net>, "Joshua Hahn" <joshua.hahnjy@gmail.com>, "Liam Howlett" <liam.howlett@oracle.com>, "Madhavan Srinivasan" <maddy@linux.ibm.com>, "Mathew Brost" <matthew.brost@intel.com>, "Matthew Wilcox (Oracle)" <willy@infradead.org>, "Miaohe Lin" <linmiaohe@huawei.com>, "Michael Ellerman" <mpe@ellerman.id.au>, "Michael S. Tsirkin" <mst@redhat.com>, "Michal Hocko" <mhocko@suse.com>, "Mike Rapoport" <rppt@kernel.org>, "Minchan Kim" <minchan@kernel.org>, "Naoya Horiguchi" <nao.horiguchi@gmail.com>, "Nicholas Piggin" <npiggin@gmail.com>, "Oscar Salvador" <osalvador@suse.de>, "Peter Xu" <peterx@redhat.com>, "Qi Zheng" <zhengqi.arch@bytedance.com>, "Rakie Kim" <rakie.kim@sk.com>, "Rik van Riel" <riel@surriel.com>, "Sergey Senozhatsky" <senozhatsky@chromium.org>, "Shakeel Butt" <shakeel.butt@linux.dev>, "Suren Baghdasaryan" <surenb@google.com>, "Vlastimil Babka" <vbabka@suse.cz>, "Xuan Zhuo" <xuanzhuo@linux.alibaba.com>, "xu xin" <xu.xin16@zte.com.cn>, "Zi Yan" <ziy@nvidia.com>, "Andrew Morton" <akpm@linux-foundation.org>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260105175213.2699504-2-sashal@kernel.org>
+
+From: David Hildenbrand <david@redhat.com>
+
+[ 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 <david@redhat.com>
+Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
+Cc: Alistair Popple <apopple@nvidia.com>
+Cc: Al Viro <viro@zeniv.linux.org.uk>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Brendan Jackman <jackmanb@google.com>
+Cc: Byungchul Park <byungchul@sk.com>
+Cc: Chengming Zhou <chengming.zhou@linux.dev>
+Cc: Christian Brauner <brauner@kernel.org>
+Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
+Cc: Eugenio Pé rez <eperezma@redhat.com>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Gregory Price <gourry@gourry.net>
+Cc: Harry Yoo <harry.yoo@oracle.com>
+Cc: "Huang, Ying" <ying.huang@linux.alibaba.com>
+Cc: Jan Kara <jack@suse.cz>
+Cc: Jason Gunthorpe <jgg@ziepe.ca>
+Cc: Jason Wang <jasowang@redhat.com>
+Cc: Jerrin Shaji George <jerrin.shaji-george@broadcom.com>
+Cc: Johannes Weiner <hannes@cmpxchg.org>
+Cc: John Hubbard <jhubbard@nvidia.com>
+Cc: Jonathan Corbet <corbet@lwn.net>
+Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
+Cc: Liam Howlett <liam.howlett@oracle.com>
+Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
+Cc: Mathew Brost <matthew.brost@intel.com>
+Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
+Cc: Miaohe Lin <linmiaohe@huawei.com>
+Cc: Michael Ellerman <mpe@ellerman.id.au>
+Cc: "Michael S. Tsirkin" <mst@redhat.com>
+Cc: Michal Hocko <mhocko@suse.com>
+Cc: Mike Rapoport <rppt@kernel.org>
+Cc: Minchan Kim <minchan@kernel.org>
+Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
+Cc: Nicholas Piggin <npiggin@gmail.com>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: Peter Xu <peterx@redhat.com>
+Cc: Qi Zheng <zhengqi.arch@bytedance.com>
+Cc: Rakie Kim <rakie.kim@sk.com>
+Cc: Rik van Riel <riel@surriel.com>
+Cc: Sergey Senozhatsky <senozhatsky@chromium.org>
+Cc: Shakeel Butt <shakeel.butt@linux.dev>
+Cc: Suren Baghdasaryan <surenb@google.com>
+Cc: Vlastimil Babka <vbabka@suse.cz>
+Cc: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+Cc: xu xin <xu.xin16@zte.com.cn>
+Cc: Zi Yan <ziy@nvidia.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: 0da2ba35c0d5 ("powerpc/pseries/cmm: adjust BALLOON_MIGRATE when migrating pages")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..7b7bc53
--- /dev/null
@@ -0,0 +1,109 @@
+From sashal@kernel.org Mon Jan  5 18:52:20 2026
+From: Sasha Levin <sashal@kernel.org>
+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" <david@redhat.com>, "Zi Yan" <ziy@nvidia.com>, "Lorenzo Stoakes" <lorenzo.stoakes@oracle.com>, "Alistair Popple" <apopple@nvidia.com>, "Al Viro" <viro@zeniv.linux.org.uk>, "Arnd Bergmann" <arnd@arndb.de>, "Brendan Jackman" <jackmanb@google.com>, "Byungchul Park" <byungchul@sk.com>, "Chengming Zhou" <chengming.zhou@linux.dev>, "Christian Brauner" <brauner@kernel.org>, "Christophe Leroy" <christophe.leroy@csgroup.eu>, "Eugenio Pé rez" <eperezma@redhat.com>, "Greg Kroah-Hartman" <gregkh@linuxfoundation.org>, "Gregory Price" <gourry@gourry.net>, "Huang, Ying" <ying.huang@linux.alibaba.com>, "Jan Kara" <jack@suse.cz>, "Jason Gunthorpe" <jgg@ziepe.ca>, "Jason Wang" <jasowang@redhat.com>, "Jerrin Shaji George" <jerrin.shaji-george@broadcom.com>, "Johannes Weiner" <hannes@cmpxchg.org>, "John Hubbard" <jhubbard@nvidia.com>, "Jonathan Corbet" <corbet@lwn.net>, "Joshua Hahn" <joshua.hahnjy@gmail.com>, "Liam Howlett" <liam.howlett@oracle.com>, "Madhavan Srinivasan" <maddy@linux.ibm.com>, "Mathew Brost" <matthew.brost@intel.com>, "Matthew Wilcox (Oracle)" <willy@infradead.org>, "Miaohe Lin" <linmiaohe@huawei.com>, "Michael Ellerman" <mpe@ellerman.id.au>, "Michael S. Tsirkin" <mst@redhat.com>, "Michal Hocko" <mhocko@suse.com>, "Mike Rapoport" <rppt@kernel.org>, "Minchan Kim" <minchan@kernel.org>, "Naoya Horiguchi" <nao.horiguchi@gmail.com>, "Nicholas Piggin" <npiggin@gmail.com>, "Oscar Salvador" <osalvador@suse.de>, "Peter Xu" <peterx@redhat.com>, "Qi Zheng" <zhengqi.arch@bytedance.com>, "Rakie Kim" <rakie.kim@sk.com>, "Rik van Riel" <riel@surriel.com>, "Sergey Senozhatsky" <senozhatsky@chromium.org>, "Shakeel Butt" <shakeel.butt@linux.dev>, "Suren Baghdasaryan" <surenb@google.com>, "Vlastimil Babka" <vbabka@suse.cz>, "Xuan Zhuo" <xuanzhuo@linux.alibaba.com>, "xu xin" <xu.xin16@zte.com.cn>, "Harry Yoo" <harry.yoo@oracle.com>, "Andrew Morton" <akpm@linux-foundation.org>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260105175213.2699504-1-sashal@kernel.org>
+
+From: David Hildenbrand <david@redhat.com>
+
+[ 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 <david@redhat.com>
+Acked-by: Zi Yan <ziy@nvidia.com>
+Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
+Cc: Alistair Popple <apopple@nvidia.com>
+Cc: Al Viro <viro@zeniv.linux.org.uk>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Brendan Jackman <jackmanb@google.com>
+Cc: Byungchul Park <byungchul@sk.com>
+Cc: Chengming Zhou <chengming.zhou@linux.dev>
+Cc: Christian Brauner <brauner@kernel.org>
+Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
+Cc: Eugenio Pé rez <eperezma@redhat.com>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Gregory Price <gourry@gourry.net>
+Cc: "Huang, Ying" <ying.huang@linux.alibaba.com>
+Cc: Jan Kara <jack@suse.cz>
+Cc: Jason Gunthorpe <jgg@ziepe.ca>
+Cc: Jason Wang <jasowang@redhat.com>
+Cc: Jerrin Shaji George <jerrin.shaji-george@broadcom.com>
+Cc: Johannes Weiner <hannes@cmpxchg.org>
+Cc: John Hubbard <jhubbard@nvidia.com>
+Cc: Jonathan Corbet <corbet@lwn.net>
+Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
+Cc: Liam Howlett <liam.howlett@oracle.com>
+Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
+Cc: Mathew Brost <matthew.brost@intel.com>
+Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
+Cc: Miaohe Lin <linmiaohe@huawei.com>
+Cc: Michael Ellerman <mpe@ellerman.id.au>
+Cc: "Michael S. Tsirkin" <mst@redhat.com>
+Cc: Michal Hocko <mhocko@suse.com>
+Cc: Mike Rapoport <rppt@kernel.org>
+Cc: Minchan Kim <minchan@kernel.org>
+Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
+Cc: Nicholas Piggin <npiggin@gmail.com>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: Peter Xu <peterx@redhat.com>
+Cc: Qi Zheng <zhengqi.arch@bytedance.com>
+Cc: Rakie Kim <rakie.kim@sk.com>
+Cc: Rik van Riel <riel@surriel.com>
+Cc: Sergey Senozhatsky <senozhatsky@chromium.org>
+Cc: Shakeel Butt <shakeel.butt@linux.dev>
+Cc: Suren Baghdasaryan <surenb@google.com>
+Cc: Vlastimil Babka <vbabka@suse.cz>
+Cc: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+Cc: xu xin <xu.xin16@zte.com.cn>
+Cc: Harry Yoo <harry.yoo@oracle.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: 0da2ba35c0d5 ("powerpc/pseries/cmm: adjust BALLOON_MIGRATE when migrating pages")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..cfaa20d
--- /dev/null
@@ -0,0 +1,46 @@
+From jefflexu@linux.alibaba.com Thu Dec 11 03:35:23 2025
+From: Jingbo Xu <jefflexu@linux.alibaba.com>
+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 <jefflexu@linux.alibaba.com>
+
+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 <jefflexu@linux.alibaba.com>
+Reported-by: Joseph Qi <joseph.qi@linux.alibaba.com>
+Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
+Cc: Stefan Roesch <shr@devkernel.io>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..b4744d6
--- /dev/null
@@ -0,0 +1,41 @@
+From stable+bounces-200760-greg=kroah.com@vger.kernel.org Thu Dec 11 03:35:48 2025
+From: Jingbo Xu <jefflexu@linux.alibaba.com>
+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 <jefflexu@linux.alibaba.com>
+
+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 <jefflexu@linux.alibaba.com>
+Cc: Joseph Qi <joseph.qi@linux.alibaba.com>
+Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
+Cc: Stefan Roesch <shr@devkernel.io>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..1c363a3
--- /dev/null
@@ -0,0 +1,49 @@
+From stable+bounces-200101-greg=kroah.com@vger.kernel.org Fri Dec  5 04:13:57 2025
+From: Chen Yu <xnguchen@sina.cn>
+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 <vladimir.oltean@nxp.com>
+
+[ 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 <vladimir.oltean@nxp.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20250318115716.2124395-4-vladimir.oltean@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Chen Yu <xnguchen@sina.cn>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..f063ce8
--- /dev/null
@@ -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" <dongchenchen2@huawei.com>, "Jakub Kicinski" <kuba@kernel.org>, syzbot+204a4382fcb3311f3858@syzkaller.appspotmail.com, "Toke Høiland-Jørgensen" <toke@redhat.com>, "Mina Almasry" <almasrymina@google.com>, "Ruohan Lan" <ruohanlan@aliyun.com>
+Message-ID: <20251210121502.5066-1-ruohanlan@aliyun.com>
+
+From: Dong Chenchen <dongchenchen2@huawei.com>
+
+[ 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:
+ <TASK>
+ __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 <kuba@kernel.org>
+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 <dongchenchen2@huawei.com>
+Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
+Reviewed-by: Mina Almasry <almasrymina@google.com>
+Link: https://patch.msgid.link/20250527114152.3119109-1-dongchenchen2@huawei.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ Minor context change fixed. ]
+Signed-off-by: Ruohan Lan <ruohanlan@aliyun.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..0dad86c
--- /dev/null
@@ -0,0 +1,228 @@
+From 353d7a84c214f184d5a6b62acdec8b4424159b7c Mon Sep 17 00:00:00 2001
+From: Hari Bathini <hbathini@linux.ibm.com>
+Date: Mon, 1 Jul 2024 18:30:21 +0530
+Subject: powerpc/64s/radix/kfence: map __kfence_pool at page granularity
+
+From: Hari Bathini <hbathini@linux.ibm.com>
+
+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 <hbathini@linux.ibm.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://msgid.link/20240701130021.578240-1-hbathini@linux.ibm.com
+Cc: Aboorva Devarajan <aboorvad@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <linux/hugetlb.h>
+ #include <linux/string_helpers.h>
+ #include <linux/memory.h>
++#include <linux/kfence.h>
+ #include <asm/pgalloc.h>
+ #include <asm/mmu_context.h>
+@@ -31,6 +32,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/ultravisor.h>
+ #include <asm/set_memory.h>
++#include <asm/kfence.h>
+ #include <trace/events/thp.h>
+@@ -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 (file)
index 0000000..4ecd5c0
--- /dev/null
@@ -0,0 +1,45 @@
+From stable+bounces-204882-greg=kroah.com@vger.kernel.org Mon Jan  5 18:52:38 2026
+From: Sasha Levin <sashal@kernel.org>
+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 <david@redhat.com>, "Ritesh Harjani (IBM)" <ritesh.list@gmail.com>, Christophe Leroy <christophe.leroy@csgroup.eu>, Madhavan Srinivasan <maddy@linux.ibm.com>, Michael Ellerman <mpe@ellerman.id.au>, Nicholas Piggin <npiggin@gmail.com>, Andrew Morton <akpm@linux-foundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260105175213.2699504-3-sashal@kernel.org>
+
+From: David Hildenbrand <david@redhat.com>
+
+[ 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 <david@redhat.com>
+Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
+Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
+Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
+Cc: Michael Ellerman <mpe@ellerman.id.au>
+Cc: Nicholas Piggin <npiggin@gmail.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);
index 156a673c6415da4f66bd1d7f5003e5c55bcda443..5443c67f8935c9b191dc06109bfa7776511e96d5 100644 (file)
@@ -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 (file)
index 0000000..644d90c
--- /dev/null
@@ -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 <fw@strlen.de>
+
+[ 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 <dvyukov@google.com>
+Fixes: c2f672fc9464 ("xfrm: state lookup can be lockless")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+[ Minor context change fixed ]
+Signed-off-by: Rajani Kantha <681739313@139.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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;
+ }