]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: don't remove the attr fork when parent pointers are enabled
authorAllison Henderson <allison.henderson@oracle.com>
Mon, 29 Jul 2024 23:22:49 +0000 (16:22 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 30 Jul 2024 00:01:03 +0000 (17:01 -0700)
Source kernel commit: 7dafb449b7922c1eec6fee3ed85b679d51f0f431

When an inode is removed, it may also cause the attribute fork to be
removed if it is the last attribute. This transaction gets flushed to
the log, but if the system goes down before we could inactivate the symlink,
the log recovery tries to inactivate this inode (since it is on the unlinked
list) but the verifier trips over the remote value and leaks it.

Hence we ended up with a file in this odd state on a "clean" mount.  The
"obvious" fix is to prohibit erasure of the attr fork to avoid tripping
over the verifiers when pptrs are enabled.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
libxfs/xfs_attr_leaf.c

index faa357f15658fd085c8191e959cce1e99ce541df..ce20d81a486988ec7b4c37e723af84979c491f3c 100644 (file)
@@ -888,7 +888,8 @@ xfs_attr_sf_removename(
         */
        if (totsize == sizeof(struct xfs_attr_sf_hdr) && xfs_has_attr2(mp) &&
            (dp->i_df.if_format != XFS_DINODE_FMT_BTREE) &&
-           !(args->op_flags & (XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE))) {
+           !(args->op_flags & (XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE)) &&
+           !xfs_has_parent(mp)) {
                xfs_attr_fork_remove(dp, args->trans);
        } else {
                xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
@@ -897,7 +898,8 @@ xfs_attr_sf_removename(
                ASSERT(totsize > sizeof(struct xfs_attr_sf_hdr) ||
                                (args->op_flags & XFS_DA_OP_ADDNAME) ||
                                !xfs_has_attr2(mp) ||
-                               dp->i_df.if_format == XFS_DINODE_FMT_BTREE);
+                               dp->i_df.if_format == XFS_DINODE_FMT_BTREE ||
+                               xfs_has_parent(mp));
                xfs_trans_log_inode(args->trans, dp,
                                        XFS_ILOG_CORE | XFS_ILOG_ADATA);
        }