]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
mkfs: create the realtime rmap inode
authorDarrick J. Wong <djwong@kernel.org>
Tue, 15 Oct 2024 19:44:41 +0000 (12:44 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Fri, 1 Nov 2024 20:44:59 +0000 (13:44 -0700)
Create a realtime rmapbt inode if we format the fs with realtime
and rmap.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
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 eb573eb528c36b5aea0b3ee110aeef080708f4c0..2a2eff4c220976603074a311e64744136a814807 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_rtgroup_get                        libxfs_rtgroup_get
 #define xfs_rtgroup_put                        libxfs_rtgroup_put
 #define xfs_rtrmapbt_calc_size         libxfs_rtrmapbt_calc_size
+#define xfs_rtrmapbt_calc_reserves     libxfs_rtrmapbt_calc_reserves
 #define xfs_rtrmapbt_commit_staged_btree       libxfs_rtrmapbt_commit_staged_btree
 #define xfs_rtrmapbt_create            libxfs_rtrmapbt_create
 #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 4e9e28d4eea1ca6934ffde9c497db0f502978fe9..54d279f939723c737eadf31887d7fdbbe80e7b67 100644 (file)
@@ -1098,6 +1098,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->rtg_inodes[XFS_RTGI_RMAP],
+                       &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)
@@ -1118,6 +1140,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 c5e6c760c6f77286f876effa6fcc89af6f7644af..4b4a0297ea03cf569133409367ecbbde9e11d5e1 100644 (file)
@@ -2624,12 +2624,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) &&
@@ -4858,6 +4864,75 @@ 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->rtg_inodes[XFS_RTGI_RMAP], 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->rtg_inodes[XFS_RTGI_RMAP]);
+
+       /* 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,
@@ -5194,6 +5269,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
         */