]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: support file data forks containing metadata btrees
authorDarrick J. Wong <djwong@kernel.org>
Mon, 24 Feb 2025 18:21:48 +0000 (10:21 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 25 Feb 2025 17:15:58 +0000 (09:15 -0800)
Source kernel commit: 702c90f451622384d6c65897b619f647704b06a9

Create a new fork format type for metadata btrees.  This fork type
requires that the inode is in the metadata directory tree, and only
applies to the data fork.  The actual type of the metadata btree itself
is determined by the di_metatype field.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
libxfs/xfs_format.h
libxfs/xfs_inode_buf.c
libxfs/xfs_inode_fork.c

index 469fc7afa591b4c3bb036b1a09906902cf7c518e..41ea4283c43cb4ddefb0da45fc7712a61805573a 100644 (file)
@@ -997,7 +997,8 @@ enum xfs_dinode_fmt {
        XFS_DINODE_FMT_LOCAL,           /* bulk data */
        XFS_DINODE_FMT_EXTENTS,         /* struct xfs_bmbt_rec */
        XFS_DINODE_FMT_BTREE,           /* struct xfs_bmdr_block */
-       XFS_DINODE_FMT_UUID             /* added long ago, but never used */
+       XFS_DINODE_FMT_UUID,            /* added long ago, but never used */
+       XFS_DINODE_FMT_META_BTREE,      /* metadata btree */
 };
 
 #define XFS_INODE_FORMAT_STR \
@@ -1005,7 +1006,8 @@ enum xfs_dinode_fmt {
        { XFS_DINODE_FMT_LOCAL,         "local" }, \
        { XFS_DINODE_FMT_EXTENTS,       "extent" }, \
        { XFS_DINODE_FMT_BTREE,         "btree" }, \
-       { XFS_DINODE_FMT_UUID,          "uuid" }
+       { XFS_DINODE_FMT_UUID,          "uuid" }, \
+       { XFS_DINODE_FMT_META_BTREE,    "meta_btree" }
 
 /*
  * Max values for extnum and aextnum.
index 98482cb4948284ae345396666af965c2e48b4834..10ce2e34969d99bf83fe7d97dd3e4ddfcdd20bc2 100644 (file)
@@ -438,6 +438,16 @@ xfs_dinode_verify_fork(
                if (di_nextents > max_extents)
                        return __this_address;
                break;
+       case XFS_DINODE_FMT_META_BTREE:
+               if (!xfs_has_metadir(mp))
+                       return __this_address;
+               if (!(dip->di_flags2 & cpu_to_be64(XFS_DIFLAG2_METADATA)))
+                       return __this_address;
+               switch (be16_to_cpu(dip->di_metatype)) {
+               default:
+                       return __this_address;
+               }
+               break;
        default:
                return __this_address;
        }
@@ -457,6 +467,10 @@ xfs_dinode_verify_forkoff(
                if (dip->di_forkoff != (roundup(sizeof(xfs_dev_t), 8) >> 3))
                        return __this_address;
                break;
+       case XFS_DINODE_FMT_META_BTREE:
+               if (!xfs_has_metadir(mp) || !xfs_has_parent(mp))
+                       return __this_address;
+               fallthrough;
        case XFS_DINODE_FMT_LOCAL:      /* fall through ... */
        case XFS_DINODE_FMT_EXTENTS:    /* fall through ... */
        case XFS_DINODE_FMT_BTREE:
@@ -634,9 +648,6 @@ xfs_dinode_verify(
        if (mode && nextents + naextents > nblocks)
                return __this_address;
 
-       if (nextents + naextents == 0 && nblocks != 0)
-               return __this_address;
-
        if (S_ISDIR(mode) && nextents > mp->m_dir_geo->max_extents)
                return __this_address;
 
@@ -740,6 +751,12 @@ xfs_dinode_verify(
                        return fa;
        }
 
+       /* metadata inodes containing btrees always have zero extent count */
+       if (XFS_DFORK_FORMAT(dip, XFS_DATA_FORK) != XFS_DINODE_FMT_META_BTREE) {
+               if (nextents + naextents == 0 && nblocks != 0)
+                       return __this_address;
+       }
+
        return NULL;
 }
 
index d6bbff85ffba8e15199117585e1e9c902934536a..b66dc4ad0f52ef3b07509b186427362c436acf41 100644 (file)
@@ -265,6 +265,12 @@ xfs_iformat_data_fork(
                        return xfs_iformat_extents(ip, dip, XFS_DATA_FORK);
                case XFS_DINODE_FMT_BTREE:
                        return xfs_iformat_btree(ip, dip, XFS_DATA_FORK);
+               case XFS_DINODE_FMT_META_BTREE:
+                       switch (ip->i_metatype) {
+                       default:
+                               break;
+                       }
+                       fallthrough;
                default:
                        xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__,
                                        dip, sizeof(*dip), __this_address);
@@ -599,6 +605,19 @@ xfs_iflush_fork(
                }
                break;
 
+       case XFS_DINODE_FMT_META_BTREE:
+               ASSERT(whichfork == XFS_DATA_FORK);
+
+               if (!(iip->ili_fields & brootflag[whichfork]))
+                       break;
+
+               switch (ip->i_metatype) {
+               default:
+                       ASSERT(0);
+                       break;
+               }
+               break;
+
        default:
                ASSERT(0);
                break;