summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2022-08-11 16:45:25 -0700
committerDarrick J. Wong <djwong@kernel.org>2022-10-14 14:17:09 -0700
commit922007c3e02f245e6226880c1c420292d9bb18d8 (patch)
tree84fc5bb45f6307c0433f3b05d497544ba9853ee3 /fs
parente274ca3b440a4b50db89a44a560e5ef9c9b25818 (diff)
xfs: grow the realtime section when realtime groups are enabled
Enable growing the rt section when realtime groups are enabled. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/libxfs/xfs_shared.h1
-rw-r--r--fs/xfs/xfs_rtalloc.c139
-rw-r--r--fs/xfs/xfs_trans.c10
-rw-r--r--fs/xfs/xfs_trans.h1
4 files changed, 145 insertions, 6 deletions
diff --git a/fs/xfs/libxfs/xfs_shared.h b/fs/xfs/libxfs/xfs_shared.h
index b9c19a3fe1ef..556903c0a2fc 100644
--- a/fs/xfs/libxfs/xfs_shared.h
+++ b/fs/xfs/libxfs/xfs_shared.h
@@ -102,6 +102,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
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index 9c842237c452..9d8d91fa0ecf 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -930,6 +930,92 @@ xfs_alloc_rsum_cache(
* Visible (exported) functions.
*/
+static int
+xfs_growfs_rt_free_new(
+ struct xfs_trans *tp,
+ struct xfs_mount *nmp,
+ xfs_rtbxlen_t *freed_rtx)
+{
+ struct xfs_mount *mp = tp->t_mountp;
+ struct xfs_sb *sbp = &mp->m_sb;
+ struct xfs_sb *nsbp = &nmp->m_sb;
+ struct xfs_buf *bp = NULL;
+ xfs_fileoff_t sumbno;
+ xfs_rtblock_t rtbno, next_rtbno;
+ int error = 0;
+
+ if (!xfs_has_rtgroups(mp)) {
+ *freed_rtx = nsbp->sb_rextents - sbp->sb_rextents;
+ return xfs_rtfree_range(nmp, tp, sbp->sb_rextents, *freed_rtx,
+ &bp, &sumbno);
+ }
+
+ *freed_rtx = 0;
+
+ rtbno = xfs_rtx_to_rtb(nmp, sbp->sb_rextents);
+ next_rtbno = xfs_rtx_to_rtb(nmp, nsbp->sb_rextents);
+ while (rtbno < next_rtbno) {
+ xfs_rtxnum_t start_rtx, next_rtx;
+ xfs_rtblock_t next_free_rtbno;
+ xfs_rgnumber_t rgno;
+ xfs_rgblock_t rgbno;
+
+ /*
+ * Compute the first new extent that we want to free, being
+ * careful to skip past a realtime superblock at the start of
+ * the new region.
+ */
+ rgbno = xfs_rtb_to_rgbno(nmp, rtbno, &rgno);
+ if (rgbno == 0) {
+ rtbno += nsbp->sb_rextsize;
+ if (rtbno >= next_rtbno)
+ break;
+ }
+
+ start_rtx = xfs_rtb_to_rtxt(nmp, rtbno);
+
+ /*
+ * Stop freeing either at the end of the new rt section or at
+ * the start of the next realtime group.
+ */
+ next_free_rtbno = xfs_rgbno_to_rtb(nmp, rgno + 1, 0);
+ next_rtx = xfs_rtb_to_rtxt(nmp, next_free_rtbno);
+ next_rtx = min(next_rtx, nsbp->sb_rextents);
+
+ bp = NULL;
+ *freed_rtx += next_rtx - start_rtx;
+ error = xfs_rtfree_range(nmp, tp, start_rtx,
+ next_rtx - start_rtx, &bp, &sumbno);
+ if (error)
+ break;
+
+ rtbno = next_free_rtbno;
+ }
+
+ return error;
+}
+
+static int
+xfs_growfs_rt_init_primary(
+ 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;
+ xfs_buf_unlock(rtsb_bp);
+ return 0;
+}
+
/*
* Grow the realtime area of the filesystem.
*/
@@ -953,8 +1039,8 @@ xfs_growfs_rt(
xfs_extlen_t rbmblocks; /* current number of rt bitmap blocks */
xfs_extlen_t rsumblocks; /* current number of rt summary blks */
xfs_sb_t *sbp; /* old superblock */
- xfs_fileoff_t sumbno; /* summary block number */
uint8_t *rsum_cache; /* old summary cache */
+ xfs_rgnumber_t new_rgcount = 0;
sbp = &mp->m_sb;
@@ -1019,6 +1105,30 @@ xfs_growfs_rt(
*/
if (nrsumblocks > (mp->m_sb.sb_logblocks >> 1))
return -EINVAL;
+
+ /* Allocate the new rt group structures */
+ if (xfs_has_rtgroups(mp)) {
+ /*
+ * We don't support changing the group size to match the extent
+ * size, even if the size of the rt section is currently zero.
+ */
+ if (mp->m_sb.sb_rgblocks % in->extsize != 0)
+ return -EOPNOTSUPP;
+
+ if (mp->m_sb.sb_rblocks == 0) {
+ error = xfs_growfs_rt_init_primary(mp);
+ if (error)
+ return error;
+ }
+
+ new_rgcount = howmany_64(nrblocks, mp->m_sb.sb_rgblocks);
+ if (new_rgcount > mp->m_sb.sb_rgcount) {
+ error = xfs_initialize_rtgroups(mp, new_rgcount);
+ 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.
@@ -1054,7 +1164,10 @@ xfs_growfs_rt(
bmbno < nrbmblocks;
bmbno++) {
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;
@@ -1074,6 +1187,11 @@ xfs_growfs_rt(
nrsumblocks = xfs_rtsummary_blockcount(mp, nrsumlevels,
nsbp->sb_rbmblocks);
nmp->m_rsumsize = nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);
+
+ if (xfs_has_rtgroups(mp))
+ nsbp->sb_rgcount = howmany_64(nsbp->sb_rblocks,
+ nsbp->sb_rgblocks);
+
/*
* Start a transaction, get the log reservation.
*/
@@ -1113,6 +1231,7 @@ xfs_growfs_rt(
if (error)
goto error_cancel;
}
+
/*
* Update superblock fields.
*/
@@ -1131,12 +1250,13 @@ 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.
*/
- bp = NULL;
- error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents,
- nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno);
+ error = xfs_growfs_rt_free_new(tp, nmp, &freed_rtx);
if (error) {
error_cancel:
xfs_trans_cancel(tp);
@@ -1145,8 +1265,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.
*/
@@ -1157,6 +1276,10 @@ 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;
}
@@ -1165,6 +1288,10 @@ error_cancel:
/* Update secondary superblocks now the physical grow has completed */
error = xfs_update_secondary_sbs(mp);
+ if (error)
+ goto out_free;
+
+ error = xfs_rtgroup_update_secondary_sbs(mp);
out_free:
/*
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 979aba1b2fc8..a6f46cd9e60c 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -510,6 +510,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;
@@ -615,6 +619,11 @@ xfs_trans_apply_sb_deltas(
whole = 1;
update_rtsb = true;
}
+ if (tp->t_rgcount_delta) {
+ be32_add_cpu(&sbp->sb_rgcount, tp->t_rgcount_delta);
+ whole = 1;
+ update_rtsb = true;
+ }
xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF);
if (whole)
@@ -728,6 +737,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);
/*
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 37cde68f3a31..efa7eace0859 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -150,6 +150,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 */