summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2022-08-12 17:06:16 -0700
committerDarrick J. Wong <djwong@kernel.org>2022-11-09 19:07:57 -0800
commit9a5b1047c38e63dae7b866a9cfff3bde6d5d058c (patch)
tree28ca0f1f7712b30e7bf8f5e6debe23d0a9faa907
parentb2cb1ceb25713528dc54680f3ca693f1df4f8a51 (diff)
xfs: write secondary realtime superblocks to disk
Create some library functions to make it easy to update all the secondary realtime superblocks on disk; this will be used by growfs, xfs_db, mkfs, and xfs_repair. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r--fs/xfs/libxfs/xfs_rtgroup.c117
-rw-r--r--fs/xfs/libxfs/xfs_rtgroup.h2
2 files changed, 119 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_rtgroup.c b/fs/xfs/libxfs/xfs_rtgroup.c
index e9655e699f4f..037506b73384 100644
--- a/fs/xfs/libxfs/xfs_rtgroup.c
+++ b/fs/xfs/libxfs/xfs_rtgroup.c
@@ -382,3 +382,120 @@ xfs_rtgroup_log_super(
xfs_rtgroup_update_super(rtsb_bp, sb_bp);
xfs_trans_ordered_buf(tp, rtsb_bp);
}
+
+/* Initialize a secondary realtime superblock. */
+static int
+xfs_rtgroup_init_secondary_super(
+ struct xfs_mount *mp,
+ xfs_rgnumber_t rgno,
+ struct xfs_buf **bpp)
+{
+ struct xfs_buf *bp;
+ struct xfs_rtsb *rsb;
+ xfs_rtblock_t rtbno;
+ int error;
+
+ ASSERT(rgno != 0);
+
+ error = xfs_buf_get_uncached(mp->m_rtdev_targp, XFS_FSB_TO_BB(mp, 1),
+ 0, &bp);
+ if (error)
+ return error;
+
+ rtbno = xfs_rgbno_to_rtb(mp, rgno, 0);
+ bp->b_maps[0].bm_bn = xfs_rtb_to_daddr(mp, rtbno);
+ bp->b_ops = &xfs_rtsb_buf_ops;
+ xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
+
+ rsb = bp->b_addr;
+ rsb->rsb_magicnum = cpu_to_be32(XFS_RTSB_MAGIC);
+ rsb->rsb_blocksize = cpu_to_be32(mp->m_sb.sb_blocksize);
+ rsb->rsb_rblocks = cpu_to_be64(mp->m_sb.sb_rblocks);
+
+ rsb->rsb_rextents = cpu_to_be64(mp->m_sb.sb_rextents);
+
+ memcpy(&rsb->rsb_uuid, &mp->m_sb.sb_uuid, sizeof(rsb->rsb_uuid));
+
+ rsb->rsb_rgcount = cpu_to_be32(mp->m_sb.sb_rgcount);
+ memcpy(&rsb->rsb_fname, &mp->m_sb.sb_fname, XFSLABEL_MAX);
+
+ rsb->rsb_rextsize = cpu_to_be32(mp->m_sb.sb_rextsize);
+ rsb->rsb_rbmblocks = cpu_to_be32(mp->m_sb.sb_rbmblocks);
+
+ rsb->rsb_rgblocks = cpu_to_be32(mp->m_sb.sb_rgblocks);
+ rsb->rsb_blocklog = mp->m_sb.sb_blocklog;
+ rsb->rsb_sectlog = mp->m_sb.sb_sectlog;
+ rsb->rsb_rextslog = mp->m_sb.sb_rextslog;
+
+ memcpy(&rsb->rsb_meta_uuid, &mp->m_sb.sb_meta_uuid,
+ sizeof(rsb->rsb_meta_uuid));
+
+ *bpp = bp;
+ return 0;
+}
+
+/*
+ * Update all the realtime superblocks to match the new state of the primary.
+ * Because we are completely overwriting all the existing fields in the
+ * secondary superblock buffers, there is no need to read them in from disk.
+ * Just get a new buffer, stamp it and write it.
+ *
+ * The rt super buffers do not need to be kept them in memory once they are
+ * written so we mark them as a one-shot buffer.
+ */
+int
+xfs_rtgroup_update_secondary_sbs(
+ struct xfs_mount *mp)
+{
+ LIST_HEAD (buffer_list);
+ struct xfs_rtgroup *rtg;
+ xfs_rgnumber_t start_rgno = 1;
+ int saved_error = 0;
+ int error = 0;
+
+ for_each_rtgroup_from(mp, start_rgno, rtg) {
+ struct xfs_buf *bp;
+
+ error = xfs_rtgroup_init_secondary_super(mp, rtg->rtg_rgno,
+ &bp);
+ /*
+ * If we get an error reading or writing alternate superblocks,
+ * continue. If we break early, we'll leave more superblocks
+ * un-updated than updated.
+ */
+ if (error) {
+ xfs_warn(mp,
+ "error allocating secondary superblock for rt group %d",
+ rtg->rtg_rgno);
+ if (!saved_error)
+ saved_error = error;
+ continue;
+ }
+
+ xfs_buf_oneshot(bp);
+ xfs_buf_delwri_queue(bp, &buffer_list);
+ xfs_buf_relse(bp);
+
+ /* don't hold too many buffers at once */
+ if (rtg->rtg_rgno % 16)
+ continue;
+
+ error = xfs_buf_delwri_submit(&buffer_list);
+ if (error) {
+ xfs_warn(mp,
+ "write error %d updating a secondary superblock near rt group %u",
+ error, rtg->rtg_rgno);
+ if (!saved_error)
+ saved_error = error;
+ continue;
+ }
+ }
+ error = xfs_buf_delwri_submit(&buffer_list);
+ if (error) {
+ xfs_warn(mp,
+ "write error %d updating a secondary superblock near rt group %u",
+ error, start_rgno);
+ }
+
+ return saved_error ? saved_error : error;
+}
diff --git a/fs/xfs/libxfs/xfs_rtgroup.h b/fs/xfs/libxfs/xfs_rtgroup.h
index c6db6b0d2ae5..d8723fabeb57 100644
--- a/fs/xfs/libxfs/xfs_rtgroup.h
+++ b/fs/xfs/libxfs/xfs_rtgroup.h
@@ -201,10 +201,12 @@ xfs_rgblock_t xfs_rtgroup_block_count(struct xfs_mount *mp,
void xfs_rtgroup_update_super(struct xfs_buf *rtsb_bp,
const struct xfs_buf *sb_bp);
void xfs_rtgroup_log_super(struct xfs_trans *tp, const struct xfs_buf *sb_bp);
+int xfs_rtgroup_update_secondary_sbs(struct xfs_mount *mp);
#else
# define xfs_rtgroup_block_count(mp, rgno) (0)
# define xfs_rtgroup_update_super(bp, sb_bp) ((void)0)
# define xfs_rtgroup_log_super(tp, sb_bp) ((void)0)
+# define xfs_rtgroup_update_secondary_sbs(mp) (0)
#endif /* CONFIG_XFS_RT */
#endif /* __LIBXFS_RTGROUP_H */