]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: support caching rtgroup metadata inodes
authorDarrick J. Wong <djwong@kernel.org>
Mon, 4 Nov 2024 04:19:06 +0000 (20:19 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 5 Nov 2024 21:38:35 +0000 (13:38 -0800)
Create the necessary per-rtgroup infrastructure that we need to load
metadata inodes into memory.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_rtgroup.c
fs/xfs/libxfs/xfs_rtgroup.h
fs/xfs/xfs_mount.h
fs/xfs/xfs_rtalloc.c

index 39e07e98eda1e5f35f7cd916405d22168a42904b..9aa8f5e5525d3dcdabea277267e2f193f6e229ef 100644 (file)
@@ -30,6 +30,8 @@
 #include "xfs_icache.h"
 #include "xfs_rtgroup.h"
 #include "xfs_rtbitmap.h"
+#include "xfs_metafile.h"
+#include "xfs_metadir.h"
 
 int
 xfs_rtgroup_alloc(
@@ -250,3 +252,124 @@ xfs_rtginode_lockdep_setup(
 #else
 #define xfs_rtginode_lockdep_setup(ip, rgno, type)     do { } while (0)
 #endif /* CONFIG_PROVE_LOCKING */
+
+struct xfs_rtginode_ops {
+       const char              *name;  /* short name */
+
+       enum xfs_metafile_type  metafile_type;
+
+       /* Does the fs have this feature? */
+       bool                    (*enabled)(struct xfs_mount *mp);
+};
+
+static const struct xfs_rtginode_ops xfs_rtginode_ops[XFS_RTGI_MAX] = {
+};
+
+/* Return the shortname of this rtgroup inode. */
+const char *
+xfs_rtginode_name(
+       enum xfs_rtg_inodes     type)
+{
+       return xfs_rtginode_ops[type].name;
+}
+
+/* Return the metafile type of this rtgroup inode. */
+enum xfs_metafile_type
+xfs_rtginode_metafile_type(
+       enum xfs_rtg_inodes     type)
+{
+       return xfs_rtginode_ops[type].metafile_type;
+}
+
+/* Should this rtgroup inode be present? */
+bool
+xfs_rtginode_enabled(
+       struct xfs_rtgroup      *rtg,
+       enum xfs_rtg_inodes     type)
+{
+       const struct xfs_rtginode_ops *ops = &xfs_rtginode_ops[type];
+
+       if (!ops->enabled)
+               return true;
+       return ops->enabled(rtg_mount(rtg));
+}
+
+/* Load and existing rtgroup inode into the rtgroup structure. */
+int
+xfs_rtginode_load(
+       struct xfs_rtgroup      *rtg,
+       enum xfs_rtg_inodes     type,
+       struct xfs_trans        *tp)
+{
+       struct xfs_mount        *mp = tp->t_mountp;
+       const char              *path;
+       struct xfs_inode        *ip;
+       const struct xfs_rtginode_ops *ops = &xfs_rtginode_ops[type];
+       int                     error;
+
+       if (!xfs_rtginode_enabled(rtg, type))
+               return 0;
+
+       if (!mp->m_rtdirip)
+               return -EFSCORRUPTED;
+
+       path = xfs_rtginode_path(rtg_rgno(rtg), type);
+       if (!path)
+               return -ENOMEM;
+       error = xfs_metadir_load(tp, mp->m_rtdirip, path, ops->metafile_type,
+                       &ip);
+       kfree(path);
+
+       if (error)
+               return error;
+
+       if (XFS_IS_CORRUPT(mp, ip->i_df.if_format != XFS_DINODE_FMT_EXTENTS &&
+                              ip->i_df.if_format != XFS_DINODE_FMT_BTREE)) {
+               xfs_irele(ip);
+               return -EFSCORRUPTED;
+       }
+
+       if (XFS_IS_CORRUPT(mp, ip->i_projid != rtg_rgno(rtg))) {
+               xfs_irele(ip);
+               return -EFSCORRUPTED;
+       }
+
+       xfs_rtginode_lockdep_setup(ip, rtg_rgno(rtg), type);
+       rtg->rtg_inodes[type] = ip;
+       return 0;
+}
+
+/* Release an rtgroup metadata inode. */
+void
+xfs_rtginode_irele(
+       struct xfs_inode        **ipp)
+{
+       if (*ipp)
+               xfs_irele(*ipp);
+       *ipp = NULL;
+}
+
+/* Create the parent directory for all rtgroup inodes and load it. */
+int
+xfs_rtginode_mkdir_parent(
+       struct xfs_mount        *mp)
+{
+       if (!mp->m_metadirip)
+               return -EFSCORRUPTED;
+
+       return xfs_metadir_mkdir(mp->m_metadirip, "rtgroups", &mp->m_rtdirip);
+}
+
+/* Load the parent directory of all rtgroup inodes. */
+int
+xfs_rtginode_load_parent(
+       struct xfs_trans        *tp)
+{
+       struct xfs_mount        *mp = tp->t_mountp;
+
+       if (!mp->m_metadirip)
+               return -EFSCORRUPTED;
+
+       return xfs_metadir_load(tp, mp->m_metadirip, "rtgroups",
+                       XFS_METAFILE_DIR, &mp->m_rtdirip);
+}
index 7d82eb753fd0972994917898626f3284e77c2732..2c894df723a786019b6ada5ccf93f94a8c77365f 100644 (file)
 struct xfs_mount;
 struct xfs_trans;
 
+enum xfs_rtg_inodes {
+       XFS_RTGI_MAX,
+};
+
+#ifdef MAX_LOCKDEP_SUBCLASSES
+static_assert(XFS_RTGI_MAX <= MAX_LOCKDEP_SUBCLASSES);
+#endif
+
 /*
  * Realtime group incore structure, similar to the per-AG structure.
  */
 struct xfs_rtgroup {
        struct xfs_group        rtg_group;
 
+       /* per-rtgroup metadata inodes */
+       struct xfs_inode        *rtg_inodes[1 /* hack */];
+
        /* Number of blocks in this group */
        xfs_rtxnum_t            rtg_extents;
 };
@@ -210,6 +221,22 @@ void xfs_rtgroup_lock(struct xfs_rtgroup *rtg, unsigned int rtglock_flags);
 void xfs_rtgroup_unlock(struct xfs_rtgroup *rtg, unsigned int rtglock_flags);
 void xfs_rtgroup_trans_join(struct xfs_trans *tp, struct xfs_rtgroup *rtg,
                unsigned int rtglock_flags);
+
+int xfs_rtginode_mkdir_parent(struct xfs_mount *mp);
+int xfs_rtginode_load_parent(struct xfs_trans *tp);
+
+const char *xfs_rtginode_name(enum xfs_rtg_inodes type);
+enum xfs_metafile_type xfs_rtginode_metafile_type(enum xfs_rtg_inodes type);
+bool xfs_rtginode_enabled(struct xfs_rtgroup *rtg, enum xfs_rtg_inodes type);
+int xfs_rtginode_load(struct xfs_rtgroup *rtg, enum xfs_rtg_inodes type,
+               struct xfs_trans *tp);
+void xfs_rtginode_irele(struct xfs_inode **ipp);
+
+static inline const char *xfs_rtginode_path(xfs_rgnumber_t rgno,
+               enum xfs_rtg_inodes type)
+{
+       return kasprintf(GFP_KERNEL, "%u.%s", rgno, xfs_rtginode_name(type));
+}
 #else
 static inline void xfs_free_rtgroups(struct xfs_mount *mp,
                xfs_rgnumber_t first_rgno, xfs_rgnumber_t end_rgno)
index d491e31d33aac3fd9fd92d42b90a730fea7d6cd5..0c90625374a8ee9493a767b594b82898d385cca4 100644 (file)
@@ -128,6 +128,7 @@ typedef struct xfs_mount {
        struct xfs_inode        *m_rsumip;      /* pointer to summary inode */
        struct xfs_inode        *m_rootip;      /* pointer to root directory */
        struct xfs_inode        *m_metadirip;   /* ptr to metadata directory */
+       struct xfs_inode        *m_rtdirip;     /* ptr to realtime metadir */
        struct xfs_quotainfo    *m_quotainfo;   /* disk quota information */
        struct xfs_buftarg      *m_ddev_targp;  /* data device */
        struct xfs_buftarg      *m_logdev_targp;/* log device */
index 917c1a5e8f3180e249ada83cddaccee27f441185..96225313686414c5891fb934e8792bb9a9109c80 100644 (file)
@@ -28,6 +28,7 @@
 #include "xfs_da_format.h"
 #include "xfs_metafile.h"
 #include "xfs_rtgroup.h"
+#include "xfs_error.h"
 
 /*
  * Return whether there are any free extents in the size range given
@@ -652,6 +653,16 @@ xfs_rtallocate_extent_size(
        return -ENOSPC;
 }
 
+static void
+xfs_rtunmount_rtg(
+       struct xfs_rtgroup      *rtg)
+{
+       int                     i;
+
+       for (i = 0; i < XFS_RTGI_MAX; i++)
+               xfs_rtginode_irele(&rtg->rtg_inodes[i]);
+}
+
 static int
 xfs_alloc_rsum_cache(
        struct xfs_mount        *mp,
@@ -1127,6 +1138,43 @@ out_unlock:
        return error;
 }
 
+static void
+xfs_rtgroup_unmount_inodes(
+       struct xfs_mount        *mp)
+{
+       struct xfs_rtgroup      *rtg = NULL;
+
+       while ((rtg = xfs_rtgroup_next(mp, rtg)))
+               xfs_rtunmount_rtg(rtg);
+       xfs_rtginode_irele(&mp->m_rtdirip);
+}
+
+static int
+xfs_rtmount_rtg(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       struct xfs_rtgroup      *rtg)
+{
+       int                     error, i;
+
+       rtg->rtg_extents = xfs_rtgroup_extents(mp, rtg_rgno(rtg));
+
+       for (i = 0; i < XFS_RTGI_MAX; i++) {
+               error = xfs_rtginode_load(rtg, i, tp);
+               if (error)
+                       return error;
+
+               if (rtg->rtg_inodes[i]) {
+                       error = xfs_rtmount_iread_extents(tp,
+                                       rtg->rtg_inodes[i], 0);
+                       if (error)
+                               return error;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * Get the bitmap and summary inodes and the summary cache into the mount
  * structure at mount time.
@@ -1168,15 +1216,28 @@ xfs_rtmount_inodes(
        if (error)
                goto out_rele_summary;
 
-       while ((rtg = xfs_rtgroup_next(mp, rtg)))
-               rtg->rtg_extents = xfs_rtgroup_extents(mp, rtg_rgno(rtg));
+       if (xfs_has_rtgroups(mp) && mp->m_sb.sb_rgcount > 0) {
+               error = xfs_rtginode_load_parent(tp);
+               if (error)
+                       goto out_rele_summary;
+       }
+
+       while ((rtg = xfs_rtgroup_next(mp, rtg))) {
+               error = xfs_rtmount_rtg(mp, tp, rtg);
+               if (error) {
+                       xfs_rtgroup_rele(rtg);
+                       goto out_rele_inodes;
+               }
+       }
 
        error = xfs_alloc_rsum_cache(mp, sbp->sb_rbmblocks);
        if (error)
-               goto out_rele_summary;
+               goto out_rele_inodes;
        xfs_trans_cancel(tp);
        return 0;
 
+out_rele_inodes:
+       xfs_rtgroup_unmount_inodes(mp);
 out_rele_summary:
        xfs_irele(mp->m_rsumip);
 out_rele_bitmap:
@@ -1191,6 +1252,8 @@ xfs_rtunmount_inodes(
        struct xfs_mount        *mp)
 {
        kvfree(mp->m_rsum_cache);
+
+       xfs_rtgroup_unmount_inodes(mp);
        if (mp->m_rbmip)
                xfs_irele(mp->m_rbmip);
        if (mp->m_rsumip)