Skip to contentSkip to conversation

FAILED: patch "[PATCH] xfs: don't stash removename operations with unknown ftype" failed to apply to 6.12-stable tree

PATCH In review [email protected] 3 participants 4 messages Sep 16 – Sep 30

Subsystems (2)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

To reproduce the conflict and resubmit, you may use the following commands:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 865b751e75039fc07838b3200f9740256653da9a
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026091654-contented-triceps-9bbc@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'

Possible dependencies:

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From 865b751e75039fc07838b3200f9740256653da9a Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <[email protected]>
Date: Wed, 26 Aug 2026 22:31:25 -0700
Subject: [PATCH] xfs: don't stash removename operations with unknown ftype

LOLLM notices that the behavior of xrep_dir_replay_update changes based on the ftype recorded in the stashed removename information. It also notices that the unlink iops sometimes set that ftype to FT_UNKNOWN because the regular directory tree update code paths don't need to know the ftype of the child.

Unfortunately, this results in incorrect link counts, which eventually trips link count errors in later phases of xfs_scrub, or in xfs_repair. Fix this by creating a second xfs_name with the type set correctly.

Fixes 8559b21a64d983 ("xfs: implement live updates for directory repairs")
Assisted-by LOLLM # finding obvious bugs
fs/xfs/scrub/dir_repair.c +17 -2
index 0c1224d05d57..31a23c5f386a 100644
@@ -1381,9 +1381,24 @@ xrep_dir_live_update(
 		if (p->delta > 0)
 			error = xrep_dir_stash_createname(rd, p->name,
 					I_INO(p->ip));
-		else
-			error = xrep_dir_stash_removename(rd, p->name,
+		else {
+			/*
+			 * xfs_dentry_to_name in unlink or rename-exchange can
+			 * pass us names with ftype FT_UNKNOWN, but we really
+			 * must know the ftype of the child that is being
+			 * removed so that we can do nlink updates correctly
+			 * without holding inode references.
+			 */
+			struct xfs_name	name = {
+				.name	= p->name->name,
+				.len	= p->name->len,
+				.type	= xfs_mode_to_ftype(
+						VFS_IC(p->ip)->i_mode),
+			};
+
+			error = xrep_dir_stash_removename(rd, &name,
 					I_INO(p->ip));
+		}
 		mutex_unlock(&rd->pscan.lock);
 		if (error)
 			goto out_abort;
maintainer
#1 lore raw

PATCH 1/2 xfs: remove the i_ino field in struct xfs_inode

From: Christoph Hellwig <[email protected]>

[ Upstream commit 1113a6d6d5d1336f4415fa1367aac0f853f0892d ]

Now that the VFS inode has a u64 i_ino field, there is no need to store a copy of the inode number in the xfs_inode structure.

Introduce an I_INO() wrapper as a shortcut to the inode number so that we don't have to propagate the VFS inode everywhere.

The only non-obvious part is the clearing of i_ino to 0 for RCU freeing the inode. None of this calls into VFS paths, which makes clearing the VFS inode field here just as safe as clearing the old field in the xfs_inode.

[ Stable dependency adaptation for 865b751e75039fc07838b3200f9740256653da9a:
Keep xfs_inode.i_ino because this branch's VFS inode number is unsigned long and cannot hold all XFS inode numbers on 32-bit architectures. Provide I_INO as a macro over the existing xfs_ino_t field, without adding a function or changing inode allocation and reclaim semantics. Retain only the accessor conversions in xrep_dir_live_update, which provide the context needed for the target directory-repair fix to apply unchanged. Drop the other conversions, including changes to metadata-directory and realtime-repair code absent from this tree. The upstream subject is retained; removal of the inode field is not part of this stable adaptation. ]

[ sashal: Reduced backport -- upstream 1113a6d6d5d13 touches 91 file(s), this
backport carries 2. Not backported here:
fs/xfs/libxfs/xfs_attr.c
fs/xfs/libxfs/xfs_attr_leaf.c
fs/xfs/libxfs/xfs_bmap_btree.c
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_btree_staging.c
fs/xfs/libxfs/xfs_da_btree.c
fs/xfs/libxfs/xfs_dir2.c
... and 81 more
This note is generated from the file lists only; see the resolution record for the reasoning. ]

Stable-dep-of: 865b751e7503 ("xfs: don't stash removename operations with unknown ftype")

---
 fs/xfs/scrub/dir_repair.c | 16 ++++++++--------
 fs/xfs/xfs_inode.h        |  3 +++
 2 files changed, 11 insertions(+), 8 deletions(-)
fs/xfs/scrub/dir_repair.c +8 -8
index 29c48c4db53b2..0cdd763250cc3 100644
@@ -1367,15 +1367,15 @@ xrep_dir_live_update(
 	 * rebuilding.  Stash the update for replay against the temporary
 	 * directory.
 	 */
-	if (p->dp->i_ino == sc->ip->i_ino &&
-	    xchk_iscan_want_live_update(&rd->pscan.iscan, p->ip->i_ino)) {
+	if (I_INO(p->dp) == I_INO(sc->ip) &&
+	    xchk_iscan_want_live_update(&rd->pscan.iscan, I_INO(p->ip))) {
 		mutex_lock(&rd->pscan.lock);
 		if (p->delta > 0)
 			error = xrep_dir_stash_createname(rd, p->name,
-					p->ip->i_ino);
+					I_INO(p->ip));
 		else
 			error = xrep_dir_stash_removename(rd, p->name,
-					p->ip->i_ino);
+					I_INO(p->ip));
 		mutex_unlock(&rd->pscan.lock);
 		if (error)
 			goto out_abort;
@@ -1386,14 +1386,14 @@ xrep_dir_live_update(
 	 * the directory that we're rebuilding, so remember the new dotdot
 	 * target.
 	 */
-	if (p->ip->i_ino == sc->ip->i_ino &&
-	    xchk_iscan_want_live_update(&rd->pscan.iscan, p->dp->i_ino)) {
+	if (I_INO(p->ip) == I_INO(sc->ip) &&
+	    xchk_iscan_want_live_update(&rd->pscan.iscan, I_INO(p->dp))) {
 		if (p->delta > 0) {
 			trace_xrep_dir_stash_createname(sc->tempip,
 					&xfs_name_dotdot,
-					p->dp->i_ino);
+					I_INO(p->dp));
 
-			xrep_findparent_scan_found(&rd->pscan, p->dp->i_ino);
+			xrep_findparent_scan_found(&rd->pscan, I_INO(p->dp));
 		} else {
 			trace_xrep_dir_stash_removename(sc->tempip,
 					&xfs_name_dotdot,
fs/xfs/xfs_inode.h +3 -0
index 03944b6c5fba1..33ea744d5992b 100644
@@ -178,6 +178,9 @@ static inline const struct inode *VFS_IC(const struct xfs_inode *ip)
 	return &ip->i_vnode;
 }
 
+/* The VFS inode number can be narrower than xfs_ino_t on this branch. */
+#define I_INO(ip) ((ip)->i_ino)
+
 /*
  * For regular files we only update the on-disk filesize when actually
  * writing data back to disk.  Until then only the copy in the VFS inode
Signature · 1 line
2.53.0
maintainer
#2 lore raw

PATCH 2/2 xfs: don't stash removename operations with unknown ftype

From: "Darrick J. Wong" <[email protected]>

[ Upstream commit 865b751e75039fc07838b3200f9740256653da9a ]

LOLLM notices that the behavior of xrep_dir_replay_update changes based on the ftype recorded in the stashed removename information. It also notices that the unlink iops sometimes set that ftype to FT_UNKNOWN because the regular directory tree update code paths don't need to know the ftype of the child.

Unfortunately, this results in incorrect link counts, which eventually trips link count errors in later phases of xfs_scrub, or in xfs_repair. Fix this by creating a second xfs_name with the type set correctly.

Fixes 8559b21a64d983 ("xfs: implement live updates for directory repairs")
Assisted-by LOLLM # finding obvious bugs
---
 fs/xfs/scrub/dir_repair.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)
fs/xfs/scrub/dir_repair.c +17 -2
index 0cdd763250cc3..5d594085a6c1b 100644
@@ -1373,9 +1373,24 @@ xrep_dir_live_update(
 		if (p->delta > 0)
 			error = xrep_dir_stash_createname(rd, p->name,
 					I_INO(p->ip));
-		else
-			error = xrep_dir_stash_removename(rd, p->name,
+		else {
+			/*
+			 * xfs_dentry_to_name in unlink or rename-exchange can
+			 * pass us names with ftype FT_UNKNOWN, but we really
+			 * must know the ftype of the child that is being
+			 * removed so that we can do nlink updates correctly
+			 * without holding inode references.
+			 */
+			struct xfs_name	name = {
+				.name	= p->name->name,
+				.len	= p->name->len,
+				.type	= xfs_mode_to_ftype(
+						VFS_IC(p->ip)->i_mode),
+			};
+
+			error = xrep_dir_stash_removename(rd, &name,
 					I_INO(p->ip));
+		}
 		mutex_unlock(&rd->pscan.lock);
 		if (error)
 			goto out_abort;
Signature · 1 line
2.53.0
#3 lore raw

Re: [PATCH 6.12.y 2/2] xfs: don't stash removename operations with unknown ftype

Quoted 60 lines · Sasha Levin

From: "Darrick J. Wong" <[email protected]>

[ Upstream commit 865b751e75039fc07838b3200f9740256653da9a ]

LOLLM notices that the behavior of xrep_dir_replay_update changes based on the ftype recorded in the stashed removename information. It also notices that the unlink iops sometimes set that ftype to FT_UNKNOWN because the regular directory tree update code paths don't need to know the ftype of the child.

Unfortunately, this results in incorrect link counts, which eventually trips link count errors in later phases of xfs_scrub, or in xfs_repair. Fix this by creating a second xfs_name with the type set correctly.

Fixes 8559b21a64d983 ("xfs: implement live updates for directory repairs")
Assisted-by LOLLM # finding obvious bugs
---
 fs/xfs/scrub/dir_repair.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)
fs/xfs/scrub/dir_repair.c +17 -2
index 0cdd763250cc3..5d594085a6c1b 100644
@@ -1373,9 +1373,24 @@ xrep_dir_live_update(
 		if (p->delta > 0)
 			error = xrep_dir_stash_createname(rd, p->name,
 					I_INO(p->ip));
-		else
-			error = xrep_dir_stash_removename(rd, p->name,
+		else {
+			/*
+			 * xfs_dentry_to_name in unlink or rename-exchange can
+			 * pass us names with ftype FT_UNKNOWN, but we really
+			 * must know the ftype of the child that is being
+			 * removed so that we can do nlink updates correctly
+			 * without holding inode references.
+			 */
+			struct xfs_name	name = {
+				.name	= p->name->name,
+				.len	= p->name->len,
+				.type	= xfs_mode_to_ftype(
+						VFS_IC(p->ip)->i_mode),
+			};
+
+			error = xrep_dir_stash_removename(rd, &name,
 					I_INO(p->ip));
+		}
 		mutex_unlock(&rd->pscan.lock);
 		if (error)
 			goto out_abort;
Signature · 1 line
2.53.0

did not apply