]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
mkfs: create the realtime rmap inode
authorDarrick J. Wong <djwong@kernel.org>
Tue, 9 Jan 2024 17:40:22 +0000 (09:40 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 10 Apr 2024 00:21:45 +0000 (17:21 -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
mkfs/proto.c
mkfs/xfs_mkfs.c

index 117a1608d732a0ab6e7d3862d6e642e0b93abff1..f8a58b71b5f93fdd31144ff84d890b568ae928a4 100644 (file)
@@ -308,13 +308,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 2d661984947a6a8b562ebe985fa289764ab6894f..4eea8cfa6e1819f70af645b06e3deda64a4b15da 100644 (file)
@@ -855,6 +855,54 @@ rtsummary_create(
        mp->m_rsumip = rsumip;
 }
 
+/* Create the realtime rmap btree inode. */
+static void
+rtrmapbt_create(
+       struct xfs_rtgroup      *rtg)
+{
+       struct xfs_imeta_update upd;
+       struct xfs_rmap_irec    rmap = {
+               .rm_startblock  = 0,
+               .rm_blockcount  = rtg->rtg_mount->m_sb.sb_rextsize,
+               .rm_owner       = XFS_RMAP_OWN_FS,
+               .rm_offset      = 0,
+               .rm_flags       = 0,
+       };
+       struct xfs_mount        *mp = rtg->rtg_mount;
+       struct xfs_imeta_path   *path;
+       struct xfs_btree_cur    *cur;
+       int                     error;
+
+       error = -libxfs_rtrmapbt_create_path(mp, rtg->rtg_rgno, &path);
+       if (error)
+               fail( _("rtrmap inode path creation failed"), error);
+
+       error = -libxfs_imeta_ensure_dirpath(mp, path);
+       if (error)
+               fail(_("rtgroup directory allocation failed"), error);
+
+       error = -libxfs_imeta_start_create(mp, path, &upd);
+       if (error)
+               res_failed(error);
+
+       error = -libxfs_rtrmapbt_create(&upd, &rtg->rtg_rmapip);
+       if (error)
+               fail(_("rtrmap inode creation failed"), error);
+
+       /* Adding an rmap for the rtgroup super should fit in the data fork */
+       cur = libxfs_rtrmapbt_init_cursor(mp, upd.tp, rtg, rtg->rtg_rmapip);
+       error = -libxfs_rmap_map_raw(cur, &rmap);
+       libxfs_btree_del_cursor(cur, error);
+       if (error)
+               fail(_("rtrmapbt initialization failed"), error);
+
+       error = -libxfs_imeta_commit_update(&upd);
+       if (error)
+               fail(_("rtrmapbt commit failed"), error);
+
+       libxfs_imeta_free_path(path);
+}
+
 /* Initialize block headers of rt free space files. */
 static int
 init_rtblock_headers(
@@ -1087,9 +1135,17 @@ static void
 rtinit(
        struct xfs_mount        *mp)
 {
+       struct xfs_rtgroup      *rtg;
+       xfs_rgnumber_t          rgno;
+
        rtbitmap_create(mp);
        rtsummary_create(mp);
 
+       for_each_rtgroup(mp, rgno, rtg) {
+               if (xfs_has_rtrmapbt(mp))
+                       rtrmapbt_create(rtg);
+       }
+
        rtbitmap_init(mp);
        rtsummary_init(mp);
        if (xfs_has_rtgroups(mp))
index f10d6fd3d6fc936ac9d3e9c147c5c4e09471f036..8676579ecfabbb4a264002bcdea51e89ab239f17 100644 (file)
@@ -2489,12 +2489,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.rtgroups && cli->sb_feat.rmapbt) {
+                       if (cli_opt_set(&mopts, M_RMAPBT) &&
+                           cli_opt_set(&ropts, R_RTGROUPS)) {
+                               fprintf(stderr,
+_("rmapbt not supported on realtime devices without rtgroups feature\n"));
+                               usage();
+                       } else if (cli_opt_set(&mopts, M_RMAPBT)) {
+                               cli->sb_feat.rtgroups = true;
+                       } else {
+                               cli->sb_feat.rmapbt = false;
+                       }
                }
-               cli->sb_feat.rmapbt = false;
        }
 
        if ((cli->fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE) &&
@@ -4588,6 +4594,77 @@ cfgfile_parse(
                cli->cfgfile);
 }
 
+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;
+       struct xfs_rtgroup      *rtg;
+       xfs_agnumber_t          agno;
+       xfs_rgnumber_t          rgno;
+       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;
+
+       for_each_perag(mp, agno, 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 */
+       for_each_rtgroup(mp, rgno, rtg) {
+               ask = libxfs_rtrmapbt_calc_reserves(mp);
+               error = -libxfs_imeta_resv_init_inode(rtg->rtg_rmapip, ask);
+               if (error)
+                       prealloc_fail(mp, error, ask, _("realtime rmap btree"));
+       }
+
+       /* Unreserve the realtime metadata reservations. */
+       for_each_rtgroup(mp, rgno, rtg) {
+               libxfs_imeta_resv_free_inode(rtg->rtg_rmapip);
+       }
+
+       /* Unreserve the per-AG reservations. */
+       for_each_perag(mp, agno, pag)
+               libxfs_ag_resv_free(pag);
+
+       mp->m_finobt_nores = false;
+}
+
 int
 main(
        int                     argc,
@@ -4957,6 +5034,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
         */