--- /dev/null
+From stable+bounces-272222-greg=kroah.com@vger.kernel.org Mon Jul 6 16:57:59 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 6 Jul 2026 09:17:08 -0400
+Subject: apparmor: advertise the tcp fast open fix is applied
+To: stable@vger.kernel.org
+Cc: John Johansen <john.johansen@canonical.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260706131708.2289810-1-sashal@kernel.org>
+
+From: John Johansen <john.johansen@canonical.com>
+
+[ Upstream commit 2f6701a5ce6257ae7a64ddc6d89d0a08d2a034f8 ]
+
+The fix for tcp-fast-open ensures that the connect permission is being
+mediated correctly but it didn't add an artifact to the feature set to
+advertise the fix is available. Add an artifact so that the test suite
+can identify if the fix has not been properly applied or a new
+unexpected regression has occurred.
+
+Fixes: 4d587cd8a7215 ("apparmor: mediate the implicit connect of TCP fast open sendmsg")
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ security/apparmor/net.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/security/apparmor/net.c
++++ b/security/apparmor/net.c
+@@ -21,6 +21,7 @@
+
+ struct aa_sfs_entry aa_sfs_entry_network[] = {
+ AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK),
++ AA_SFS_FILE_BOOLEAN("tcp-fast-open", 1),
+ { }
+ };
+
--- /dev/null
+From stable+bounces-271576-greg=kroah.com@vger.kernel.org Fri Jul 3 00:23:04 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Jul 2026 18:22:52 -0400
+Subject: device property: initialize the remaining fields of fwnode_handle in fwnode_init()
+To: stable@vger.kernel.org
+Cc: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>, Sakari Ailus <sakari.ailus@linux.intel.com>, "Rafael J. Wysocki (Intel)" <rafael@kernel.org>, Andy Shevchenko <andriy.shevchenko@linux.intel.com>, Danilo Krummrich <dakr@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260702222252.3701173-1-sashal@kernel.org>
+
+From: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+
+[ Upstream commit 7eba000621fff223dd7bab484d48918c7c77a307 ]
+
+If a firmware node is allocated on the stack (for instance: temporary
+software node whose life-time we control) or on the heap - but using a
+non-zeroing allocation function - and initialized using fwnode_init(),
+its secondary pointer will contain uninitialized memory which likely
+will be neither NULL nor IS_ERR() and so may end up being dereferenced
+(for example: in dev_to_swnode()). Set fwnode->secondary to NULL on
+initialization. While at it: initialize the remaining fields of struct
+fwnode_handle too just to be sure.
+
+Cc: stable@vger.kernel.org
+Fixes: 01bb86b380a3 ("driver core: Add fwnode_init()")
+Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Reviewed-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260511074927.9473-1-bartosz.golaszewski@oss.qualcomm.com
+[ Fix typo in commit message. - Danilo ]
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/fwnode.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/include/linux/fwnode.h
++++ b/include/linux/fwnode.h
+@@ -202,8 +202,10 @@ static inline void fwnode_init(struct fw
+ {
+ fwnode->secondary = NULL;
+ fwnode->ops = ops;
++ fwnode->dev = NULL;
+ INIT_LIST_HEAD(&fwnode->consumers);
+ INIT_LIST_HEAD(&fwnode->suppliers);
++ fwnode->flags = 0;
+ }
+
+ static inline void fwnode_set_flag(struct fwnode_handle *fwnode,
--- /dev/null
+From stable+bounces-271775-greg=kroah.com@vger.kernel.org Fri Jul 3 15:33:23 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 3 Jul 2026 09:23:42 -0400
+Subject: f2fs: atomic: fix UAF issue on f2fs_inode_info.atomic_inode
+To: stable@vger.kernel.org
+Cc: Chao Yu <chao@kernel.org>, stable@kernel.org, Daeho Jeong <daehojeong@google.com>, Sunmin Jeong <s_min.jeong@samsung.com>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260703132342.4101156-1-sashal@kernel.org>
+
+From: Chao Yu <chao@kernel.org>
+
+[ Upstream commit e0288584baa5dc41df4a829a023c4c1b33fe53d7 ]
+
+- ioctl(F2FS_IOC_GARBAGE_COLLECT_RANGE) - shrink
+ - f2fs_gc
+ - gc_data_segment
+ - ra_data_block(cow_inode)
+ - mapping = F2FS_I(inode)->atomic_inode->i_mapping
+ : f2fs_is_cow_file(cow_inode) is true
+ - f2fs_evict_inode(atomic_inode)
+ - clear_inode_flag(fi->cow_inode, FI_COW_FILE)
+ - F2FS_I(fi->cow_inode)->atomic_inode = NULL
+ ...
+ - truncate_inode_pages_final(atomic_inode)
+ - f2fs_grab_cache_folio(mapping)
+ : create folio in atomic_inode->mapping
+ - clear_inode(atomic_inode)
+ - BUG_ON(atomic_inode->i_data.nrpages)
+
+We need to add a reference on fi->atomic_inode before using its mapping
+field during garbage collection, otherwise, it will cause UAF issue.
+
+Cc: stable@kernel.org
+Cc: Daeho Jeong <daehojeong@google.com>
+Cc: Sunmin Jeong <s_min.jeong@samsung.com>
+Fixes: 3db1de0e582c ("f2fs: change the current atomic write way")
+Fixes: f18d00769336 ("f2fs: use meta inode for GC of COW file")
+Signed-off-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/gc.c | 50 ++++++++++++++++++++++++++++++++++++++++++--------
+ fs/f2fs/inode.c | 11 ++++++++---
+ 2 files changed, 50 insertions(+), 11 deletions(-)
+
+--- a/fs/f2fs/gc.c
++++ b/fs/f2fs/gc.c
+@@ -1213,8 +1213,8 @@ static bool is_alive(struct f2fs_sb_info
+ static int ra_data_block(struct inode *inode, pgoff_t index)
+ {
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+- struct address_space *mapping = f2fs_is_cow_file(inode) ?
+- F2FS_I(inode)->atomic_inode->i_mapping : inode->i_mapping;
++ struct address_space *mapping = inode->i_mapping;
++ struct inode *atomic_inode = NULL;
+ struct dnode_of_data dn;
+ struct page *page;
+ struct f2fs_io_info fio = {
+@@ -1229,9 +1229,22 @@ static int ra_data_block(struct inode *i
+ };
+ int err;
+
++ f2fs_down_read(&F2FS_I(inode)->i_sem);
++ if (f2fs_is_cow_file(inode)) {
++ atomic_inode = igrab(F2FS_I(inode)->atomic_inode);
++ if (!atomic_inode) {
++ f2fs_up_read(&F2FS_I(inode)->i_sem);
++ return -EBUSY;
++ }
++ mapping = atomic_inode->i_mapping;
++ }
++ f2fs_up_read(&F2FS_I(inode)->i_sem);
++
+ page = f2fs_grab_cache_page(mapping, index, true);
+- if (!page)
+- return -ENOMEM;
++ if (!page) {
++ err = -ENOMEM;
++ goto out_iput;
++ }
+
+ if (f2fs_lookup_read_extent_cache_block(inode, index,
+ &dn.data_blkaddr)) {
+@@ -1288,11 +1301,16 @@ got_it:
+ f2fs_update_iostat(sbi, inode, FS_DATA_READ_IO, F2FS_BLKSIZE);
+ f2fs_update_iostat(sbi, NULL, FS_GDATA_READ_IO, F2FS_BLKSIZE);
+
++ if (atomic_inode)
++ iput(atomic_inode);
+ return 0;
+ put_encrypted_page:
+ f2fs_put_page(fio.encrypted_page, 1);
+ put_page:
+ f2fs_put_page(page, 1);
++out_iput:
++ if (atomic_inode)
++ iput(atomic_inode);
+ return err;
+ }
+
+@@ -1303,8 +1321,8 @@ put_page:
+ static int move_data_block(struct inode *inode, block_t bidx,
+ int gc_type, unsigned int segno, int off)
+ {
+- struct address_space *mapping = f2fs_is_cow_file(inode) ?
+- F2FS_I(inode)->atomic_inode->i_mapping : inode->i_mapping;
++ struct address_space *mapping = inode->i_mapping;
++ struct inode *atomic_inode = NULL;
+ struct f2fs_io_info fio = {
+ .sbi = F2FS_I_SB(inode),
+ .ino = inode->i_ino,
+@@ -1326,10 +1344,23 @@ static int move_data_block(struct inode
+ (fio.sbi->gc_mode != GC_URGENT_HIGH) ?
+ CURSEG_ALL_DATA_ATGC : CURSEG_COLD_DATA;
+
++ f2fs_down_read(&F2FS_I(inode)->i_sem);
++ if (f2fs_is_cow_file(inode)) {
++ atomic_inode = igrab(F2FS_I(inode)->atomic_inode);
++ if (!atomic_inode) {
++ f2fs_up_read(&F2FS_I(inode)->i_sem);
++ return -EBUSY;
++ }
++ mapping = atomic_inode->i_mapping;
++ }
++ f2fs_up_read(&F2FS_I(inode)->i_sem);
++
+ /* do not read out */
+ page = f2fs_grab_cache_page(mapping, bidx, false);
+- if (!page)
+- return -ENOMEM;
++ if (!page) {
++ err = -ENOMEM;
++ goto out_iput;
++ }
+
+ if (!check_valid_map(F2FS_I_SB(inode), segno, off)) {
+ err = -ENOENT;
+@@ -1456,6 +1487,9 @@ put_out:
+ f2fs_put_dnode(&dn);
+ out:
+ f2fs_put_page(page, 1);
++out_iput:
++ if (atomic_inode)
++ iput(atomic_inode);
+ return err;
+ }
+
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -839,10 +839,15 @@ void f2fs_evict_inode(struct inode *inod
+ f2fs_abort_atomic_write(inode, true);
+
+ if (fi->cow_inode && f2fs_is_cow_file(fi->cow_inode)) {
+- clear_inode_flag(fi->cow_inode, FI_COW_FILE);
+- F2FS_I(fi->cow_inode)->atomic_inode = NULL;
+- iput(fi->cow_inode);
++ struct inode *cow_inode = fi->cow_inode;
++
++ f2fs_down_write(&F2FS_I(cow_inode)->i_sem);
++ clear_inode_flag(cow_inode, FI_COW_FILE);
++ F2FS_I(cow_inode)->atomic_inode = NULL;
+ fi->cow_inode = NULL;
++ f2fs_up_write(&F2FS_I(cow_inode)->i_sem);
++
++ iput(cow_inode);
+ }
+
+ trace_f2fs_evict_inode(inode);
--- /dev/null
+From stable+bounces-271805-greg=kroah.com@vger.kernel.org Fri Jul 3 16:35:31 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 3 Jul 2026 10:26:35 -0400
+Subject: f2fs: bound i_inline_xattr_size for non-inline-xattr inodes
+To: stable@vger.kernel.org
+Cc: Bryam Vargas <hexlabsecurity@proton.me>, Chao Yu <chao@kernel.org>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260703142635.55675-1-sashal@kernel.org>
+
+From: Bryam Vargas <hexlabsecurity@proton.me>
+
+[ Upstream commit 378acf3cf19b6af6cba55e8dd1154c4e1504bae8 ]
+
+When the flexible_inline_xattr feature is enabled, do_read_inode() loads
+the on-disk i_inline_xattr_size unconditionally:
+
+ if (f2fs_sb_has_flexible_inline_xattr(sbi))
+ fi->i_inline_xattr_size = le16_to_cpu(ri->i_inline_xattr_size);
+
+but sanity_check_inode() only range-checks it when the inode also has the
+FI_INLINE_XATTR flag set. An inode that carries an inline dentry or inline
+data but not FI_INLINE_XATTR -- the normal layout for an inline
+directory -- therefore keeps a fully attacker-controlled
+i_inline_xattr_size from a crafted image.
+
+get_inline_xattr_addrs() returns that value with no flag gating, so it
+feeds the inode geometry:
+
+ MAX_INLINE_DATA() = 4 * (CUR_ADDRS_PER_INODE - i_inline_xattr_size - 1)
+ NR_INLINE_DENTRY() = MAX_INLINE_DATA() * BITS_PER_BYTE / (...)
+ addrs_per_page() = CUR_ADDRS_PER_INODE - i_inline_xattr_size
+
+A large i_inline_xattr_size drives MAX_INLINE_DATA() and NR_INLINE_DENTRY()
+negative, so make_dentry_ptr_inline() sets d->max (int) to a negative
+value. The inline directory walk then compares an unsigned long bit_pos
+against that negative d->max, which is promoted to a huge unsigned bound,
+and reads far past the inline area:
+
+ while (bit_pos < d->max) /* fs/f2fs/dir.c */
+ ... test_bit_le(bit_pos, d->bitmap) / d->dentry[bit_pos] ...
+
+Mounting a crafted image and reading such a directory triggers an
+out-of-bounds read in f2fs_fill_dentries(); the same underflow also
+corrupts ADDRS_PER_INODE for regular files.
+
+Validate i_inline_xattr_size against MAX_INLINE_XATTR_SIZE whenever the
+flexible_inline_xattr feature is enabled -- i.e. whenever the value is
+loaded from disk and consumed -- and keep the lower MIN_INLINE_XATTR_SIZE
+bound gated on inodes that actually carry an inline xattr, so legitimate
+inodes with i_inline_xattr_size == 0 are still accepted.
+
+Cc: stable@vger.kernel.org
+Fixes: 6afc662e68b5 ("f2fs: support flexible inline xattr size")
+Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/inode.c | 19 ++++++++++---------
+ 1 file changed, 10 insertions(+), 9 deletions(-)
+
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -308,15 +308,6 @@ static bool sanity_check_inode(struct in
+ F2FS_TOTAL_EXTRA_ATTR_SIZE);
+ return false;
+ }
+- if (f2fs_sb_has_flexible_inline_xattr(sbi) &&
+- f2fs_has_inline_xattr(inode) &&
+- (!fi->i_inline_xattr_size ||
+- fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE)) {
+- f2fs_warn(sbi, "%s: inode (ino=%lx) has corrupted i_inline_xattr_size: %d, max: %lu",
+- __func__, inode->i_ino, fi->i_inline_xattr_size,
+- MAX_INLINE_XATTR_SIZE);
+- return false;
+- }
+ if (f2fs_sb_has_compression(sbi) &&
+ fi->i_flags & F2FS_COMPR_FL &&
+ F2FS_FITS_IN_INODE(ri, fi->i_extra_isize,
+@@ -326,6 +317,16 @@ static bool sanity_check_inode(struct in
+ }
+ }
+
++ if (f2fs_sb_has_flexible_inline_xattr(sbi) &&
++ (fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE ||
++ (f2fs_has_inline_xattr(inode) &&
++ fi->i_inline_xattr_size < MIN_INLINE_XATTR_SIZE))) {
++ f2fs_warn(sbi, "%s: inode (ino=%lx) has corrupted i_inline_xattr_size: %d, min: %zu, max: %lu",
++ __func__, inode->i_ino, fi->i_inline_xattr_size,
++ MIN_INLINE_XATTR_SIZE, MAX_INLINE_XATTR_SIZE);
++ return false;
++ }
++
+ if (!f2fs_sb_has_extra_attr(sbi)) {
+ if (f2fs_sb_has_project_quota(sbi)) {
+ f2fs_warn(sbi, "%s: corrupted inode ino=%lx, wrong feature flag: %u, run fsck to fix.",
--- /dev/null
+From stable+bounces-271856-greg=kroah.com@vger.kernel.org Fri Jul 3 20:50:22 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 3 Jul 2026 14:50:15 -0400
+Subject: f2fs: fix listxattr handling of corrupted xattr entries
+To: stable@vger.kernel.org
+Cc: Keshav Verma <iganschel@gmail.com>, stable@kernel.org, Chao Yu <chao@kernel.org>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260703185015.285028-1-sashal@kernel.org>
+
+From: Keshav Verma <iganschel@gmail.com>
+
+[ Upstream commit 5ef5bc304f23c3fe255d4936472378dcb74d0e94 ]
+
+Validate the xattr entry before reading its fields in f2fs_listxattr().
+Return -EFSCORRUPTED when the entry is outside the valid xattr storage
+area instead of returning a successful partial result.
+
+Fixes: 688078e7f36c ("f2fs: fix to avoid memory leakage in f2fs_listxattr")
+Cc: stable@kernel.org
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Keshav Verma <iganschel@gmail.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/xattr.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/fs/f2fs/xattr.c
++++ b/fs/f2fs/xattr.c
+@@ -581,8 +581,6 @@ ssize_t f2fs_listxattr(struct dentry *de
+ size_t prefix_len;
+ size_t size;
+
+- prefix = f2fs_xattr_prefix(entry->e_name_index, dentry);
+-
+ if ((void *)(entry) + sizeof(__u32) > last_base_addr ||
+ (void *)XATTR_NEXT_ENTRY(entry) > last_base_addr) {
+ f2fs_err(F2FS_I_SB(inode), "list inode (%lu) has corrupted xattr",
+@@ -590,9 +588,11 @@ ssize_t f2fs_listxattr(struct dentry *de
+ set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
+ f2fs_handle_error(F2FS_I_SB(inode),
+ ERROR_CORRUPTED_XATTR);
+- break;
++ error = -EFSCORRUPTED;
++ goto cleanup;
+ }
+
++ prefix = f2fs_xattr_prefix(entry->e_name_index, dentry);
+ if (!prefix)
+ continue;
+
--- /dev/null
+From stable+bounces-271846-greg=kroah.com@vger.kernel.org Fri Jul 3 20:32:05 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 3 Jul 2026 14:24:12 -0400
+Subject: f2fs: fix potential deadlock in f2fs_balance_fs()
+To: stable@vger.kernel.org
+Cc: Ruipeng Qi <ruipengqi3@gmail.com>, Chao Yu <chao@kernel.org>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260703182413.254727-1-sashal@kernel.org>
+
+From: Ruipeng Qi <ruipengqi3@gmail.com>
+
+[ Upstream commit dd3114870771562036fdcf5abe813956f36d224d ]
+
+When the f2fs filesystem space is nearly exhausted, we encounter deadlock
+issues as below:
+
+INFO: task A:1890 blocked for more than 120 seconds.
+ Tainted: G O 6.12.41-g3fe07ddf05ab #1
+"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+task:A state:D stack:0 pid:1890 tgid:1626 ppid:1153 flags:0x00000204
+Call trace:
+ __switch_to+0xf4/0x158
+ __schedule+0x27c/0x908
+ schedule+0x3c/0x118
+ io_schedule+0x44/0x68
+ folio_wait_bit_common+0x174/0x370
+ folio_wait_bit+0x20/0x38
+ folio_wait_writeback+0x54/0xc8
+ truncate_inode_partial_folio+0x70/0x1e0
+ truncate_inode_pages_range+0x1b0/0x450
+ truncate_pagecache+0x54/0x88
+ f2fs_file_write_iter+0x3e8/0xb80
+ do_iter_readv_writev+0xf0/0x1e0
+ vfs_writev+0x138/0x2c8
+ do_writev+0x88/0x130
+ __arm64_sys_writev+0x28/0x40
+ invoke_syscall+0x50/0x120
+ el0_svc_common.constprop.0+0xc8/0xf0
+ do_el0_svc+0x24/0x38
+ el0_svc+0x30/0xf8
+ el0t_64_sync_handler+0x120/0x130
+ el0t_64_sync+0x190/0x198
+
+INFO: task kworker/u8:11:2680853 blocked for more than 120 seconds.
+ Tainted: G O 6.12.41-g3fe07ddf05ab #1
+"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+task:kworker/u8:11 state:D stack:0 pid:2680853 tgid:2680853 ppid:2 flags:0x00000208
+Workqueue: writeback wb_workfn (flush-254:0)
+Call trace:
+ __switch_to+0xf4/0x158
+ __schedule+0x27c/0x908
+ schedule+0x3c/0x118
+ io_schedule+0x44/0x68
+ folio_wait_bit_common+0x174/0x370
+ __filemap_get_folio+0x214/0x348
+ pagecache_get_page+0x20/0x70
+ f2fs_get_read_data_page+0x150/0x3e8
+ f2fs_get_lock_data_page+0x2c/0x160
+ move_data_page+0x50/0x478
+ do_garbage_collect+0xd38/0x1528
+ f2fs_gc+0x240/0x7e0
+ f2fs_balance_fs+0x1a0/0x208
+ f2fs_write_single_data_page+0x6e4/0x730
+ f2fs_write_cache_pages+0x378/0x9b0
+ f2fs_write_data_pages+0x2e4/0x388
+ do_writepages+0x8c/0x2c8
+ __writeback_single_inode+0x4c/0x498
+ writeback_sb_inodes+0x234/0x4a8
+ __writeback_inodes_wb+0x58/0x118
+ wb_writeback+0x2f8/0x3c0
+ wb_workfn+0x2c4/0x508
+ process_one_work+0x180/0x408
+ worker_thread+0x258/0x368
+ kthread+0x118/0x128
+ ret_from_fork+0x10/0x200
+
+INFO: task kworker/u8:8:2641297 blocked for more than 120 seconds.
+ Tainted: G O 6.12.41-g3fe07ddf05ab #1
+"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+task:kworker/u8:8 state:D stack:0 pid:2641297 tgid:2641297 ppid:2 flags:0x00000208
+Workqueue: writeback wb_workfn (flush-254:0)
+Call trace:
+ __switch_to+0xf4/0x158
+ __schedule+0x27c/0x908
+ rt_mutex_schedule+0x30/0x60
+ __rt_mutex_slowlock_locked.constprop.0+0x460/0x8a8
+ rwbase_write_lock+0x24c/0x378
+ down_write+0x1c/0x30
+ f2fs_balance_fs+0x184/0x208
+ f2fs_write_inode+0xf4/0x328
+ __writeback_single_inode+0x370/0x498
+ writeback_sb_inodes+0x234/0x4a8
+ __writeback_inodes_wb+0x58/0x118
+ wb_writeback+0x2f8/0x3c0
+ wb_workfn+0x2c4/0x508
+ process_one_work+0x180/0x408
+ worker_thread+0x258/0x368
+ kthread+0x118/0x128
+ ret_from_fork+0x10/0x20
+
+INFO: task B:1902 blocked for more than 120 seconds.
+ Tainted: G O 6.12.41-g3fe07ddf05ab #1
+"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+task:B state:D stack:0 pid:1902 tgid:1626 ppid:1153 flags:0x0000020c
+Call trace:
+ __switch_to+0xf4/0x158
+ __schedule+0x27c/0x908
+ rt_mutex_schedule+0x30/0x60
+ __rt_mutex_slowlock_locked.constprop.0+0x460/0x8a8
+ rwbase_write_lock+0x24c/0x378
+ down_write+0x1c/0x30
+ f2fs_balance_fs+0x184/0x208
+ f2fs_map_blocks+0x94c/0x1110
+ f2fs_file_write_iter+0x228/0xb80
+ do_iter_readv_writev+0xf0/0x1e0
+ vfs_writev+0x138/0x2c8
+ do_writev+0x88/0x130
+ __arm64_sys_writev+0x28/0x40
+ invoke_syscall+0x50/0x120
+ el0_svc_common.constprop.0+0xc8/0xf0
+ do_el0_svc+0x24/0x38
+ el0_svc+0x30/0xf8
+ el0t_64_sync_handler+0x120/0x130
+ el0t_64_sync+0x190/0x198
+
+INFO: task sync:2769849 blocked for more than 120 seconds.
+ Tainted: G O 6.12.41-g3fe07ddf05ab #1
+"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+task:sync state:D stack:0 pid:2769849 tgid:2769849 ppid:736 flags:0x0000020c
+Call trace:
+ __switch_to+0xf4/0x158
+ __schedule+0x27c/0x908
+ schedule+0x3c/0x118
+ wb_wait_for_completion+0xb0/0xe8
+ sync_inodes_sb+0xc8/0x2b0
+ sync_inodes_one_sb+0x24/0x38
+ iterate_supers+0xa8/0x138
+ ksys_sync+0x54/0xc8
+ __arm64_sys_sync+0x18/0x30
+ invoke_syscall+0x50/0x120
+ el0_svc_common.constprop.0+0xc8/0xf0
+ do_el0_svc+0x24/0x38
+ el0_svc+0x30/0xf8
+ el0t_64_sync_handler+0x120/0x130
+ el0t_64_sync+0x190/0x198
+
+The root cause is a potential deadlock between the following tasks:
+
+kworker/u8:11 Thread A
+- f2fs_write_single_data_page
+ - f2fs_do_write_data_page
+ - folio_start_writeback(X)
+ - f2fs_outplace_write_data
+ - bio_add_folio(X)
+ - folio_unlock(X)
+ - truncate_inode_pages_range
+ - __filemap_get_folio(X, FGP_LOCK)
+ - truncate_inode_partial_folio(X)
+ - folio_wait_writeback(X)
+ - f2fs_balance_fs
+ - f2fs_gc
+ - do_garbage_collect
+ - move_data_page
+ - f2fs_get_lock_data_page
+ - __filemap_get_folio(X, FGP_LOCK)
+
+Both threads try to access folio X. Thread A holds the lock but waits
+for writeback, while kworker waits for the lock. This causes a deadlock.
+
+Other threads also enter D state, waiting for locks such as gc_lock and
+writepages.
+
+OPU/IPU DATA folio are all affected by this issue. To avoid such
+potential deadlocks, always commit these cached folios before
+triggering f2fs_gc() in f2fs_balance_fs().
+
+Suggested-by: Chao Yu <chao@kernel.org>
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Ruipeng Qi <ruipengqi3@gmail.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Stable-dep-of: 8b4468ec023d ("f2fs: fix potential deadlock in gc_merge path of f2fs_balance_fs()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/data.c | 29 +++++++++++++++++++++++++++++
+ fs/f2fs/f2fs.h | 1 +
+ fs/f2fs/segment.c | 8 ++++++++
+ 3 files changed, 38 insertions(+)
+
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -890,6 +890,35 @@ void f2fs_submit_merged_ipu_write(struct
+ }
+ }
+
++void f2fs_submit_all_merged_ipu_writes(struct f2fs_sb_info *sbi)
++{
++ struct bio_entry *be, *tmp;
++ struct f2fs_bio_info *io;
++ enum temp_type temp;
++
++ for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
++ LIST_HEAD(list);
++
++ io = sbi->write_io[DATA] + temp;
++
++ /* A lockless list_empty() check is safe here: any bios from
++ * other kworkers that we miss will be submitted by those
++ * kworkers accordingly.
++ */
++ if (list_empty(&io->bio_list))
++ continue;
++
++ f2fs_down_write(&io->bio_list_lock);
++ list_splice_init(&io->bio_list, &list);
++ f2fs_up_write(&io->bio_list_lock);
++
++ list_for_each_entry_safe(be, tmp, &list, list) {
++ f2fs_submit_write_bio(sbi, be->bio, DATA);
++ del_bio_entry(be);
++ }
++ }
++}
++
+ int f2fs_merge_page_bio(struct f2fs_io_info *fio)
+ {
+ struct bio *bio = *fio->bio;
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -3929,6 +3929,7 @@ void f2fs_submit_merged_write_cond(struc
+ nid_t ino, enum page_type type);
+ void f2fs_submit_merged_ipu_write(struct f2fs_sb_info *sbi,
+ struct bio **bio, struct page *page);
++void f2fs_submit_all_merged_ipu_writes(struct f2fs_sb_info *sbi);
+ void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi);
+ int f2fs_submit_page_bio(struct f2fs_io_info *fio);
+ int f2fs_merge_page_bio(struct f2fs_io_info *fio);
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -451,6 +451,14 @@ void f2fs_balance_fs(struct f2fs_sb_info
+ .should_migrate_blocks = false,
+ .err_gc_skipped = false,
+ .nr_free_secs = 1 };
++
++ /*
++ * Submit all cached OPU/IPU DATA bios before triggering
++ * foreground GC to avoid potential deadlocks.
++ */
++ f2fs_submit_merged_write(sbi, DATA);
++ f2fs_submit_all_merged_ipu_writes(sbi);
++
+ f2fs_down_write(&sbi->gc_lock);
+ stat_inc_gc_call_count(sbi, FOREGROUND);
+ f2fs_gc(sbi, &gc_control);
--- /dev/null
+From stable+bounces-271847-greg=kroah.com@vger.kernel.org Fri Jul 3 20:27:31 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 3 Jul 2026 14:24:13 -0400
+Subject: f2fs: fix potential deadlock in gc_merge path of f2fs_balance_fs()
+To: stable@vger.kernel.org
+Cc: Chao Yu <chao@kernel.org>, stable@kernel.org, Ruipeng Qi <ruipengqi3@gmail.com>, Chao Yu <chaseyu@google.com>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260703182413.254727-2-sashal@kernel.org>
+
+From: Chao Yu <chao@kernel.org>
+
+[ Upstream commit 8b4468ec023d0d1b4669dfb867588997cc03a06b ]
+
+When we mount device w/ gc_merge mount option, we may suffer below
+potential deadlock:
+
+Kworker GC trehad Truncator
+- f2fs_write_cache_pages
+ - f2fs_write_single_data_page
+ - f2fs_do_write_data_page
+ - folio_start_writeback --- set writeback flag on folio
+ - f2fs_outplace_write_data
+ : cached folio in internal bio cache
+ - f2fs_balance_fs
+ - wake_up(gc_thread)
+ : wake up gc thread to run foreground GC
+ - finish_wait(fggc_wq)
+ : wait on the waitqueue --- wait on GC thread to finish the work
+ - truncate_inode_pages_range
+ - __filemap_get_folio(, FGP_LOCK) --- lock folio
+ - truncate_inode_partial_folio
+ - folio_wait_writeback --- wait on writeback being cleared
+ - do_garbage_collect
+ - move_data_page
+ - f2fs_get_lock_data_folio
+ - lock on folio --- blocked on folio's lock
+
+In order to avoid such deadlock, let's call below functions to commit
+cached bios in GC_MERGE path of f2fs_balance_fs() as the same as we did
+in NOGC_MERGE path.
+- f2fs_submit_merged_write(sbi, DATA);
+- f2fs_submit_all_merged_ipu_writes(sbi);
+
+Cc: stable@kernel.org
+Fixes: 351df4b20115 ("f2fs: add segment operations")
+Cc: Ruipeng Qi <ruipengqi3@gmail.com>
+Reported: Sandeep Dhavale <dhavale@google.com>
+Signed-off-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Chao Yu <chaseyu@google.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/segment.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -434,6 +434,13 @@ void f2fs_balance_fs(struct f2fs_sb_info
+ if (has_enough_free_secs(sbi, 0, 0))
+ return;
+
++ /*
++ * Submit all cached OPU/IPU DATA bios before triggering
++ * foreground GC to avoid potential deadlocks.
++ */
++ f2fs_submit_merged_write(sbi, DATA);
++ f2fs_submit_all_merged_ipu_writes(sbi);
++
+ if (test_opt(sbi, GC_MERGE) && sbi->gc_thread &&
+ sbi->gc_thread->f2fs_gc_task) {
+ DEFINE_WAIT(wait);
+@@ -452,13 +459,6 @@ void f2fs_balance_fs(struct f2fs_sb_info
+ .err_gc_skipped = false,
+ .nr_free_secs = 1 };
+
+- /*
+- * Submit all cached OPU/IPU DATA bios before triggering
+- * foreground GC to avoid potential deadlocks.
+- */
+- f2fs_submit_merged_write(sbi, DATA);
+- f2fs_submit_all_merged_ipu_writes(sbi);
+-
+ f2fs_down_write(&sbi->gc_lock);
+ stat_inc_gc_call_count(sbi, FOREGROUND);
+ f2fs_gc(sbi, &gc_control);
--- /dev/null
+From stable+bounces-271761-greg=kroah.com@vger.kernel.org Fri Jul 3 14:42:14 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 3 Jul 2026 08:34:00 -0400
+Subject: f2fs: validate orphan inode entry count
+To: stable@vger.kernel.org
+Cc: Wenjie Qi <qwjhust@gmail.com>, stable@kernel.org, Wenjie Qi <qiwenjie@xiaomi.com>, Chao Yu <chao@kernel.org>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260703123400.3946185-1-sashal@kernel.org>
+
+From: Wenjie Qi <qwjhust@gmail.com>
+
+[ Upstream commit 846c499a65816d13f1186e3090e825e8bb8bcb8b ]
+
+f2fs_recover_orphan_inodes() trusts the orphan block entry_count when
+replaying orphan inodes from the checkpoint pack. A corrupted entry_count
+larger than F2FS_ORPHANS_PER_BLOCK makes the recovery loop read past the
+ino[] array and interpret footer or following data as inode numbers.
+
+On a crafted image, mounting an unpatched kernel can drive orphan recovery
+into f2fs_bug_on() and panic the kernel. Validate entry_count before
+consuming entries so corrupted checkpoint data fails the mount with
+-EFSCORRUPTED and requests fsck instead.
+
+Set ERROR_INCONSISTENT_ORPHAN as well, so the corruption reason can be
+recorded in the superblock s_errors[] field. This gives fsck a persistent
+hint even though mount-time orphan recovery failure may leave no chance to
+persist SBI_NEED_FSCK through a checkpoint.
+
+Cc: stable@kernel.org
+Fixes: 127e670abfa7 ("f2fs: add checkpoint operations")
+Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c | 14 +++++++++++++-
+ include/linux/f2fs_fs.h | 1 +
+ 2 files changed, 14 insertions(+), 1 deletion(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -759,6 +759,7 @@ int f2fs_recover_orphan_inodes(struct f2
+ for (i = 0; i < orphan_blocks; i++) {
+ struct page *page;
+ struct f2fs_orphan_block *orphan_blk;
++ unsigned int entry_count;
+
+ page = f2fs_get_meta_page(sbi, start_blk + i);
+ if (IS_ERR(page)) {
+@@ -767,7 +768,18 @@ int f2fs_recover_orphan_inodes(struct f2
+ }
+
+ orphan_blk = (struct f2fs_orphan_block *)page_address(page);
+- for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) {
++ entry_count = le32_to_cpu(orphan_blk->entry_count);
++ if (entry_count > F2FS_ORPHANS_PER_BLOCK) {
++ f2fs_err(sbi, "invalid orphan inode entry count %u",
++ entry_count);
++ set_sbi_flag(sbi, SBI_NEED_FSCK);
++ f2fs_handle_error(sbi, ERROR_INCONSISTENT_ORPHAN);
++ err = -EFSCORRUPTED;
++ f2fs_put_page(page, 1);
++ goto out;
++ }
++
++ for (j = 0; j < entry_count; j++) {
+ nid_t ino = le32_to_cpu(orphan_blk->ino[j]);
+
+ err = recover_orphan_inode(sbi, ino);
+--- a/include/linux/f2fs_fs.h
++++ b/include/linux/f2fs_fs.h
+@@ -104,6 +104,7 @@ enum f2fs_error {
+ ERROR_CORRUPTED_XATTR,
+ ERROR_INVALID_NODE_REFERENCE,
+ ERROR_INCONSISTENT_NAT,
++ ERROR_INCONSISTENT_ORPHAN,
+ ERROR_MAX,
+ };
+
--- /dev/null
+From stable+bounces-271995-greg=kroah.com@vger.kernel.org Sun Jul 5 05:11:47 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 4 Jul 2026 23:11:39 -0400
+Subject: fbdev: fbcon: fix out-of-bounds read in err_out of fbcon_do_set_font()
+To: stable@vger.kernel.org
+Cc: Mingyu Wang <25181214217@stu.xidian.edu.cn>, Thomas Zimmermann <tzimmermann@suse.de>, Helge Deller <deller@gmx.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260705031139.1600541-1-sashal@kernel.org>
+
+From: Mingyu Wang <25181214217@stu.xidian.edu.cn>
+
+[ Upstream commit 8fdc8c2057eea08d40ce2c8eed41ff9e451c65c2 ]
+
+When fbcon_do_set_font() fails (e.g., due to a memory allocation failure
+inside vc_resize() under heavy memory pressure), it jumps to the `err_out`
+label to roll back the console state. However, the current rollback logic
+forgets to restore the `hi_font` state, leading to a severe state machine
+corruption.
+
+Earlier in the function, `set_vc_hi_font()` might be called to change
+`vc->vc_hi_font_mask` and mutate the screen buffer. If `vc_resize()`
+subsequently fails, the `err_out` path restores `vc_font.charcount`
+but entirely skips rolling back the `vc_hi_font_mask` and the screen
+buffer.
+
+This mismatch leaves the terminal in a desynchronized state. Because
+`vc_hi_font_mask` remains set, the VT subsystem will still accept
+character indices greater than 255 from userspace and write them to the
+screen buffer. Subsequent rendering calls (e.g., `fbcon_putcs()`) will
+then use these inflated indices to access the reverted, 256-character
+font array, leading to a deterministic out-of-bounds read and potential
+kernel memory disclosure.
+
+Fix this by adding the missing rollback logic for the `hi_font` mask
+and screen buffer in the error path.
+
+Fixes: a5a923038d70 ("fbdev: fbcon: Properly revert changes when vc_resize() failed")
+Cc: stable@vger.kernel.org
+Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>
+Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
+Signed-off-by: Helge Deller <deller@gmx.de>
+[ Adjust context ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/video/fbdev/core/fbcon.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/video/fbdev/core/fbcon.c
++++ b/drivers/video/fbdev/core/fbcon.c
+@@ -2427,6 +2427,7 @@ static int fbcon_do_set_font(struct vc_d
+ struct fbcon_display *p = &fb_display[vc->vc_num];
+ int resize, ret, old_userfont, old_width, old_height, old_charcount;
+ u8 *old_data = vc->vc_font.data;
++ unsigned short old_hi_font_mask = vc->vc_hi_font_mask;
+
+ resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
+ vc->vc_font.data = (void *)(p->fontdata = data);
+@@ -2480,6 +2481,12 @@ err_out:
+ vc->vc_font.height = old_height;
+ vc->vc_font.charcount = old_charcount;
+
++ /* Restore the hi_font state and screen buffer */
++ if (old_hi_font_mask && !vc->vc_hi_font_mask)
++ set_vc_hi_font(vc, true);
++ else if (!old_hi_font_mask && vc->vc_hi_font_mask)
++ set_vc_hi_font(vc, false);
++
+ return ret;
+ }
+
--- /dev/null
+From stable+bounces-272218-greg=kroah.com@vger.kernel.org Mon Jul 6 15:03:44 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 6 Jul 2026 08:50:05 -0400
+Subject: locking/rtmutex: Make sure we wake anything on the wake_q when we release the lock->wait_lock
+To: stable@vger.kernel.org
+Cc: John Stultz <jstultz@google.com>, Bert Karwatzki <spasswolf@web.de>, "Peter Zijlstra (Intel)" <peterz@infradead.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260706125005.2225064-1-sashal@kernel.org>
+
+From: John Stultz <jstultz@google.com>
+
+[ Upstream commit 4a077914578183ec397ad09f7156a357e00e5d72 ]
+
+Bert reported seeing occasional boot hangs when running with
+PREEPT_RT and bisected it down to commit 894d1b3db41c
+("locking/mutex: Remove wakeups from under mutex::wait_lock").
+
+It looks like I missed a few spots where we drop the wait_lock and
+potentially call into schedule without waking up the tasks on the
+wake_q structure. Since the tasks being woken are ww_mutex tasks
+they need to be able to run to release the mutex and unblock the
+task that currently is planning to wake them. Thus we can deadlock.
+
+So make sure we wake the wake_q tasks when we unlock the wait_lock.
+
+Closes: https://lore.kernel.org/lkml/20241211182502.2915-1-spasswolf@web.de
+Fixes: 894d1b3db41c ("locking/mutex: Remove wakeups from under mutex::wait_lock")
+Reported-by: Bert Karwatzki <spasswolf@web.de>
+Signed-off-by: John Stultz <jstultz@google.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://lkml.kernel.org/r/20241212222138.2400498-1-jstultz@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/locking/rtmutex.c | 18 ++++++++++++++++--
+ kernel/locking/rtmutex_api.c | 2 +-
+ 2 files changed, 17 insertions(+), 3 deletions(-)
+
+--- a/kernel/locking/rtmutex.c
++++ b/kernel/locking/rtmutex.c
+@@ -1292,7 +1292,13 @@ static int __sched task_blocks_on_rt_mut
+ */
+ get_task_struct(owner);
+
++ preempt_disable();
+ raw_spin_unlock_irq(&lock->wait_lock);
++ /* wake up any tasks on the wake_q before calling rt_mutex_adjust_prio_chain */
++ wake_up_q(wake_q);
++ wake_q_init(wake_q);
++ preempt_enable();
++
+
+ res = rt_mutex_adjust_prio_chain(owner, chwalk, lock,
+ next_lock, waiter, task);
+@@ -1602,6 +1608,7 @@ static void __sched remove_waiter(struct
+ * or TASK_UNINTERRUPTIBLE)
+ * @timeout: the pre-initialized and started timer, or NULL for none
+ * @waiter: the pre-initialized rt_mutex_waiter
++ * @wake_q: wake_q of tasks to wake when we drop the lock->wait_lock
+ *
+ * Must be called with lock->wait_lock held and interrupts disabled
+ */
+@@ -1609,7 +1616,8 @@ static int __sched rt_mutex_slowlock_blo
+ struct ww_acquire_ctx *ww_ctx,
+ unsigned int state,
+ struct hrtimer_sleeper *timeout,
+- struct rt_mutex_waiter *waiter)
++ struct rt_mutex_waiter *waiter,
++ struct wake_q_head *wake_q)
+ {
+ struct rt_mutex *rtm = container_of(lock, struct rt_mutex, rtmutex);
+ struct task_struct *owner;
+@@ -1639,7 +1647,13 @@ static int __sched rt_mutex_slowlock_blo
+ owner = rt_mutex_owner(lock);
+ else
+ owner = NULL;
++ preempt_disable();
+ raw_spin_unlock_irq(&lock->wait_lock);
++ if (wake_q) {
++ wake_up_q(wake_q);
++ wake_q_init(wake_q);
++ }
++ preempt_enable();
+
+ if (!owner || !rtmutex_spin_on_owner(lock, waiter, owner))
+ rt_mutex_schedule();
+@@ -1713,7 +1727,7 @@ static int __sched __rt_mutex_slowlock(s
+
+ ret = task_blocks_on_rt_mutex(lock, waiter, current, ww_ctx, chwalk, wake_q);
+ if (likely(!ret))
+- ret = rt_mutex_slowlock_block(lock, ww_ctx, state, NULL, waiter);
++ ret = rt_mutex_slowlock_block(lock, ww_ctx, state, NULL, waiter, wake_q);
+
+ if (likely(!ret)) {
+ /* acquired the lock */
+--- a/kernel/locking/rtmutex_api.c
++++ b/kernel/locking/rtmutex_api.c
+@@ -383,7 +383,7 @@ int __sched rt_mutex_wait_proxy_lock(str
+ raw_spin_lock_irq(&lock->wait_lock);
+ /* sleep on the mutex */
+ set_current_state(TASK_INTERRUPTIBLE);
+- ret = rt_mutex_slowlock_block(lock, NULL, TASK_INTERRUPTIBLE, to, waiter);
++ ret = rt_mutex_slowlock_block(lock, NULL, TASK_INTERRUPTIBLE, to, waiter, NULL);
+ /*
+ * try_to_take_rt_mutex() sets the waiter bit unconditionally. We might
+ * have to fix that up.
--- /dev/null
+From stable+bounces-271997-greg=kroah.com@vger.kernel.org Sun Jul 5 05:11:59 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 4 Jul 2026 23:11:47 -0400
+Subject: nfs_common: rename functions that invalidate LOCALIO nfs_clients
+To: stable@vger.kernel.org
+Cc: Mike Snitzer <snitzer@kernel.org>, NeilBrown <neilb@suse.de>, Jeff Layton <jlayton@kernel.org>, Anna Schumaker <anna.schumaker@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260705031150.1600970-2-sashal@kernel.org>
+
+From: Mike Snitzer <snitzer@kernel.org>
+
+[ Upstream commit b49f049a22227df701bfbca083d6cc859496e615 ]
+
+Rename nfs_uuid_invalidate_one_client to nfs_localio_disable_client.
+Rename nfs_uuid_invalidate_clients to nfs_localio_invalidate_clients.
+
+Signed-off-by: Mike Snitzer <snitzer@kernel.org>
+Reviewed-by: NeilBrown <neilb@suse.de>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
+Stable-dep-of: 2c6bb3c40bc2 ("NFSv4/flexfiles: reject zero filehandle version count")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/localio.c | 2 +-
+ fs/nfs_common/nfslocalio.c | 8 ++++----
+ fs/nfsd/nfsctl.c | 4 ++--
+ include/linux/nfslocalio.h | 5 +++--
+ 4 files changed, 10 insertions(+), 9 deletions(-)
+
+--- a/fs/nfs/localio.c
++++ b/fs/nfs/localio.c
+@@ -141,7 +141,7 @@ void nfs_local_disable(struct nfs_client
+ spin_lock(&clp->cl_localio_lock);
+ if (test_and_clear_bit(NFS_CS_LOCAL_IO, &clp->cl_flags)) {
+ trace_nfs_local_disable(clp);
+- nfs_uuid_invalidate_one_client(&clp->cl_uuid);
++ nfs_localio_disable_client(&clp->cl_uuid);
+ }
+ spin_unlock(&clp->cl_localio_lock);
+ }
+--- a/fs/nfs_common/nfslocalio.c
++++ b/fs/nfs_common/nfslocalio.c
+@@ -107,7 +107,7 @@ static void nfs_uuid_put_locked(nfs_uuid
+ list_del_init(&nfs_uuid->list);
+ }
+
+-void nfs_uuid_invalidate_clients(struct list_head *list)
++void nfs_localio_invalidate_clients(struct list_head *list)
+ {
+ nfs_uuid_t *nfs_uuid, *tmp;
+
+@@ -116,9 +116,9 @@ void nfs_uuid_invalidate_clients(struct
+ nfs_uuid_put_locked(nfs_uuid);
+ spin_unlock(&nfs_uuid_lock);
+ }
+-EXPORT_SYMBOL_GPL(nfs_uuid_invalidate_clients);
++EXPORT_SYMBOL_GPL(nfs_localio_invalidate_clients);
+
+-void nfs_uuid_invalidate_one_client(nfs_uuid_t *nfs_uuid)
++void nfs_localio_disable_client(nfs_uuid_t *nfs_uuid)
+ {
+ if (nfs_uuid->net) {
+ spin_lock(&nfs_uuid_lock);
+@@ -126,7 +126,7 @@ void nfs_uuid_invalidate_one_client(nfs_
+ spin_unlock(&nfs_uuid_lock);
+ }
+ }
+-EXPORT_SYMBOL_GPL(nfs_uuid_invalidate_one_client);
++EXPORT_SYMBOL_GPL(nfs_localio_disable_client);
+
+ /*
+ * Caller is responsible for calling nfsd_net_put and
+--- a/fs/nfsd/nfsctl.c
++++ b/fs/nfsd/nfsctl.c
+@@ -2296,14 +2296,14 @@ out_export_error:
+ * nfsd_net_pre_exit - Disconnect localio clients from net namespace
+ * @net: a network namespace that is about to be destroyed
+ *
+- * This invalidated ->net pointers held by localio clients
++ * This invalidates ->net pointers held by localio clients
+ * while they can still safely access nn->counter.
+ */
+ static __net_exit void nfsd_net_pre_exit(struct net *net)
+ {
+ struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+- nfs_uuid_invalidate_clients(&nn->local_clients);
++ nfs_localio_invalidate_clients(&nn->local_clients);
+ }
+ #endif
+
+--- a/include/linux/nfslocalio.h
++++ b/include/linux/nfslocalio.h
+@@ -37,8 +37,9 @@ bool nfs_uuid_begin(nfs_uuid_t *);
+ void nfs_uuid_end(nfs_uuid_t *);
+ void nfs_uuid_is_local(const uuid_t *, struct list_head *,
+ struct net *, struct auth_domain *, struct module *);
+-void nfs_uuid_invalidate_clients(struct list_head *list);
+-void nfs_uuid_invalidate_one_client(nfs_uuid_t *nfs_uuid);
++
++void nfs_localio_disable_client(nfs_uuid_t *nfs_uuid);
++void nfs_localio_invalidate_clients(struct list_head *list);
+
+ /* localio needs to map filehandle -> struct nfsd_file */
+ extern struct nfsd_file *
--- /dev/null
+From stable+bounces-271996-greg=kroah.com@vger.kernel.org Sun Jul 5 05:11:57 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 4 Jul 2026 23:11:46 -0400
+Subject: nfsd: add nfsd_file_{get,put} to 'nfs_to' nfsd_localio_operations
+To: stable@vger.kernel.org
+Cc: Mike Snitzer <snitzer@kernel.org>, Jeff Layton <jlayton@kernel.org>, Chuck Lever <chuck.lever@oracle.com>, Anna Schumaker <anna.schumaker@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260705031150.1600970-1-sashal@kernel.org>
+
+From: Mike Snitzer <snitzer@kernel.org>
+
+[ Upstream commit a61466315d7afca032342183a57e62d5e3a3157c ]
+
+In later a commit LOCALIO must call both nfsd_file_get and
+nfsd_file_put to manage extra nfsd_file references.
+
+Signed-off-by: Mike Snitzer <snitzer@kernel.org>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Acked-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
+Stable-dep-of: 2c6bb3c40bc2 ("NFSv4/flexfiles: reject zero filehandle version count")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/localio.c | 2 ++
+ include/linux/nfslocalio.h | 2 ++
+ 2 files changed, 4 insertions(+)
+
+--- a/fs/nfsd/localio.c
++++ b/fs/nfsd/localio.c
+@@ -29,6 +29,8 @@ static const struct nfsd_localio_operati
+ .nfsd_net_put = nfsd_net_put,
+ .nfsd_open_local_fh = nfsd_open_local_fh,
+ .nfsd_file_put_local = nfsd_file_put_local,
++ .nfsd_file_get = nfsd_file_get,
++ .nfsd_file_put = nfsd_file_put,
+ .nfsd_file_file = nfsd_file_file,
+ };
+
+--- a/include/linux/nfslocalio.h
++++ b/include/linux/nfslocalio.h
+@@ -56,6 +56,8 @@ struct nfsd_localio_operations {
+ const struct nfs_fh *,
+ const fmode_t);
+ struct net *(*nfsd_file_put_local)(struct nfsd_file *);
++ struct nfsd_file *(*nfsd_file_get)(struct nfsd_file *);
++ void (*nfsd_file_put)(struct nfsd_file *);
+ struct file *(*nfsd_file_file)(struct nfsd_file *);
+ } ____cacheline_aligned;
+
--- /dev/null
+From stable+bounces-271999-greg=kroah.com@vger.kernel.org Sun Jul 5 05:12:08 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 4 Jul 2026 23:11:49 -0400
+Subject: NFSv4/flexfiles: Add data structure support for striped layouts
+To: stable@vger.kernel.org
+Cc: Jonathan Curley <jcurley@purestorage.com>, Anna Schumaker <anna.schumaker@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260705031150.1600970-4-sashal@kernel.org>
+
+From: Jonathan Curley <jcurley@purestorage.com>
+
+[ Upstream commit d442670c0f63c46b7f348f68fb2002af597708f2 ]
+
+Adds a new struct nfs4_ff_layout_ds_stripe that represents a data
+server stripe within a layout. A new dynamically allocated array of
+this type has been added to nfs4_ff_layout_mirror and per stripe
+configuration information has been moved from the mirror type to the
+stripe based on the RFC.
+
+Signed-off-by: Jonathan Curley <jcurley@purestorage.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
+Stable-dep-of: 2c6bb3c40bc2 ("NFSv4/flexfiles: reject zero filehandle version count")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/flexfilelayout/flexfilelayout.c | 149 ++++++++++++++++--------------
+ fs/nfs/flexfilelayout/flexfilelayout.h | 27 +++--
+ fs/nfs/flexfilelayout/flexfilelayoutdev.c | 54 +++++-----
+ 3 files changed, 128 insertions(+), 102 deletions(-)
+
+--- a/fs/nfs/flexfilelayout/flexfilelayout.c
++++ b/fs/nfs/flexfilelayout/flexfilelayout.c
+@@ -183,13 +183,13 @@ static bool ff_mirror_match_fh(const str
+ {
+ int i, j;
+
+- if (m1->fh_versions_cnt != m2->fh_versions_cnt)
++ if (m1->dss[0].fh_versions_cnt != m2->dss[0].fh_versions_cnt)
+ return false;
+- for (i = 0; i < m1->fh_versions_cnt; i++) {
++ for (i = 0; i < m1->dss[0].fh_versions_cnt; i++) {
+ bool found_fh = false;
+- for (j = 0; j < m2->fh_versions_cnt; j++) {
+- if (nfs_compare_fh(&m1->fh_versions[i],
+- &m2->fh_versions[j]) == 0) {
++ for (j = 0; j < m2->dss[0].fh_versions_cnt; j++) {
++ if (nfs_compare_fh(&m1->dss[0].fh_versions[i],
++ &m2->dss[0].fh_versions[j]) == 0) {
+ found_fh = true;
+ break;
+ }
+@@ -210,7 +210,8 @@ ff_layout_add_mirror(struct pnfs_layout_
+
+ spin_lock(&inode->i_lock);
+ list_for_each_entry(pos, &ff_layout->mirrors, mirrors) {
+- if (memcmp(&mirror->devid, &pos->devid, sizeof(pos->devid)) != 0)
++ if (memcmp(&mirror->dss[0].devid, &pos->dss[0].devid,
++ sizeof(pos->dss[0].devid)) != 0)
+ continue;
+ if (!ff_mirror_match_fh(mirror, pos))
+ continue;
+@@ -238,30 +239,46 @@ ff_layout_remove_mirror(struct nfs4_ff_l
+ mirror->layout = NULL;
+ }
+
+-static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(gfp_t gfp_flags)
++static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(u32 dss_count,
++ gfp_t gfp_flags)
+ {
+ struct nfs4_ff_layout_mirror *mirror;
+
+ mirror = kzalloc(sizeof(*mirror), gfp_flags);
+- if (mirror != NULL) {
+- spin_lock_init(&mirror->lock);
+- refcount_set(&mirror->ref, 1);
+- INIT_LIST_HEAD(&mirror->mirrors);
++ if (mirror == NULL)
++ return NULL;
++
++ spin_lock_init(&mirror->lock);
++ refcount_set(&mirror->ref, 1);
++ INIT_LIST_HEAD(&mirror->mirrors);
++
++ mirror->dss_count = dss_count;
++ mirror->dss =
++ kcalloc(dss_count, sizeof(struct nfs4_ff_layout_ds_stripe),
++ gfp_flags);
++ if (mirror->dss == NULL) {
++ kfree(mirror);
++ return NULL;
+ }
++
+ return mirror;
+ }
+
+ static void ff_layout_free_mirror(struct nfs4_ff_layout_mirror *mirror)
+ {
+- const struct cred *cred;
++ const struct cred *cred;
++ int dss_id = 0;
+
+ ff_layout_remove_mirror(mirror);
+- kfree(mirror->fh_versions);
+- cred = rcu_access_pointer(mirror->ro_cred);
++
++ kfree(mirror->dss[dss_id].fh_versions);
++ cred = rcu_access_pointer(mirror->dss[dss_id].ro_cred);
+ put_cred(cred);
+- cred = rcu_access_pointer(mirror->rw_cred);
++ cred = rcu_access_pointer(mirror->dss[dss_id].rw_cred);
+ put_cred(cred);
+- nfs4_ff_layout_put_deviceid(mirror->mirror_ds);
++ nfs4_ff_layout_put_deviceid(mirror->dss[dss_id].mirror_ds);
++
++ kfree(mirror->dss);
+ kfree(mirror);
+ }
+
+@@ -371,8 +388,8 @@ static void ff_layout_sort_mirrors(struc
+
+ for (i = 0; i < fls->mirror_array_cnt - 1; i++) {
+ for (j = i + 1; j < fls->mirror_array_cnt; j++)
+- if (fls->mirror_array[i]->efficiency <
+- fls->mirror_array[j]->efficiency)
++ if (fls->mirror_array[i]->dss[0].efficiency <
++ fls->mirror_array[j]->dss[0].efficiency)
+ swap(fls->mirror_array[i],
+ fls->mirror_array[j]);
+ }
+@@ -426,35 +443,35 @@ ff_layout_alloc_lseg(struct pnfs_layout_
+ fls->mirror_array_cnt = mirror_array_cnt;
+ fls->stripe_unit = stripe_unit;
+
++ u32 dss_count = 0;
+ for (i = 0; i < fls->mirror_array_cnt; i++) {
+ struct nfs4_ff_layout_mirror *mirror;
+ struct cred *kcred;
+ const struct cred __rcu *cred;
+ kuid_t uid;
+ kgid_t gid;
+- u32 ds_count, fh_count, id;
+- int j;
++ u32 fh_count, id;
++ int j, dss_id = 0;
+
+ rc = -EIO;
+ p = xdr_inline_decode(&stream, 4);
+ if (!p)
+ goto out_err_free;
+- ds_count = be32_to_cpup(p);
++
++ dss_count = be32_to_cpup(p);
+
+ /* FIXME: allow for striping? */
+- if (ds_count != 1)
++ if (dss_count != 1)
+ goto out_err_free;
+
+- fls->mirror_array[i] = ff_layout_alloc_mirror(gfp_flags);
++ fls->mirror_array[i] = ff_layout_alloc_mirror(dss_count, gfp_flags);
+ if (fls->mirror_array[i] == NULL) {
+ rc = -ENOMEM;
+ goto out_err_free;
+ }
+
+- fls->mirror_array[i]->ds_count = ds_count;
+-
+ /* deviceid */
+- rc = decode_deviceid(&stream, &fls->mirror_array[i]->devid);
++ rc = decode_deviceid(&stream, &fls->mirror_array[i]->dss[dss_id].devid);
+ if (rc)
+ goto out_err_free;
+
+@@ -463,10 +480,10 @@ ff_layout_alloc_lseg(struct pnfs_layout_
+ p = xdr_inline_decode(&stream, 4);
+ if (!p)
+ goto out_err_free;
+- fls->mirror_array[i]->efficiency = be32_to_cpup(p);
++ fls->mirror_array[i]->dss[dss_id].efficiency = be32_to_cpup(p);
+
+ /* stateid */
+- rc = decode_pnfs_stateid(&stream, &fls->mirror_array[i]->stateid);
++ rc = decode_pnfs_stateid(&stream, &fls->mirror_array[i]->dss[dss_id].stateid);
+ if (rc)
+ goto out_err_free;
+
+@@ -477,22 +494,22 @@ ff_layout_alloc_lseg(struct pnfs_layout_
+ goto out_err_free;
+ fh_count = be32_to_cpup(p);
+
+- fls->mirror_array[i]->fh_versions =
+- kcalloc(fh_count, sizeof(struct nfs_fh),
+- gfp_flags);
+- if (fls->mirror_array[i]->fh_versions == NULL) {
++ fls->mirror_array[i]->dss[dss_id].fh_versions =
++ kcalloc(fh_count, sizeof(struct nfs_fh),
++ gfp_flags);
++ if (fls->mirror_array[i]->dss[dss_id].fh_versions == NULL) {
+ rc = -ENOMEM;
+ goto out_err_free;
+ }
+
+ for (j = 0; j < fh_count; j++) {
+ rc = decode_nfs_fh(&stream,
+- &fls->mirror_array[i]->fh_versions[j]);
++ &fls->mirror_array[i]->dss[dss_id].fh_versions[j]);
+ if (rc)
+ goto out_err_free;
+ }
+
+- fls->mirror_array[i]->fh_versions_cnt = fh_count;
++ fls->mirror_array[i]->dss[dss_id].fh_versions_cnt = fh_count;
+
+ /* user */
+ rc = decode_name(&stream, &id);
+@@ -523,19 +540,21 @@ ff_layout_alloc_lseg(struct pnfs_layout_
+ cred = RCU_INITIALIZER(kcred);
+
+ if (lgr->range.iomode == IOMODE_READ)
+- rcu_assign_pointer(fls->mirror_array[i]->ro_cred, cred);
++ rcu_assign_pointer(fls->mirror_array[i]->dss[dss_id].ro_cred, cred);
+ else
+- rcu_assign_pointer(fls->mirror_array[i]->rw_cred, cred);
++ rcu_assign_pointer(fls->mirror_array[i]->dss[dss_id].rw_cred, cred);
+
+ mirror = ff_layout_add_mirror(lh, fls->mirror_array[i]);
+ if (mirror != fls->mirror_array[i]) {
+ /* swap cred ptrs so free_mirror will clean up old */
+ if (lgr->range.iomode == IOMODE_READ) {
+- cred = xchg(&mirror->ro_cred, fls->mirror_array[i]->ro_cred);
+- rcu_assign_pointer(fls->mirror_array[i]->ro_cred, cred);
++ cred = xchg(&mirror->dss[dss_id].ro_cred,
++ fls->mirror_array[i]->dss[dss_id].ro_cred);
++ rcu_assign_pointer(fls->mirror_array[i]->dss[dss_id].ro_cred, cred);
+ } else {
+- cred = xchg(&mirror->rw_cred, fls->mirror_array[i]->rw_cred);
+- rcu_assign_pointer(fls->mirror_array[i]->rw_cred, cred);
++ cred = xchg(&mirror->dss[dss_id].rw_cred,
++ fls->mirror_array[i]->dss[dss_id].rw_cred);
++ rcu_assign_pointer(fls->mirror_array[i]->dss[dss_id].rw_cred, cred);
+ }
+ ff_layout_free_mirror(fls->mirror_array[i]);
+ fls->mirror_array[i] = mirror;
+@@ -623,8 +642,8 @@ nfs4_ff_layoutstat_start_io(struct nfs4_
+ struct nfs4_flexfile_layout *ffl = FF_LAYOUT_FROM_HDR(mirror->layout);
+
+ nfs4_ff_start_busy_timer(&layoutstat->busy_timer, now);
+- if (!mirror->start_time)
+- mirror->start_time = now;
++ if (!mirror->dss[0].start_time)
++ mirror->dss[0].start_time = now;
+ if (mirror->report_interval != 0)
+ report_interval = (s64)mirror->report_interval * 1000LL;
+ else if (layoutstats_timer != 0)
+@@ -679,8 +698,8 @@ nfs4_ff_layout_stat_io_start_read(struct
+ bool report;
+
+ spin_lock(&mirror->lock);
+- report = nfs4_ff_layoutstat_start_io(mirror, &mirror->read_stat, now);
+- nfs4_ff_layout_stat_io_update_requested(&mirror->read_stat, requested);
++ report = nfs4_ff_layoutstat_start_io(mirror, &mirror->dss[0].read_stat, now);
++ nfs4_ff_layout_stat_io_update_requested(&mirror->dss[0].read_stat, requested);
+ set_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags);
+ spin_unlock(&mirror->lock);
+
+@@ -695,7 +714,7 @@ nfs4_ff_layout_stat_io_end_read(struct r
+ __u64 completed)
+ {
+ spin_lock(&mirror->lock);
+- nfs4_ff_layout_stat_io_update_completed(&mirror->read_stat,
++ nfs4_ff_layout_stat_io_update_completed(&mirror->dss[0].read_stat,
+ requested, completed,
+ ktime_get(), task->tk_start);
+ set_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags);
+@@ -710,8 +729,8 @@ nfs4_ff_layout_stat_io_start_write(struc
+ bool report;
+
+ spin_lock(&mirror->lock);
+- report = nfs4_ff_layoutstat_start_io(mirror , &mirror->write_stat, now);
+- nfs4_ff_layout_stat_io_update_requested(&mirror->write_stat, requested);
++ report = nfs4_ff_layoutstat_start_io(mirror, &mirror->dss[0].write_stat, now);
++ nfs4_ff_layout_stat_io_update_requested(&mirror->dss[0].write_stat, requested);
+ set_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags);
+ spin_unlock(&mirror->lock);
+
+@@ -730,7 +749,7 @@ nfs4_ff_layout_stat_io_end_write(struct
+ requested = completed = 0;
+
+ spin_lock(&mirror->lock);
+- nfs4_ff_layout_stat_io_update_completed(&mirror->write_stat,
++ nfs4_ff_layout_stat_io_update_completed(&mirror->dss[0].write_stat,
+ requested, completed, ktime_get(), task->tk_start);
+ set_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags);
+ spin_unlock(&mirror->lock);
+@@ -772,7 +791,7 @@ ff_layout_choose_ds_for_read(struct pnfs
+ continue;
+
+ if (check_device &&
+- nfs4_test_deviceid_unavailable(&mirror->mirror_ds->id_node)) {
++ nfs4_test_deviceid_unavailable(&mirror->dss[0].mirror_ds->id_node)) {
+ // reinitialize the error state in case if this is the last iteration
+ ds = ERR_PTR(-EINVAL);
+ continue;
+@@ -881,7 +900,7 @@ retry:
+
+ mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx);
+ pgm = &pgio->pg_mirrors[0];
+- pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize;
++ pgm->pg_bsize = mirror->dss[0].mirror_ds->ds_versions[0].rsize;
+
+ pgio->pg_mirror_idx = ds_idx;
+ return;
+@@ -953,7 +972,7 @@ retry:
+ goto retry;
+ }
+ pgm = &pgio->pg_mirrors[i];
+- pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].wsize;
++ pgm->pg_bsize = mirror->dss[0].mirror_ds->ds_versions[0].wsize;
+ }
+
+ if (NFS_SERVER(pgio->pg_inode)->flags &
+@@ -2013,7 +2032,7 @@ select_ds_fh_from_commit(struct pnfs_lay
+ /* FIXME: Assume that there is only one NFS version available
+ * for the DS.
+ */
+- return &flseg->mirror_array[i]->fh_versions[0];
++ return &flseg->mirror_array[i]->dss[0].fh_versions[0];
+ }
+
+ static int ff_layout_initiate_commit(struct nfs_commit_data *data, int how)
+@@ -2129,10 +2148,10 @@ static void ff_layout_cancel_io(struct p
+
+ for (idx = 0; idx < flseg->mirror_array_cnt; idx++) {
+ mirror = flseg->mirror_array[idx];
+- mirror_ds = mirror->mirror_ds;
++ mirror_ds = mirror->dss[0].mirror_ds;
+ if (IS_ERR_OR_NULL(mirror_ds))
+ continue;
+- ds = mirror->mirror_ds->ds;
++ ds = mirror->dss[0].mirror_ds->ds;
+ if (!ds)
+ continue;
+ ds_clp = ds->ds_clp;
+@@ -2533,8 +2552,8 @@ ff_layout_encode_ff_layoutupdate(struct
+ struct nfs4_ff_layout_mirror *mirror)
+ {
+ struct nfs4_pnfs_ds_addr *da;
+- struct nfs4_pnfs_ds *ds = mirror->mirror_ds->ds;
+- struct nfs_fh *fh = &mirror->fh_versions[0];
++ struct nfs4_pnfs_ds *ds = mirror->dss[0].mirror_ds->ds;
++ struct nfs_fh *fh = &mirror->dss[0].fh_versions[0];
+ __be32 *p;
+
+ da = list_first_entry(&ds->ds_addrs, struct nfs4_pnfs_ds_addr, da_node);
+@@ -2547,12 +2566,12 @@ ff_layout_encode_ff_layoutupdate(struct
+ xdr_encode_opaque(p, fh->data, fh->size);
+ /* ff_io_latency4 read */
+ spin_lock(&mirror->lock);
+- ff_layout_encode_io_latency(xdr, &mirror->read_stat.io_stat);
++ ff_layout_encode_io_latency(xdr, &mirror->dss[0].read_stat.io_stat);
+ /* ff_io_latency4 write */
+- ff_layout_encode_io_latency(xdr, &mirror->write_stat.io_stat);
++ ff_layout_encode_io_latency(xdr, &mirror->dss[0].write_stat.io_stat);
+ spin_unlock(&mirror->lock);
+ /* nfstime4 */
+- ff_layout_encode_nfstime(xdr, ktime_sub(ktime_get(), mirror->start_time));
++ ff_layout_encode_nfstime(xdr, ktime_sub(ktime_get(), mirror->dss[0].start_time));
+ /* bool */
+ p = xdr_reserve_space(xdr, 4);
+ *p = cpu_to_be32(false);
+@@ -2599,7 +2618,7 @@ ff_layout_mirror_prepare_stats(struct pn
+ list_for_each_entry(mirror, &ff_layout->mirrors, mirrors) {
+ if (i >= dev_limit)
+ break;
+- if (IS_ERR_OR_NULL(mirror->mirror_ds))
++ if (IS_ERR_OR_NULL(mirror->dss[0].mirror_ds))
+ continue;
+ if (!test_and_clear_bit(NFS4_FF_MIRROR_STAT_AVAIL,
+ &mirror->flags) &&
+@@ -2608,15 +2627,15 @@ ff_layout_mirror_prepare_stats(struct pn
+ /* mirror refcount put in cleanup_layoutstats */
+ if (!refcount_inc_not_zero(&mirror->ref))
+ continue;
+- dev = &mirror->mirror_ds->id_node;
++ dev = &mirror->dss[0].mirror_ds->id_node;
+ memcpy(&devinfo->dev_id, &dev->deviceid, NFS4_DEVICEID4_SIZE);
+ devinfo->offset = 0;
+ devinfo->length = NFS4_MAX_UINT64;
+ spin_lock(&mirror->lock);
+- devinfo->read_count = mirror->read_stat.io_stat.ops_completed;
+- devinfo->read_bytes = mirror->read_stat.io_stat.bytes_completed;
+- devinfo->write_count = mirror->write_stat.io_stat.ops_completed;
+- devinfo->write_bytes = mirror->write_stat.io_stat.bytes_completed;
++ devinfo->read_count = mirror->dss[0].read_stat.io_stat.ops_completed;
++ devinfo->read_bytes = mirror->dss[0].read_stat.io_stat.bytes_completed;
++ devinfo->write_count = mirror->dss[0].write_stat.io_stat.ops_completed;
++ devinfo->write_bytes = mirror->dss[0].write_stat.io_stat.bytes_completed;
+ spin_unlock(&mirror->lock);
+ devinfo->layout_type = LAYOUT_FLEX_FILES;
+ devinfo->ld_private.ops = &layoutstat_ops;
+--- a/fs/nfs/flexfilelayout/flexfilelayout.h
++++ b/fs/nfs/flexfilelayout/flexfilelayout.h
+@@ -71,24 +71,31 @@ struct nfs4_ff_layoutstat {
+ struct nfs4_ff_busy_timer busy_timer;
+ };
+
+-struct nfs4_ff_layout_mirror {
+- struct pnfs_layout_hdr *layout;
+- struct list_head mirrors;
+- u32 ds_count;
+- u32 efficiency;
++struct nfs4_ff_layout_mirror;
++
++struct nfs4_ff_layout_ds_stripe {
++ struct nfs4_ff_layout_mirror *mirror;
+ struct nfs4_deviceid devid;
++ u32 efficiency;
+ struct nfs4_ff_layout_ds *mirror_ds;
+ u32 fh_versions_cnt;
+ struct nfs_fh *fh_versions;
+ nfs4_stateid stateid;
+ const struct cred __rcu *ro_cred;
+ const struct cred __rcu *rw_cred;
+- refcount_t ref;
+- spinlock_t lock;
+- unsigned long flags;
+ struct nfs4_ff_layoutstat read_stat;
+ struct nfs4_ff_layoutstat write_stat;
+ ktime_t start_time;
++};
++
++struct nfs4_ff_layout_mirror {
++ struct pnfs_layout_hdr *layout;
++ struct list_head mirrors;
++ u32 dss_count;
++ struct nfs4_ff_layout_ds_stripe *dss;
++ refcount_t ref;
++ spinlock_t lock;
++ unsigned long flags;
+ u32 report_interval;
+ };
+
+@@ -154,7 +161,7 @@ FF_LAYOUT_DEVID_NODE(struct pnfs_layout_
+ struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, idx);
+
+ if (mirror != NULL) {
+- struct nfs4_ff_layout_ds *mirror_ds = mirror->mirror_ds;
++ struct nfs4_ff_layout_ds *mirror_ds = mirror->dss[0].mirror_ds;
+
+ if (!IS_ERR_OR_NULL(mirror_ds))
+ return &mirror_ds->id_node;
+@@ -183,7 +190,7 @@ ff_layout_no_read_on_rw(struct pnfs_layo
+ static inline int
+ nfs4_ff_layout_ds_version(const struct nfs4_ff_layout_mirror *mirror)
+ {
+- return mirror->mirror_ds->ds_versions[0].version;
++ return mirror->dss[0].mirror_ds->ds_versions[0].version;
+ }
+
+ struct nfs4_ff_layout_ds *
+--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c
++++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
+@@ -259,7 +259,7 @@ int ff_layout_track_ds_error(struct nfs4
+ if (status == 0)
+ return 0;
+
+- if (IS_ERR_OR_NULL(mirror->mirror_ds))
++ if (IS_ERR_OR_NULL(mirror->dss[0].mirror_ds))
+ return -EINVAL;
+
+ dserr = kmalloc(sizeof(*dserr), gfp_flags);
+@@ -271,8 +271,8 @@ int ff_layout_track_ds_error(struct nfs4
+ dserr->length = length;
+ dserr->status = status;
+ dserr->opnum = opnum;
+- nfs4_stateid_copy(&dserr->stateid, &mirror->stateid);
+- memcpy(&dserr->deviceid, &mirror->mirror_ds->id_node.deviceid,
++ nfs4_stateid_copy(&dserr->stateid, &mirror->dss[0].stateid);
++ memcpy(&dserr->deviceid, &mirror->dss[0].mirror_ds->id_node.deviceid,
+ NFS4_DEVICEID4_SIZE);
+
+ spin_lock(&flo->generic_hdr.plh_inode->i_lock);
+@@ -287,9 +287,9 @@ ff_layout_get_mirror_cred(struct nfs4_ff
+ const struct cred *cred, __rcu **pcred;
+
+ if (iomode == IOMODE_READ)
+- pcred = &mirror->ro_cred;
++ pcred = &mirror->dss[0].ro_cred;
+ else
+- pcred = &mirror->rw_cred;
++ pcred = &mirror->dss[0].rw_cred;
+
+ rcu_read_lock();
+ do {
+@@ -307,7 +307,7 @@ struct nfs_fh *
+ nfs4_ff_layout_select_ds_fh(struct nfs4_ff_layout_mirror *mirror)
+ {
+ /* FIXME: For now assume there is only 1 version available for the DS */
+- return &mirror->fh_versions[0];
++ return &mirror->dss[0].fh_versions[0];
+ }
+
+ void
+@@ -315,7 +315,7 @@ nfs4_ff_layout_select_ds_stateid(const s
+ nfs4_stateid *stateid)
+ {
+ if (nfs4_ff_layout_ds_version(mirror) == 4)
+- nfs4_stateid_copy(stateid, &mirror->stateid);
++ nfs4_stateid_copy(stateid, &mirror->dss[0].stateid);
+ }
+
+ static bool
+@@ -324,23 +324,23 @@ ff_layout_init_mirror_ds(struct pnfs_lay
+ {
+ if (mirror == NULL)
+ goto outerr;
+- if (mirror->mirror_ds == NULL) {
++ if (mirror->dss[0].mirror_ds == NULL) {
+ struct nfs4_deviceid_node *node;
+ struct nfs4_ff_layout_ds *mirror_ds = ERR_PTR(-ENODEV);
+
+ node = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode),
+- &mirror->devid, lo->plh_lc_cred,
++ &mirror->dss[0].devid, lo->plh_lc_cred,
+ GFP_KERNEL);
+ if (node)
+ mirror_ds = FF_LAYOUT_MIRROR_DS(node);
+
+ /* check for race with another call to this function */
+- if (cmpxchg(&mirror->mirror_ds, NULL, mirror_ds) &&
++ if (cmpxchg(&mirror->dss[0].mirror_ds, NULL, mirror_ds) &&
+ mirror_ds != ERR_PTR(-ENODEV))
+ nfs4_put_deviceid_node(node);
+ }
+
+- if (IS_ERR(mirror->mirror_ds))
++ if (IS_ERR(mirror->dss[0].mirror_ds))
+ goto outerr;
+
+ return true;
+@@ -379,7 +379,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_la
+ if (!ff_layout_init_mirror_ds(lseg->pls_layout, mirror))
+ goto noconnect;
+
+- ds = mirror->mirror_ds->ds;
++ ds = mirror->dss[0].mirror_ds->ds;
+ if (READ_ONCE(ds->ds_clp))
+ goto out;
+ /* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */
+@@ -388,10 +388,10 @@ nfs4_ff_layout_prepare_ds(struct pnfs_la
+ /* FIXME: For now we assume the server sent only one version of NFS
+ * to use for the DS.
+ */
+- status = nfs4_pnfs_ds_connect(s, ds, &mirror->mirror_ds->id_node,
++ status = nfs4_pnfs_ds_connect(s, ds, &mirror->dss[0].mirror_ds->id_node,
+ dataserver_timeo, dataserver_retrans,
+- mirror->mirror_ds->ds_versions[0].version,
+- mirror->mirror_ds->ds_versions[0].minor_version);
++ mirror->dss[0].mirror_ds->ds_versions[0].version,
++ mirror->dss[0].mirror_ds->ds_versions[0].minor_version);
+
+ /* connect success, check rsize/wsize limit */
+ if (!status) {
+@@ -404,10 +404,10 @@ nfs4_ff_layout_prepare_ds(struct pnfs_la
+ max_payload =
+ nfs_block_size(rpc_max_payload(ds->ds_clp->cl_rpcclient),
+ NULL);
+- if (mirror->mirror_ds->ds_versions[0].rsize > max_payload)
+- mirror->mirror_ds->ds_versions[0].rsize = max_payload;
+- if (mirror->mirror_ds->ds_versions[0].wsize > max_payload)
+- mirror->mirror_ds->ds_versions[0].wsize = max_payload;
++ if (mirror->dss[0].mirror_ds->ds_versions[0].rsize > max_payload)
++ mirror->dss[0].mirror_ds->ds_versions[0].rsize = max_payload;
++ if (mirror->dss[0].mirror_ds->ds_versions[0].wsize > max_payload)
++ mirror->dss[0].mirror_ds->ds_versions[0].wsize = max_payload;
+ goto out;
+ }
+ noconnect:
+@@ -430,7 +430,7 @@ ff_layout_get_ds_cred(struct nfs4_ff_lay
+ {
+ const struct cred *cred;
+
+- if (mirror && !mirror->mirror_ds->ds_versions[0].tightly_coupled) {
++ if (mirror && !mirror->dss[0].mirror_ds->ds_versions[0].tightly_coupled) {
+ cred = ff_layout_get_mirror_cred(mirror, range->iomode);
+ if (!cred)
+ cred = get_cred(mdscred);
+@@ -453,7 +453,7 @@ struct rpc_clnt *
+ nfs4_ff_find_or_create_ds_client(struct nfs4_ff_layout_mirror *mirror,
+ struct nfs_client *ds_clp, struct inode *inode)
+ {
+- switch (mirror->mirror_ds->ds_versions[0].version) {
++ switch (mirror->dss[0].mirror_ds->ds_versions[0].version) {
+ case 3:
+ /* For NFSv3 DS, flavor is set when creating DS connections */
+ return ds_clp->cl_rpcclient;
+@@ -564,11 +564,11 @@ static bool ff_read_layout_has_available
+ for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) {
+ mirror = FF_LAYOUT_COMP(lseg, idx);
+ if (mirror) {
+- if (!mirror->mirror_ds)
++ if (!mirror->dss[0].mirror_ds)
+ return true;
+- if (IS_ERR(mirror->mirror_ds))
++ if (IS_ERR(mirror->dss[0].mirror_ds))
+ continue;
+- devid = &mirror->mirror_ds->id_node;
++ devid = &mirror->dss[0].mirror_ds->id_node;
+ if (!nfs4_test_deviceid_unavailable(devid))
+ return true;
+ }
+@@ -585,11 +585,11 @@ static bool ff_rw_layout_has_available_d
+
+ for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) {
+ mirror = FF_LAYOUT_COMP(lseg, idx);
+- if (!mirror || IS_ERR(mirror->mirror_ds))
++ if (!mirror || IS_ERR(mirror->dss[0].mirror_ds))
+ return false;
+- if (!mirror->mirror_ds)
++ if (!mirror->dss[0].mirror_ds)
+ continue;
+- devid = &mirror->mirror_ds->id_node;
++ devid = &mirror->dss[0].mirror_ds->id_node;
+ if (nfs4_test_deviceid_unavailable(devid))
+ return false;
+ }
--- /dev/null
+From stable+bounces-272000-greg=kroah.com@vger.kernel.org Sun Jul 5 05:12:09 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 4 Jul 2026 23:11:50 -0400
+Subject: NFSv4/flexfiles: reject zero filehandle version count
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Anna Schumaker <anna.schumaker@hammerspace.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260705031150.1600970-5-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit 2c6bb3c40bc24f6aa8dfbe6fe98c3ad6389203f2 ]
+
+ff_layout_alloc_lseg() decodes the filehandle-version array count
+from the flexfiles layout body. The value is used as the count for
+kzalloc_objs(), and the current code only rejects NULL.
+
+A zero count yields ZERO_SIZE_PTR, which can be stored in
+dss_info->fh_versions even though later flexfiles paths assume that at
+least one filehandle version exists.
+
+Reject fh_count == 0 before the allocation, matching the existing zero
+version_count validation in the flexfiles GETDEVICEINFO parser.
+
+A QEMU/KASAN run with a malformed flexfiles layout hit:
+
+ KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
+ RIP: 0010:ff_layout_encode_ff_layoutupdate.isra.0+0x15f/0x750
+ ff_layout_encode_layoutreturn+0x683/0x970
+ nfs4_xdr_enc_layoutreturn+0x278/0x3a0
+ Kernel panic - not syncing: Fatal exception
+
+The patched kernel rejects the malformed layout without KASAN/oops/panic,
+and a valid fh_count=1 regression still opens, reads, and unmounts cleanly.
+
+Cc: stable@vger.kernel.org
+Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver")
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/flexfilelayout/flexfilelayout.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/fs/nfs/flexfilelayout/flexfilelayout.c
++++ b/fs/nfs/flexfilelayout/flexfilelayout.c
+@@ -493,6 +493,10 @@ ff_layout_alloc_lseg(struct pnfs_layout_
+ if (!p)
+ goto out_err_free;
+ fh_count = be32_to_cpup(p);
++ if (fh_count == 0) {
++ rc = -EINVAL;
++ goto out_err_free;
++ }
+
+ fls->mirror_array[i]->dss[dss_id].fh_versions =
+ kcalloc(fh_count, sizeof(struct nfs_fh),
--- /dev/null
+From stable+bounces-271998-greg=kroah.com@vger.kernel.org Sun Jul 5 05:12:02 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 4 Jul 2026 23:11:48 -0400
+Subject: NFSv4/flexfiles: Remove cred local variable dependency
+To: stable@vger.kernel.org
+Cc: Jonathan Curley <jcurley@purestorage.com>, Anna Schumaker <anna.schumaker@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260705031150.1600970-3-sashal@kernel.org>
+
+From: Jonathan Curley <jcurley@purestorage.com>
+
+[ Upstream commit fec80afc41afa3016421115427df8d00dc491ee5 ]
+
+No-op preparation change to remove dependency on cred local
+variable. Subsequent striping diff has a cred per stripe so this local
+variable can't be trusted to be the same.
+
+Signed-off-by: Jonathan Curley <jcurley@purestorage.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
+Stable-dep-of: 2c6bb3c40bc2 ("NFSv4/flexfiles: reject zero filehandle version count")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/flexfilelayout/flexfilelayout.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/fs/nfs/flexfilelayout/flexfilelayout.c
++++ b/fs/nfs/flexfilelayout/flexfilelayout.c
+@@ -531,10 +531,10 @@ ff_layout_alloc_lseg(struct pnfs_layout_
+ if (mirror != fls->mirror_array[i]) {
+ /* swap cred ptrs so free_mirror will clean up old */
+ if (lgr->range.iomode == IOMODE_READ) {
+- cred = xchg(&mirror->ro_cred, cred);
++ cred = xchg(&mirror->ro_cred, fls->mirror_array[i]->ro_cred);
+ rcu_assign_pointer(fls->mirror_array[i]->ro_cred, cred);
+ } else {
+- cred = xchg(&mirror->rw_cred, cred);
++ cred = xchg(&mirror->rw_cred, fls->mirror_array[i]->rw_cred);
+ rcu_assign_pointer(fls->mirror_array[i]->rw_cred, cred);
+ }
+ ff_layout_free_mirror(fls->mirror_array[i]);
gpio-rockchip-teardown-bugs-and-resource-leaks.patch
gpio-rockchip-fix-generic-irq-chip-leak-on-remove.patch
mm-vmalloc-take-vmap_purge_lock-in-shrinker.patch
+device-property-initialize-the-remaining-fields-of-fwnode_handle-in-fwnode_init.patch
+f2fs-validate-orphan-inode-entry-count.patch
+f2fs-atomic-fix-uaf-issue-on-f2fs_inode_info.atomic_inode.patch
+f2fs-bound-i_inline_xattr_size-for-non-inline-xattr-inodes.patch
+f2fs-fix-potential-deadlock-in-f2fs_balance_fs.patch
+f2fs-fix-potential-deadlock-in-gc_merge-path-of-f2fs_balance_fs.patch
+f2fs-fix-listxattr-handling-of-corrupted-xattr-entries.patch
+fbdev-fbcon-fix-out-of-bounds-read-in-err_out-of-fbcon_do_set_font.patch
+nfsd-add-nfsd_file_-get-put-to-nfs_to-nfsd_localio_operations.patch
+nfs_common-rename-functions-that-invalidate-localio-nfs_clients.patch
+nfsv4-flexfiles-remove-cred-local-variable-dependency.patch
+nfsv4-flexfiles-add-data-structure-support-for-striped-layouts.patch
+nfsv4-flexfiles-reject-zero-filehandle-version-count.patch
+locking-rtmutex-make-sure-we-wake-anything-on-the-wake_q-when-we-release-the-lock-wait_lock.patch
+apparmor-advertise-the-tcp-fast-open-fix-is-applied.patch