]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs: define the on-disk format for the metadir feature
authorDarrick J. Wong <djwong@kernel.org>
Wed, 29 May 2024 04:10:55 +0000 (21:10 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 30 Jul 2024 00:13:16 +0000 (17:13 -0700)
Define the on-disk layout and feature flags for the metadata inode
directory feature.  Add a xfs_sb_version_hasmetadir for benefit of
xfs_repair, which needs to know where the new end of the superblock
lies.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
include/xfs_inode.h
include/xfs_mount.h
libxfs/xfs_format.h
libxfs/xfs_inode_util.c
libxfs/xfs_ondisk.h
libxfs/xfs_sb.c

index 27c050357c544a8848a82dbab1f843afc0e60379..549d7ea0ca1a3bba30c22350befc105e9776d232 100644 (file)
@@ -405,6 +405,11 @@ static inline bool xfs_is_always_cow_inode(struct xfs_inode *ip)
        return false;
 }
 
+static inline bool xfs_is_metadir_inode(const struct xfs_inode *ip)
+{
+       return ip->i_diflags2 & XFS_DIFLAG2_METADATA;
+}
+
 extern void    libxfs_trans_inode_alloc_buf (struct xfs_trans *,
                                struct xfs_buf *);
 
index a60474a8db3f22036d377db29f9d52fa4d100c53..8c8047f9e1cfb88225a8b12b3a2094fc585abf60 100644 (file)
@@ -170,6 +170,7 @@ typedef struct xfs_mount {
 #define XFS_FEAT_NEEDSREPAIR   (1ULL << 25)    /* needs xfs_repair */
 #define XFS_FEAT_NREXT64       (1ULL << 26)    /* large extent counters */
 #define XFS_FEAT_EXCHANGE_RANGE        (1ULL << 27)    /* exchange range */
+#define XFS_FEAT_METADIR       (1ULL << 28)    /* metadata directory tree */
 
 #define __XFS_HAS_FEAT(name, NAME) \
 static inline bool xfs_has_ ## name (struct xfs_mount *mp) \
@@ -215,6 +216,7 @@ __XFS_HAS_FEAT(bigtime, BIGTIME)
 __XFS_HAS_FEAT(needsrepair, NEEDSREPAIR)
 __XFS_HAS_FEAT(large_extent_counts, NREXT64)
 __XFS_HAS_FEAT(exchange_range, EXCHANGE_RANGE)
+__XFS_HAS_FEAT(metadir, METADIR)
 
 /* Kernel mount features that we don't support */
 #define __XFS_UNSUPP_FEAT(name) \
index e1bfee0c3b1a8c735bc18c698fb45ccc7ce110bd..68447c1e28b9aa38ab0bb8327db49e40e20b7938 100644 (file)
@@ -174,6 +174,8 @@ typedef struct xfs_sb {
        xfs_lsn_t       sb_lsn;         /* last write sequence */
        uuid_t          sb_meta_uuid;   /* metadata file system unique id */
 
+       xfs_ino_t       sb_metadirino;  /* metadata directory tree root */
+
        /* must be padded to 64 bit alignment */
 } xfs_sb_t;
 
@@ -259,6 +261,8 @@ struct xfs_dsb {
        __be64          sb_lsn;         /* last write sequence */
        uuid_t          sb_meta_uuid;   /* metadata file system unique id */
 
+       __be64          sb_metadirino;  /* metadata directory tree root */
+
        /* must be padded to 64 bit alignment */
 };
 
@@ -374,6 +378,7 @@ xfs_sb_has_ro_compat_feature(
 #define XFS_SB_FEAT_INCOMPAT_NREXT64   (1 << 5)  /* large extent counters */
 #define XFS_SB_FEAT_INCOMPAT_EXCHRANGE (1 << 6)  /* exchangerange supported */
 #define XFS_SB_FEAT_INCOMPAT_PARENT    (1 << 7)  /* parent pointers */
+#define XFS_SB_FEAT_INCOMPAT_METADIR   (1U << 31)      /* metadata dir tree */
 #define XFS_SB_FEAT_INCOMPAT_ALL \
                (XFS_SB_FEAT_INCOMPAT_FTYPE | \
                 XFS_SB_FEAT_INCOMPAT_SPINODES | \
@@ -426,6 +431,12 @@ static inline bool xfs_sb_version_haslogxattrs(struct xfs_sb *sbp)
                 XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);
 }
 
+static inline bool xfs_sb_version_hasmetadir(const struct xfs_sb *sbp)
+{
+       return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
+               (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_METADIR);
+}
+
 static inline bool
 xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino)
 {
@@ -1092,17 +1103,47 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
 #define XFS_DIFLAG2_REFLINK_BIT        1       /* file's blocks may be shared */
 #define XFS_DIFLAG2_COWEXTSIZE_BIT   2  /* copy on write extent size hint */
 #define XFS_DIFLAG2_BIGTIME_BIT        3       /* big timestamps */
-#define XFS_DIFLAG2_NREXT64_BIT 4      /* large extent counters */
+#define XFS_DIFLAG2_NREXT64_BIT        4       /* large extent counters */
+#define XFS_DIFLAG2_METADATA_BIT       63      /* filesystem metadata */
+
+#define XFS_DIFLAG2_DAX                (1ULL << XFS_DIFLAG2_DAX_BIT)
+#define XFS_DIFLAG2_REFLINK    (1ULL << XFS_DIFLAG2_REFLINK_BIT)
+#define XFS_DIFLAG2_COWEXTSIZE (1ULL << XFS_DIFLAG2_COWEXTSIZE_BIT)
+#define XFS_DIFLAG2_BIGTIME    (1ULL << XFS_DIFLAG2_BIGTIME_BIT)
+#define XFS_DIFLAG2_NREXT64    (1ULL << XFS_DIFLAG2_NREXT64_BIT)
 
-#define XFS_DIFLAG2_DAX                (1 << XFS_DIFLAG2_DAX_BIT)
-#define XFS_DIFLAG2_REFLINK     (1 << XFS_DIFLAG2_REFLINK_BIT)
-#define XFS_DIFLAG2_COWEXTSIZE  (1 << XFS_DIFLAG2_COWEXTSIZE_BIT)
-#define XFS_DIFLAG2_BIGTIME    (1 << XFS_DIFLAG2_BIGTIME_BIT)
-#define XFS_DIFLAG2_NREXT64    (1 << XFS_DIFLAG2_NREXT64_BIT)
+/*
+ * The inode contains filesystem metadata and can be found through the metadata
+ * directory tree.  Metadata inodes must satisfy the following constraints:
+ *
+ * - V5 filesystem (and ftype) are enabled;
+ * - The only valid modes are regular files and directories;
+ * - The access bits must be zero;
+ * - DMAPI event and state masks are zero;
+ * - The user and group IDs must be zero;
+ * - The project ID can be used as a u32 annotation;
+ * - The immutable, sync, noatime, nodump, nodefrag flags must be set.
+ * - The dax flag must not be set.
+ * - Directories must have nosymlinks set.
+ *
+ * These requirements are chosen defensively to minimize the ability of
+ * userspace to read or modify the contents, should a metadata file ever
+ * escape to userspace.
+ *
+ * There are further constraints on the directory tree itself:
+ *
+ * - Metadata inodes must never be resolvable through the root directory;
+ * - They must never be accessed by userspace;
+ * - Metadata directory entries must have correct ftype.
+ *
+ * Superblock-rooted metadata files must have the METADATA iflag set even
+ * though they do not have a parent directory.
+ */
+#define XFS_DIFLAG2_METADATA   (1ULL << XFS_DIFLAG2_METADATA_BIT)
 
 #define XFS_DIFLAG2_ANY \
        (XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \
-        XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_NREXT64)
+        XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_NREXT64 | XFS_DIFLAG2_METADATA)
 
 static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
 {
index 74d2b5960bf0f22dcf4c85ef3142a46ce93b5969..e534a4e9d9869cd65a75db057e5c115f438500fa 100644 (file)
@@ -221,6 +221,8 @@ xfs_inode_inherit_flags2(
        }
        if (pip->i_diflags2 & XFS_DIFLAG2_DAX)
                ip->i_diflags2 |= XFS_DIFLAG2_DAX;
+       if (pip->i_diflags2 & XFS_DIFLAG2_METADATA)
+               ip->i_diflags2 |= XFS_DIFLAG2_METADATA;
 
        /* Don't let invalid cowextsize hints propagate. */
        failaddr = xfs_inode_validate_cowextsize(ip->i_mount, ip->i_cowextsize,
index 23c133fd36f5bb10a3f867224c028a8ba1de4178..8bca86e350fdc11980a00cf52a492fc9b7504496 100644 (file)
@@ -37,7 +37,7 @@ xfs_check_ondisk_structs(void)
        XFS_CHECK_STRUCT_SIZE(struct xfs_dinode,                176);
        XFS_CHECK_STRUCT_SIZE(struct xfs_disk_dquot,            104);
        XFS_CHECK_STRUCT_SIZE(struct xfs_dqblk,                 136);
-       XFS_CHECK_STRUCT_SIZE(struct xfs_dsb,                   264);
+       XFS_CHECK_STRUCT_SIZE(struct xfs_dsb,                   272);
        XFS_CHECK_STRUCT_SIZE(struct xfs_dsymlink_hdr,          56);
        XFS_CHECK_STRUCT_SIZE(struct xfs_inobt_key,             4);
        XFS_CHECK_STRUCT_SIZE(struct xfs_inobt_rec,             16);
index bedb36a0620dff2065483a75ab152583e851d071..d59fa5093a3d08ce61c7be23c39f16c85ac93e37 100644 (file)
@@ -177,6 +177,8 @@ xfs_sb_version_to_features(
                features |= XFS_FEAT_EXCHANGE_RANGE;
        if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_PARENT)
                features |= XFS_FEAT_PARENT;
+       if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_METADIR)
+               features |= XFS_FEAT_METADIR;
 
        return features;
 }
@@ -680,6 +682,11 @@ __xfs_sb_from_disk(
        /* Convert on-disk flags to in-memory flags? */
        if (convert_xquota)
                xfs_sb_quota_from_disk(to);
+
+       if (to->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_METADIR)
+               to->sb_metadirino = be64_to_cpu(from->sb_metadirino);
+       else
+               to->sb_metadirino = NULLFSINO;
 }
 
 void
@@ -827,6 +834,9 @@ xfs_sb_to_disk(
        to->sb_lsn = cpu_to_be64(from->sb_lsn);
        if (from->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID)
                uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid);
+
+       if (from->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_METADIR)
+               to->sb_metadirino = cpu_to_be64(from->sb_metadirino);
 }
 
 /*