]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: attr fork iext must be loaded before calling xfs_attr_is_leaf
authorDarrick J. Wong <djwong@kernel.org>
Mon, 29 Jul 2024 23:22:44 +0000 (16:22 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 30 Jul 2024 00:01:01 +0000 (17:01 -0700)
Source kernel commit: ef80de940a6344da1d4f12c948a0ad4d6ff6e841

Christoph noticed that the xfs_attr_is_leaf in xfs_attr_get_ilocked can
access the incore extent tree of the attr fork, but nothing in the
xfs_attr_get path guarantees that the incore tree is actually loaded.

Most of the time it is, but seeing as xfs_attr_is_leaf ignores the
return value of xfs_iext_get_extent I guess we've been making choices
based on random stack contents and nobody's complained?

Reported-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
libxfs/xfs_attr.c

index 5249f9be046e50a5ae51fa6d12e7f63c03f37d42..8e9e238369ceda0f3fd1b729b3f00a1d07ac3688 100644 (file)
@@ -85,6 +85,8 @@ xfs_attr_is_leaf(
        struct xfs_iext_cursor  icur;
        struct xfs_bmbt_irec    imap;
 
+       ASSERT(!xfs_need_iread_extents(ifp));
+
        if (ifp->if_nextents != 1 || ifp->if_format != XFS_DINODE_FMT_EXTENTS)
                return false;
 
@@ -222,11 +224,21 @@ int
 xfs_attr_get_ilocked(
        struct xfs_da_args      *args)
 {
+       int                     error;
+
        xfs_assert_ilocked(args->dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);
 
        if (!xfs_inode_hasattr(args->dp))
                return -ENOATTR;
 
+       /*
+        * The incore attr fork iext tree must be loaded for xfs_attr_is_leaf
+        * to work correctly.
+        */
+       error = xfs_iread_extents(args->trans, args->dp, XFS_ATTR_FORK);
+       if (error)
+               return error;
+
        if (args->dp->i_af.if_format == XFS_DINODE_FMT_LOCAL)
                return xfs_attr_shortform_getvalue(args);
        if (xfs_attr_is_leaf(args->dp))
@@ -868,6 +880,11 @@ xfs_attr_lookup(
                return -ENOATTR;
        }
 
+       /* Prerequisite for xfs_attr_is_leaf */
+       error = xfs_iread_extents(args->trans, args->dp, XFS_ATTR_FORK);
+       if (error)
+               return error;
+
        if (xfs_attr_is_leaf(dp)) {
                error = xfs_attr_leaf_hasname(args, &bp);