]> www.infradead.org Git - users/hch/misc.git/commitdiff
xfs: grow the realtime section when realtime groups are enabled
authorDarrick J. Wong <djwong@kernel.org>
Wed, 29 May 2024 04:11:14 +0000 (21:11 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 24 Jul 2024 05:33:35 +0000 (22:33 -0700)
Enable growing the rt section when realtime groups are enabled.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
fs/xfs/libxfs/xfs_shared.h
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans.h

index 0343926d2a6b4f9210b39e799cc25ddb55051be5..f9f09174c4218f9bdcfb22fd392954f7c02f437c 100644 (file)
@@ -158,6 +158,7 @@ void        xfs_log_get_max_trans_res(struct xfs_mount *mp,
 #define        XFS_TRANS_SB_RBLOCKS            0x00000800
 #define        XFS_TRANS_SB_REXTENTS           0x00001000
 #define        XFS_TRANS_SB_REXTSLOG           0x00002000
+#define XFS_TRANS_SB_RGCOUNT           0x00004000
 
 /*
  * Here we centralize the specification of XFS meta-data buffer reference count
index 5d56dbcc9b7a0c758108886b9906be3aa82528cb..51de35e5022733c572981fb12d454c5868f27606 100644 (file)
@@ -807,6 +807,72 @@ xfs_alloc_rsum_cache(
  * Visible (exported) functions.
  */
 
+static int
+xfs_growfs_rt_free_new(
+       struct xfs_mount        *mp,
+       struct xfs_rtalloc_args *nargs,
+       xfs_rtbxlen_t           *freed_rtx)
+{
+       struct xfs_mount        *nmp = nargs->mp;
+       struct xfs_sb           *sbp = &mp->m_sb;
+       struct xfs_sb           *nsbp = &nmp->m_sb;
+       xfs_rtxnum_t            start_rtx = sbp->sb_rextents;
+
+       /*
+        * Compute the first new extent that we want to free, being careful to
+        * skip past a realtime superblock at the start of the realtime volume.
+        */
+       if (xfs_has_rtsb(mp) && start_rtx == 0)
+               start_rtx++;
+
+       *freed_rtx = nsbp->sb_rextents - start_rtx;
+       return xfs_rtfree_range(nargs, start_rtx, *freed_rtx);
+}
+
+static int
+xfs_growfs_rt_init_super(
+       struct xfs_mount        *mp)
+{
+       struct xfs_buf          *rtsb_bp;
+       int                     error;
+
+       error = xfs_buf_get_uncached(mp->m_rtdev_targp, XFS_FSB_TO_BB(mp, 1),
+                       0, &rtsb_bp);
+       if (error)
+               return error;
+
+       rtsb_bp->b_maps[0].bm_bn = XFS_RTSB_DADDR;
+       rtsb_bp->b_ops = &xfs_rtsb_buf_ops;
+
+       xfs_rtgroup_update_super(rtsb_bp, mp->m_sb_bp);
+       mp->m_rtsb_bp = rtsb_bp;
+       error = xfs_bwrite(rtsb_bp);
+       xfs_buf_unlock(rtsb_bp);
+       return error;
+}
+
+/* Add rtgroups as needed to deal with this phase of rt expansion. */
+STATIC int
+xfs_growfsrt_alloc_rtgroups(
+       struct xfs_mount        *mp,
+       struct xfs_mount        *nmp)
+{
+       struct xfs_sb           *nsbp = &nmp->m_sb;
+
+       nsbp->sb_rgcount = howmany_64(nsbp->sb_rextents, nsbp->sb_rgextents);
+       return xfs_initialize_rtgroups(mp, nsbp->sb_rgcount);
+}
+
+/* Remove excess rtgroups after a grow failed. */
+STATIC void
+xfs_growfsrt_free_rtgroups(
+       struct xfs_mount        *mp,
+       struct xfs_sb           *nsbp)
+{
+       xfs_free_unused_rtgroup_range(mp, mp->m_sb.sb_rgcount + 1,
+                       nsbp->sb_rgcount);
+}
+
 /*
  * Grow the realtime area of the filesystem.
  */
@@ -897,6 +963,27 @@ xfs_growfs_rt(
         */
        if (nrsumblocks > (mp->m_sb.sb_logblocks >> 1))
                return -EINVAL;
+
+       /*
+        * Allocate the new rt group structures.  Changing the rtgroup size is
+        * not allowed (even if the rt volume hasn't yet been initialized)
+        * because the userspace ABI doesn't support it.
+        */
+       if (xfs_has_rtgroups(mp)) {
+               uint64_t        new_rgcount;
+
+               new_rgcount = howmany_64(nrextents, mp->m_sb.sb_rgextents);
+               if (new_rgcount > XFS_MAX_RGNUMBER)
+                       return -EINVAL;
+       }
+
+       /* Set up the realtime superblock if we're adding a new rt section. */
+       if (xfs_has_rtsb(mp) && mp->m_sb.sb_rblocks == 0) {
+               error = xfs_growfs_rt_init_super(mp);
+               if (error)
+                       return error;
+       }
+
        /*
         * Get the old block counts for bitmap and summary inodes.
         * These can't change since other growfs callers are locked out.
@@ -938,7 +1025,10 @@ xfs_growfs_rt(
                        .mp             = nmp,
                };
                struct xfs_trans        *tp;
+               struct xfs_rtgroup      *rtg;
                xfs_rfsblock_t          nrblocks_step;
+               xfs_rtbxlen_t           freed_rtx = 0;
+               xfs_rgnumber_t          last_rgno = mp->m_sb.sb_rgcount - 1;
 
                *nmp = *mp;
                nsbp = &nmp->m_sb;
@@ -961,6 +1051,12 @@ xfs_growfs_rt(
                /* recompute growfsrt reservation from new rsumsize */
                xfs_trans_resv_calc(nmp, &nmp->m_resv);
 
+               if (xfs_has_rtgroups(mp)) {
+                       error = xfs_growfsrt_alloc_rtgroups(mp, nmp);
+                       if (error)
+                               goto out_free;
+               }
+
                /*
                 * Start a transaction, get the log reservation.
                 */
@@ -1003,6 +1099,7 @@ xfs_growfs_rt(
                        if (error)
                                goto error_cancel;
                }
+
                /*
                 * Update superblock fields.
                 */
@@ -1021,11 +1118,14 @@ xfs_growfs_rt(
                if (nsbp->sb_rextslog != sbp->sb_rextslog)
                        xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSLOG,
                                nsbp->sb_rextslog - sbp->sb_rextslog);
+               if (nsbp->sb_rgcount != sbp->sb_rgcount)
+                       xfs_trans_mod_sb(tp, XFS_TRANS_SB_RGCOUNT,
+                               nsbp->sb_rgcount - sbp->sb_rgcount);
+
                /*
                 * Free new extent.
                 */
-               error = xfs_rtfree_range(&nargs, sbp->sb_rextents,
-                               nsbp->sb_rextents - sbp->sb_rextents);
+               error = xfs_growfs_rt_free_new(mp, &nargs, &freed_rtx);
                xfs_rtbuf_cache_relse(&nargs);
                if (error) {
 error_cancel:
@@ -1035,8 +1135,7 @@ error_cancel:
                /*
                 * Mark more blocks free in the superblock.
                 */
-               xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS,
-                       nsbp->sb_rextents - sbp->sb_rextents);
+               xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, freed_rtx);
                /*
                 * Update mp values into the real mp structure.
                 */
@@ -1049,11 +1148,18 @@ error_cancel:
                if (error)
                        break;
 
+               for_each_rtgroup_from(mp, last_rgno, rtg)
+                       rtg->rtg_blockcount = xfs_rtgroup_block_count(mp,
+                                                               rtg->rtg_rgno);
+
                /* Ensure the mount RT feature flag is now set. */
                mp->m_features |= XFS_FEAT_REALTIME;
        }
-       if (error)
+       if (error) {
+               if (xfs_has_rtgroups(mp))
+                       xfs_growfsrt_free_rtgroups(mp, nsbp);
                goto out_free;
+       }
 
        /* Update secondary superblocks now the physical grow has completed */
        error = xfs_update_secondary_sbs(mp);
index 5fd1765b3dcd8726856a288af1b2125aa4191ec0..c130cfd8b0028769bba4f5474652778e92f558c1 100644 (file)
@@ -456,6 +456,10 @@ xfs_trans_mod_sb(
        case XFS_TRANS_SB_REXTSLOG:
                tp->t_rextslog_delta += delta;
                break;
+       case XFS_TRANS_SB_RGCOUNT:
+               ASSERT(delta > 0);
+               tp->t_rgcount_delta += delta;
+               break;
        default:
                ASSERT(0);
                return;
@@ -555,6 +559,10 @@ xfs_trans_apply_sb_deltas(
                sbp->sb_rextslog += tp->t_rextslog_delta;
                whole = 1;
        }
+       if (tp->t_rgcount_delta) {
+               be32_add_cpu(&sbp->sb_rgcount, tp->t_rgcount_delta);
+               whole = 1;
+       }
 
        xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF);
        if (whole)
@@ -669,6 +677,7 @@ xfs_trans_unreserve_and_mod_sb(
        mp->m_sb.sb_rblocks += tp->t_rblocks_delta;
        mp->m_sb.sb_rextents += tp->t_rextents_delta;
        mp->m_sb.sb_rextslog += tp->t_rextslog_delta;
+       mp->m_sb.sb_rgcount += tp->t_rgcount_delta;
        spin_unlock(&mp->m_sb_lock);
 
        /*
index f97e5c416efad126dd2f5056384d564f2f284b4d..71c2e82e4dadfffc632db9b10cde6859dbf8b9fd 100644 (file)
@@ -148,6 +148,7 @@ typedef struct xfs_trans {
        int64_t                 t_rblocks_delta;/* superblock rblocks change */
        int64_t                 t_rextents_delta;/* superblocks rextents chg */
        int64_t                 t_rextslog_delta;/* superblocks rextslog chg */
+       int64_t                 t_rgcount_delta; /* realtime group count */
        struct list_head        t_items;        /* log item descriptors */
        struct list_head        t_busy;         /* list of busy extents */
        struct list_head        t_dfops;        /* deferred operations */