]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
mkfs: create the realtime rmap inode
authorDarrick J. Wong <djwong@kernel.org>
Fri, 15 Jul 2022 21:27:26 +0000 (14:27 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 22 Nov 2023 23:03:40 +0000 (15:03 -0800)
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 8bd3c588eb4ef09fae6cc85516f094884cd6c494..b6a37bc552ae9ade6f53211be5247b66aac6ac4c 100644 (file)
@@ -462,13 +462,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 5239f9ec413cd9614b1662f812fd5483d8e050bb..d575d9c511e9cab96a803704f85bdd94f336b0e8 100644 (file)
@@ -852,6 +852,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(
@@ -1084,9 +1132,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 2d587ca5bfd6ffd91b8a65dd371f5dd35cada417..1ced02fbc40511458992d3c9e80b1d08e16ca0c0 100644 (file)
@@ -2486,12 +2486,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) &&
@@ -4597,6 +4603,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,
@@ -4972,6 +5049,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
         */