]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
mkfs: create the realtime rmap inode
authorDarrick J. Wong <djwong@kernel.org>
Mon, 24 Feb 2025 18:22:02 +0000 (10:22 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 25 Feb 2025 17:16:01 +0000 (09:16 -0800)
Create a realtime rmapbt inode if we format the fs with realtime
and rmap.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
libxfs/init.c
libxfs/libxfs_api_defs.h
mkfs/proto.c
mkfs/xfs_mkfs.c

index 02a4cfdf38b198f03ea9b3c701b9e3a96029dfbe..f92805620c33f1e990ef14f60e0fd39b07632324 100644 (file)
@@ -312,13 +312,6 @@ rtmount_init(
                return -1;
        }
 
-       if (xfs_has_rmapbt(mp)) {
-               fprintf(stderr,
-       _("%s: Reverse mapping btree not compatible with realtime device. Please try a newer xfsprogs.\n"),
-                               progname);
-               return -1;
-       }
-
        if (mp->m_rtdev_targp->bt_bdev == 0 && !xfs_is_debugger(mp)) {
                fprintf(stderr, _("%s: filesystem has a realtime subvolume\n"),
                        progname);
index 193b1eeaa7537e8f211869c9c8a63c951b544578..df24f36f0d2874a22bccc0098ff5a4b37b70df90 100644 (file)
 
 #define xfs_metafile_iget              libxfs_metafile_iget
 #define xfs_trans_metafile_iget                libxfs_trans_metafile_iget
+#define xfs_metafile_resv_free         libxfs_metafile_resv_free
+#define xfs_metafile_resv_init         libxfs_metafile_resv_init
 #define xfs_metafile_set_iflag         libxfs_metafile_set_iflag
 #define xfs_metadir_cancel             libxfs_metadir_cancel
 #define xfs_metadir_commit             libxfs_metadir_commit
 #define xfs_rtrmapbt_droot_maxrecs     libxfs_rtrmapbt_droot_maxrecs
 #define xfs_rtrmapbt_maxlevels_ondisk  libxfs_rtrmapbt_maxlevels_ondisk
 #define xfs_rtrmapbt_init_cursor       libxfs_rtrmapbt_init_cursor
+#define xfs_rtrmapbt_init_rtsb         libxfs_rtrmapbt_init_rtsb
 #define xfs_rtrmapbt_maxrecs           libxfs_rtrmapbt_maxrecs
 #define xfs_rtrmapbt_mem_init          libxfs_rtrmapbt_mem_init
 #define xfs_rtrmapbt_mem_cursor                libxfs_rtrmapbt_mem_cursor
index 60e5c7d02713d0c1c0ccc6b47fb7255b3a8d844c..2c45348027166689f1b2fd10c5d059bc40a92a36 100644 (file)
@@ -1095,6 +1095,28 @@ rtinit_nogroups(
        }
 }
 
+static int
+init_rtrmap_for_rtsb(
+       struct xfs_rtgroup      *rtg)
+{
+       struct xfs_mount        *mp = rtg_mount(rtg);
+       struct xfs_trans        *tp;
+       int                     error;
+
+       error = -libxfs_trans_alloc_inode(rtg_rmap(rtg),
+                       &M_RES(mp)->tr_itruncate, 0, 0, false, &tp);
+       if (error)
+               return error;
+
+       error = -libxfs_rtrmapbt_init_rtsb(mp, rtg, tp);
+       if (error) {
+               libxfs_trans_cancel(tp);
+               return error;
+       }
+
+       return -libxfs_trans_commit(tp);
+}
+
 static void
 rtinit_groups(
        struct xfs_mount        *mp)
@@ -1115,6 +1137,13 @@ rtinit_groups(
                                                error);
                }
 
+               if (xfs_has_rtsb(mp) && xfs_has_rtrmapbt(mp) &&
+                   rtg_rgno(rtg) == 0) {
+                       error = init_rtrmap_for_rtsb(rtg);
+                       if (error)
+                               fail(_("rtrmap rtsb init failed"), error);
+               }
+
                rtfreesp_init(rtg);
        }
 }
index 86bc9865b1071e34eaa7ca37253035515d7cbabc..da83fb36a2438d91361fa64ab8db226fc87f0f7f 100644 (file)
@@ -2678,12 +2678,18 @@ _("reflink not supported with realtime devices\n"));
                }
                cli->sb_feat.reflink = false;
 
-               if (cli->sb_feat.rmapbt && cli_opt_set(&mopts, M_RMAPBT)) {
-                       fprintf(stderr,
-_("rmapbt not supported with realtime devices\n"));
-                       usage();
+               if (!cli->sb_feat.metadir && cli->sb_feat.rmapbt) {
+                       if (cli_opt_set(&mopts, M_RMAPBT) &&
+                           cli_opt_set(&mopts, M_METADIR)) {
+                               fprintf(stderr,
+_("rmapbt not supported on realtime devices without metadir feature\n"));
+                               usage();
+                       } else if (cli_opt_set(&mopts, M_RMAPBT)) {
+                               cli->sb_feat.metadir = true;
+                       } else {
+                               cli->sb_feat.rmapbt = false;
+                       }
                }
-               cli->sb_feat.rmapbt = false;
        }
 
        if ((cli->fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE) &&
@@ -5005,6 +5011,74 @@ write_rtsb(
        libxfs_buf_relse(sb_bp);
 }
 
+static inline void
+prealloc_fail(
+       struct xfs_mount        *mp,
+       int                     error,
+       xfs_filblks_t           ask,
+       const char              *tag)
+{
+       if (error == ENOSPC)
+               fprintf(stderr,
+       _("%s: cannot handle expansion of %s; need %llu free blocks, have %llu\n"),
+                               progname, tag, (unsigned long long)ask,
+                               (unsigned long long)mp->m_sb.sb_fdblocks);
+       else
+               fprintf(stderr,
+       _("%s: error %d while checking free space for %s\n"),
+                               progname, error, tag);
+       exit(1);
+}
+
+/*
+ * Make sure there's enough space on the data device to handle realtime
+ * metadata btree expansions.
+ */
+static void
+check_rt_meta_prealloc(
+       struct xfs_mount        *mp)
+{
+       struct xfs_perag        *pag = NULL;
+       struct xfs_rtgroup      *rtg = NULL;
+       xfs_filblks_t           ask;
+       int                     error;
+
+       /*
+        * First create all the per-AG reservations, since they take from the
+        * free block count.  Each AG should start with enough free space for
+        * the per-AG reservation.
+        */
+       mp->m_finobt_nores = false;
+
+       while ((pag = xfs_perag_next(mp, pag))) {
+               error = -libxfs_ag_resv_init(pag, NULL);
+               if (error && error != ENOSPC) {
+                       fprintf(stderr,
+       _("%s: error %d while checking AG free space for realtime metadata\n"),
+                                       progname, error);
+                       exit(1);
+               }
+       }
+
+       /* Realtime metadata btree inode */
+       while ((rtg = xfs_rtgroup_next(mp, rtg))) {
+               ask = libxfs_rtrmapbt_calc_reserves(mp);
+               error = -libxfs_metafile_resv_init(rtg_rmap(rtg), ask);
+               if (error)
+                       prealloc_fail(mp, error, ask, _("realtime rmap btree"));
+       }
+
+       /* Unreserve the realtime metadata reservations. */
+       while ((rtg = xfs_rtgroup_next(mp, rtg)))
+               libxfs_metafile_resv_free(rtg_rmap(rtg));
+
+       /* Unreserve the per-AG reservations. */
+       while ((pag = xfs_perag_next(mp, pag)))
+               libxfs_ag_resv_free(pag);
+
+       mp->m_finobt_nores = false;
+}
+
 int
 main(
        int                     argc,
@@ -5342,6 +5416,9 @@ main(
         */
        check_root_ino(mp);
 
+       /* Make sure we can handle space preallocations of rt metadata btrees */
+       check_rt_meta_prealloc(mp);
+
        /*
         * Re-write multiple secondary superblocks with rootinode field set
         */