This is a note to let you know that I've just added the patch titled xfs: fix incorrect i_nlink caused by inode racing to the 6.1-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: xfs-fix-incorrect-i_nlink-caused-by-inode-racing.patch and it can be found in the queue-6.1 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From stable+bounces-42902-greg=kroah.com@xxxxxxxxxxxxxxx Wed May 1 20:41:56 2024 From: Leah Rumancik <leah.rumancik@xxxxxxxxx> Date: Wed, 1 May 2024 11:41:01 -0700 Subject: xfs: fix incorrect i_nlink caused by inode racing To: stable@xxxxxxxxxxxxxxx Cc: linux-xfs@xxxxxxxxxxxxxxx, amir73il@xxxxxxxxx, chandan.babu@xxxxxxxxxx, fred@xxxxxxxxxxxxxx, Long Li <leo.lilong@xxxxxxxxxx>, "Darrick J . Wong" <djwong@xxxxxxxxxx>, Leah Rumancik <leah.rumancik@xxxxxxxxx> Message-ID: <20240501184112.3799035-13-leah.rumancik@xxxxxxxxx> From: Long Li <leo.lilong@xxxxxxxxxx> [ Upstream commit 28b4b0596343d19d140da059eee0e5c2b5328731 ] The following error occurred during the fsstress test: XFS: Assertion failed: VFS_I(ip)->i_nlink >= 2, file: fs/xfs/xfs_inode.c, line: 2452 The problem was that inode race condition causes incorrect i_nlink to be written to disk, and then it is read into memory. Consider the following call graph, inodes that are marked as both XFS_IFLUSHING and XFS_IRECLAIMABLE, i_nlink will be reset to 1 and then restored to original value in xfs_reinit_inode(). Therefore, the i_nlink of directory on disk may be set to 1. xfsaild xfs_inode_item_push xfs_iflush_cluster xfs_iflush xfs_inode_to_disk xfs_iget xfs_iget_cache_hit xfs_iget_recycle xfs_reinit_inode inode_init_always xfs_reinit_inode() needs to hold the ILOCK_EXCL as it is changing internal inode state and can race with other RCU protected inode lookups. On the read side, xfs_iflush_cluster() grabs the ILOCK_SHARED while under rcu + ip->i_flags_lock, and so xfs_iflush/xfs_inode_to_disk() are protected from racing inode updates (during transactions) by that lock. Fixes: ff7bebeb91f8 ("xfs: refactor the inode recycling code") # goes further back than this Signed-off-by: Long Li <leo.lilong@xxxxxxxxxx> Reviewed-by: Darrick J. Wong <djwong@xxxxxxxxxx> Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> Signed-off-by: Leah Rumancik <leah.rumancik@xxxxxxxxx> Acked-by: Darrick J. Wong <djwong@xxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- fs/xfs/xfs_icache.c | 6 ++++++ 1 file changed, 6 insertions(+) --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -342,6 +342,9 @@ xfs_iget_recycle( trace_xfs_iget_recycle(ip); + if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) + return -EAGAIN; + /* * We need to make it look like the inode is being reclaimed to prevent * the actual reclaim workers from stomping over us while we recycle @@ -355,6 +358,7 @@ xfs_iget_recycle( ASSERT(!rwsem_is_locked(&inode->i_rwsem)); error = xfs_reinit_inode(mp, inode); + xfs_iunlock(ip, XFS_ILOCK_EXCL); if (error) { /* * Re-initializing the inode failed, and we are in deep @@ -523,6 +527,8 @@ xfs_iget_cache_hit( if (ip->i_flags & XFS_IRECLAIMABLE) { /* Drops i_flags_lock and RCU read lock. */ error = xfs_iget_recycle(pag, ip); + if (error == -EAGAIN) + goto out_skip; if (error) return error; } else { Patches currently in stable-queue which might be from kroah.com@xxxxxxxxxxxxxxx are queue-6.1/xfs-iomap-move-delalloc-punching-to-iomap.patch queue-6.1/xfs-fix-off-by-one-block-in-xfs_discard_folio.patch queue-6.1/xfs-invalidate-block-device-page-cache-during-unmount.patch queue-6.1/xfs-drop-write-error-injection-is-unfixable-remove-it.patch queue-6.1/iomap-buffered-write-failure-should-not-truncate-the-page-cache.patch queue-6.1/xfs-fix-super-block-buf-log-item-uaf-during-force-shutdown.patch queue-6.1/xfs-fix-incorrect-i_nlink-caused-by-inode-racing.patch queue-6.1/xfs-estimate-post-merge-refcounts-correctly.patch queue-6.1/xfs-fix-log-recovery-when-unknown-rocompat-bits-are-set.patch queue-6.1/xfs-punching-delalloc-extents-on-write-failure-is-racy.patch queue-6.1/xfs-allow-inode-inactivation-during-a-ro-mount-log-recovery.patch queue-6.1/iomap-write-iomap-validity-checks.patch queue-6.1/xfs-attach-dquots-to-inode-before-reading-data-cow-fork-mappings.patch queue-6.1/xfs-fix-sb-write-verify-for-lazysbcount.patch queue-6.1/xfs-wait-iclog-complete-before-tearing-down-ail.patch queue-6.1/xfs-use-byte-ranges-for-write-cleanup-ranges.patch queue-6.1/xfs-xfs_bmap_punch_delalloc_range-should-take-a-byte-range.patch queue-6.1/xfs-write-page-faults-in-iomap-are-not-buffered-writes.patch queue-6.1/xfs-short-circuit-xfs_growfs_data_private-if-delta-is-zero.patch queue-6.1/xfs-fix-incorrect-error-out-in-xfs_remove.patch queue-6.1/xfs-invalidate-xfs_bufs-when-allocating-cow-extents.patch queue-6.1/xfs-hoist-refcount-record-merge-predicates.patch queue-6.1/xfs-get-root-inode-correctly-at-bulkstat.patch queue-6.1/xfs-use-iomap_valid-method-to-detect-stale-cached-iomaps.patch