@@ -238,6 +238,8 @@
#define xfs_rtsummary_wordcount libxfs_rtsummary_wordcount
#define xfs_rtfree_extent libxfs_rtfree_extent
+#define xfs_rtgroup_update_secondary_sbs libxfs_rtgroup_update_secondary_sbs
+#define xfs_rtgroup_update_super libxfs_rtgroup_update_super
#define xfs_sb_from_disk libxfs_sb_from_disk
#define xfs_sb_quota_from_disk libxfs_sb_quota_from_disk
#define xfs_sb_read_secondary libxfs_sb_read_secondary
@@ -412,6 +412,8 @@ secondary_sb_whack(
* super byte for byte.
*/
sb->sb_metadirino = mp->m_sb.sb_metadirino;
+ sb->sb_rgblocks = mp->m_sb.sb_rgblocks;
+ sb->sb_rgcount = mp->m_sb.sb_rgcount;
} else
do_warn(
_("would zero unused portion of %s superblock (AG #%u)\n"),
@@ -195,6 +195,25 @@ set_rtbmap(
(((uint64_t) state) << ((rtx % XR_BB_NUM) * XR_BB)));
}
+static void
+rtgroups_init(
+ struct xfs_mount *mp)
+{
+ xfs_rgnumber_t rgno;
+
+ if (!xfs_has_rtgroups(mp) || !rt_bmap)
+ return;
+
+ for (rgno = 0; rgno < mp->m_sb.sb_rgcount; rgno++) {
+ xfs_rtblock_t start_rtx;
+
+ start_rtx = xfs_rgbno_to_rtb(mp, rgno, 0) /
+ mp->m_sb.sb_rextsize;
+
+ set_rtbmap(start_rtx, XR_E_INUSE_FS);
+ }
+}
+
static void
reset_rt_bmap(void)
{
@@ -219,6 +238,8 @@ init_rt_bmap(
mp->m_sb.sb_rextents);
return;
}
+
+ rtgroups_init(mp);
}
static void
@@ -271,6 +292,7 @@ reset_bmaps(xfs_mount_t *mp)
}
reset_rt_bmap();
+ rtgroups_init(mp);
}
void
@@ -17,6 +17,7 @@
#include "progress.h"
#include "bmap.h"
#include "threads.h"
+#include "rt.h"
static void
process_agi_unlinked(
@@ -116,6 +117,8 @@ phase3(
set_progress_msg(PROG_FMT_AGI_UNLINKED, (uint64_t) glob_agcount);
+ check_rtsupers(mp);
+
/* first clear the agi unlinked AGI list */
if (!no_modify) {
for (i = 0; i < mp->m_sb.sb_agcount; i++)
@@ -213,3 +213,72 @@ check_rtsummary(
check_rtfile_contents(mp, "rtsummary", mp->m_sb.sb_rsumino, sumcompute,
XFS_B_TO_FSB(mp, mp->m_rsumsize));
}
+
+void
+check_rtsupers(
+ struct xfs_mount *mp)
+{
+ struct xfs_buf *bp;
+ xfs_rtblock_t rtbno;
+ xfs_rgnumber_t rgno;
+ int error;
+
+ if (!xfs_has_rtgroups(mp))
+ return;
+
+ for (rgno = 0; rgno < mp->m_sb.sb_rgcount; rgno++) {
+ rtbno = xfs_rgbno_to_rtb(mp, rgno, 0);
+ error = -libxfs_buf_read_uncached(mp->m_rtdev_targp,
+ xfs_rtb_to_daddr(mp, rtbno),
+ XFS_FSB_TO_BB(mp, 1), 0, &bp,
+ &xfs_rtsb_buf_ops);
+ if (!error) {
+ libxfs_buf_relse(bp);
+ continue;
+ }
+
+ if (no_modify) {
+ do_warn(
+ _("would rewrite realtime group %u superblock\n"),
+ rgno);
+ } else {
+ do_warn(
+ _("will rewrite realtime group %u superblock\n"),
+ rgno);
+ /*
+ * Rewrite the primary rt superblock before an update
+ * to the primary fs superblock trips over the rt super
+ * being corrupt.
+ */
+ if (rgno == 0)
+ rewrite_primary_rt_super(mp);
+ }
+ }
+}
+
+void
+rewrite_primary_rt_super(
+ struct xfs_mount *mp)
+{
+ struct xfs_buf *rtsb_bp;
+ struct xfs_buf *sb_bp = libxfs_getsb(mp);
+ int error;
+
+ if (!sb_bp)
+ do_error(
+ _("couldn't grab primary sb to update rt superblocks\n"));
+
+ error = -libxfs_buf_get_uncached(mp->m_rtdev_targp,
+ XFS_FSB_TO_BB(mp, 1), 0, &rtsb_bp);
+ if (error)
+ do_error(
+ _("couldn't grab primary rt superblock\n"));
+
+ rtsb_bp->b_maps[0].bm_bn = XFS_RTSB_DADDR;
+ rtsb_bp->b_ops = &xfs_rtsb_buf_ops;
+
+ libxfs_rtgroup_update_super(rtsb_bp, sb_bp);
+ libxfs_buf_mark_dirty(rtsb_bp);
+ libxfs_buf_relse(rtsb_bp);
+ libxfs_buf_relse(sb_bp);
+}
@@ -16,5 +16,8 @@ int generate_rtinfo(struct xfs_mount *mp, union xfs_rtword_ondisk *words,
void check_rtbitmap(struct xfs_mount *mp);
void check_rtsummary(struct xfs_mount *mp);
+void check_rtsupers(struct xfs_mount *mp);
+
+void rewrite_primary_rt_super(struct xfs_mount *mp);
#endif /* _XFS_REPAIR_RT_H_ */
@@ -314,6 +314,37 @@ verify_sb_loginfo(
return true;
}
+static int
+verify_sb_rtgroups(
+ struct xfs_sb *sbp)
+{
+ uint64_t groups;
+
+ if (!(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_METADIR))
+ return XR_BAD_RT_GEO_DATA;
+
+ if (sbp->sb_rgblocks > XFS_MAX_RGBLOCKS)
+ return XR_BAD_RT_GEO_DATA;
+
+ if (sbp->sb_rextsize == 0)
+ return XR_BAD_RT_GEO_DATA;
+
+ if (sbp->sb_rgblocks % sbp->sb_rextsize != 0)
+ return XR_BAD_RT_GEO_DATA;
+
+ if (sbp->sb_rgblocks < (sbp->sb_rextsize << 1))
+ return XR_BAD_RT_GEO_DATA;
+
+ if (sbp->sb_rgcount > XFS_MAX_RGNUMBER)
+ return XR_BAD_RT_GEO_DATA;
+
+ groups = howmany(sbp->sb_rblocks, sbp->sb_rgblocks);
+ if (groups != sbp->sb_rgcount)
+ return XR_BAD_RT_GEO_DATA;
+
+ return 0;
+}
+
/*
* verify a superblock -- does not verify root inode #
* can only check that geometry info is internally
@@ -519,6 +550,12 @@ verify_sb(char *sb_buf, xfs_sb_t *sb, int is_primary_sb)
if (sb->sb_blocklog + sb->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG)
return XR_BAD_DIR_SIZE_DATA;
+ if (sb->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_RTGROUPS) {
+ int err = verify_sb_rtgroups(sb);
+ if (err)
+ return err;
+ }
+
return(XR_OK);
}
@@ -27,6 +27,7 @@
#include "bulkload.h"
#include "quotacheck.h"
#include "rcbag_btree.h"
+#include "rt.h"
/*
* option tables for getsubopt calls
@@ -1510,6 +1511,16 @@ _("Note - stripe unit (%d) and width (%d) were copied from a backup superblock.\
XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR;
}
+ /* Always rewrite the realtime superblocks. */
+ if (xfs_has_rtgroups(mp)) {
+ if (mp->m_sb.sb_rgcount > 0)
+ rewrite_primary_rt_super(mp);
+
+ error = -libxfs_rtgroup_update_secondary_sbs(mp);
+ if (error)
+ do_error(_("updating rt superblocks, err %d"), error);
+ }
+
/*
* Done. Flush all cached buffers and inodes first to ensure all
* verifiers are run (where we discover the max metadata LSN), reformat