@@ -284,6 +284,7 @@
#define xfs_rtsummary_wordcount libxfs_rtsummary_wordcount
#define xfs_rtfree_extent libxfs_rtfree_extent
+#define xfs_rtgroup_get libxfs_rtgroup_get
#define xfs_rtgroup_put libxfs_rtgroup_put
#define xfs_rtgroup_update_secondary_sbs libxfs_rtgroup_update_secondary_sbs
#define xfs_rtgroup_update_super libxfs_rtgroup_update_super
@@ -292,6 +293,8 @@
#define xfs_rtrmapbt_maxlevels_ondisk libxfs_rtrmapbt_maxlevels_ondisk
#define xfs_rtrmapbt_init_cursor libxfs_rtrmapbt_init_cursor
#define xfs_rtrmapbt_maxrecs libxfs_rtrmapbt_maxrecs
+#define xfs_rtrmapbt_mem_create libxfs_rtrmapbt_mem_create
+#define xfs_rtrmapbt_mem_cursor libxfs_rtrmapbt_mem_cursor
#define xfs_sb_from_disk libxfs_sb_from_disk
#define xfs_sb_quota_from_disk libxfs_sb_quota_from_disk
@@ -645,7 +645,7 @@ init_rmapbt_cursor(
/* Compute how many blocks we'll need. */
error = -libxfs_btree_bload_compute_geometry(btr->cur, &btr->bload,
- rmap_record_count(sc->mp, agno));
+ rmap_record_count(sc->mp, false, agno));
if (error)
do_error(
_("Unable to compute rmap btree geometry, error %d.\n"), error);
@@ -662,7 +662,8 @@ build_rmap_tree(
{
int error;
- error = rmap_init_mem_cursor(sc->mp, NULL, agno, &btr->rmapbt_cursor);
+ error = rmap_init_mem_cursor(sc->mp, NULL, false, agno,
+ &btr->rmapbt_cursor);
if (error)
do_error(
_("Insufficient memory to construct rmap cursor.\n"));
@@ -657,7 +657,7 @@ _("illegal state %d in block map %" PRIu64 "\n"),
}
}
if (collect_rmaps && !zap_metadata) /* && !check_dups */
- rmap_add_rec(mp, ino, whichfork, &irec);
+ rmap_add_rec(mp, ino, whichfork, &irec, false);
*tot += irec.br_blockcount;
}
error = 0;
@@ -26,7 +26,7 @@
# define dbg_printf(f, a...)
#endif
-/* per-AG rmap object anchor */
+/* allocation group (AG or rtgroup) rmap object anchor */
struct xfs_ag_rmap {
struct xfbtree *ar_xfbtree; /* rmap observations */
struct xfs_slab *ar_agbtree_rmaps; /* rmaps for rebuilt ag btrees */
@@ -36,9 +36,17 @@ struct xfs_ag_rmap {
};
static struct xfs_ag_rmap *ag_rmaps;
+static struct xfs_ag_rmap *rg_rmaps;
bool rmapbt_suspect;
static bool refcbt_suspect;
+static struct xfs_ag_rmap *rmaps_for_group(bool isrt, unsigned int group)
+{
+ if (isrt)
+ return &rg_rmaps[group];
+ return &ag_rmaps[group];
+}
+
static inline int rmap_compare(const void *a, const void *b)
{
return libxfs_rmap_compare(a, b);
@@ -76,6 +84,44 @@ rmaps_destroy(
xfile_free_buftarg(target);
}
+/* Initialize the in-memory rmap btree for collecting realtime rmap records. */
+STATIC void
+rmaps_init_rt(
+ struct xfs_mount *mp,
+ xfs_rgnumber_t rgno,
+ struct xfs_ag_rmap *ag_rmap)
+{
+ struct xfs_buftarg *target;
+ char *descr;
+ unsigned long long maxbytes;
+ int error;
+
+ if (!xfs_has_realtime(mp))
+ return;
+
+ /*
+ * Each rtgroup rmap btree file can consume the entire data device,
+ * even if the metadata space reservation will be smaller than that.
+ */
+ maxbytes = XFS_FSB_TO_B(mp, mp->m_sb.sb_dblocks);
+ descr = kasprintf("xfs_repair (%s): rtgroup %u rmap records",
+ mp->m_fsname, rgno);
+ error = -xfile_alloc_buftarg(mp, descr, maxbytes, &target);
+ kfree(descr);
+ if (error)
+ goto nomem;
+
+ error = -libxfs_rtrmapbt_mem_create(mp, rgno, target,
+ &ag_rmap->ar_xfbtree);
+ if (error)
+ goto nomem;
+
+ return;
+nomem:
+ do_error(
+_("Insufficient memory while allocating realtime reverse mapping btree."));
+}
+
/* Initialize the in-memory rmap btree for collecting per-AG rmap records. */
STATIC void
rmaps_init_ag(
@@ -135,6 +181,13 @@ rmaps_init(
for (i = 0; i < mp->m_sb.sb_agcount; i++)
rmaps_init_ag(mp, i, &ag_rmaps[i]);
+
+ rg_rmaps = calloc(mp->m_sb.sb_rgcount, sizeof(struct xfs_ag_rmap));
+ if (!rg_rmaps)
+ do_error(_("couldn't allocate per-rtgroup reverse map roots\n"));
+
+ for (i = 0; i < mp->m_sb.sb_rgcount; i++)
+ rmaps_init_rt(mp, i, &rg_rmaps[i]);
}
/*
@@ -149,6 +202,11 @@ rmaps_free(
if (!rmap_needs_work(mp))
return;
+ for (i = 0; i < mp->m_sb.sb_rgcount; i++)
+ rmaps_destroy(mp, &rg_rmaps[i]);
+ free(rg_rmaps);
+ rg_rmaps = NULL;
+
for (i = 0; i < mp->m_sb.sb_agcount; i++)
rmaps_destroy(mp, &ag_rmaps[i]);
free(ag_rmaps);
@@ -184,26 +242,38 @@ int
rmap_init_mem_cursor(
struct xfs_mount *mp,
struct xfs_trans *tp,
+ bool isrt,
xfs_agnumber_t agno,
struct rmap_mem_cur *rmcur)
{
struct xfbtree *xfbt;
- struct xfs_perag *pag;
+ struct xfs_perag *pag = NULL;
+ struct xfs_rtgroup *rtg = NULL;
int error;
- xfbt = ag_rmaps[agno].ar_xfbtree;
+ xfbt = rmaps_for_group(isrt, agno)->ar_xfbtree;
error = -xfbtree_head_read_buf(xfbt, tp, &rmcur->mhead_bp);
if (error)
return error;
- pag = libxfs_perag_get(mp, agno);
- rmcur->mcur = libxfs_rmapbt_mem_cursor(pag, tp, rmcur->mhead_bp, xfbt);
+ if (isrt) {
+ rtg = libxfs_rtgroup_get(mp, agno);
+ rmcur->mcur = libxfs_rtrmapbt_mem_cursor(rtg, tp,
+ rmcur->mhead_bp, xfbt);
+ } else {
+ pag = libxfs_perag_get(mp, agno);
+ rmcur->mcur = libxfs_rmapbt_mem_cursor(pag, tp,
+ rmcur->mhead_bp, xfbt);
+ }
error = -libxfs_btree_goto_left_edge(rmcur->mcur);
if (error)
rmap_free_mem_cursor(tp, rmcur, error);
- libxfs_perag_put(pag);
+ if (pag)
+ libxfs_perag_put(pag);
+ if (rtg)
+ libxfs_rtgroup_put(rtg);
return error;
}
@@ -248,6 +318,7 @@ rmap_get_mem_rec(
static void
rmap_add_mem_rec(
struct xfs_mount *mp,
+ bool isrt,
xfs_agnumber_t agno,
struct xfs_rmap_irec *rmap)
{
@@ -256,12 +327,12 @@ rmap_add_mem_rec(
struct xfs_trans *tp;
int error;
- xfbt = ag_rmaps[agno].ar_xfbtree;
+ xfbt = rmaps_for_group(isrt, agno)->ar_xfbtree;
error = -libxfs_trans_alloc_empty(mp, &tp);
if (error)
do_error(_("allocating tx for in-memory rmap update\n"));
- error = rmap_init_mem_cursor(mp, tp, agno, &rmcur);
+ error = rmap_init_mem_cursor(mp, tp, isrt, agno, &rmcur);
if (error)
do_error(_("reading in-memory rmap btree head\n"));
@@ -286,7 +357,8 @@ rmap_add_rec(
struct xfs_mount *mp,
xfs_ino_t ino,
int whichfork,
- struct xfs_bmbt_irec *irec)
+ struct xfs_bmbt_irec *irec,
+ bool isrt)
{
struct xfs_rmap_irec rmap;
xfs_agnumber_t agno;
@@ -295,11 +367,19 @@ rmap_add_rec(
if (!rmap_needs_work(mp))
return;
- agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock);
- agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock);
- ASSERT(agno != NULLAGNUMBER);
- ASSERT(agno < mp->m_sb.sb_agcount);
- ASSERT(agbno + irec->br_blockcount <= mp->m_sb.sb_agblocks);
+ if (isrt) {
+ xfs_rgnumber_t rgno;
+
+ agbno = xfs_rtb_to_rgbno(mp, irec->br_startblock, &rgno);
+ agno = rgno;
+ ASSERT(agbno + irec->br_blockcount <= mp->m_sb.sb_rblocks);
+ } else {
+ agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock);
+ agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock);
+ ASSERT(agno != NULLAGNUMBER);
+ ASSERT(agno < mp->m_sb.sb_agcount);
+ ASSERT(agbno + irec->br_blockcount <= mp->m_sb.sb_agblocks);
+ }
ASSERT(ino != NULLFSINO);
ASSERT(whichfork == XFS_DATA_FORK || whichfork == XFS_ATTR_FORK);
@@ -313,7 +393,7 @@ rmap_add_rec(
if (irec->br_state == XFS_EXT_UNWRITTEN)
rmap.rm_flags |= XFS_RMAP_UNWRITTEN;
- rmap_add_mem_rec(mp, agno, &rmap);
+ rmap_add_mem_rec(mp, isrt, agno, &rmap);
}
/* add a raw rmap; these will be merged later */
@@ -340,7 +420,7 @@ __rmap_add_raw_rec(
rmap.rm_startblock = agbno;
rmap.rm_blockcount = len;
- rmap_add_mem_rec(mp, agno, &rmap);
+ rmap_add_mem_rec(mp, false, agno, &rmap);
}
/*
@@ -409,6 +489,7 @@ rmap_add_agbtree_mapping(
.rm_blockcount = len,
};
struct xfs_perag *pag;
+ struct xfs_ag_rmap *x;
if (!rmap_needs_work(mp))
return 0;
@@ -417,7 +498,8 @@ rmap_add_agbtree_mapping(
assert(libxfs_verify_agbext(pag, agbno, len));
libxfs_perag_put(pag);
- return slab_add(ag_rmaps[agno].ar_agbtree_rmaps, &rmap);
+ x = rmaps_for_group(false, agno);
+ return slab_add(x->ar_agbtree_rmaps, &rmap);
}
static int
@@ -533,7 +615,7 @@ rmap_commit_agbtree_mappings(
struct xfs_buf *agflbp = NULL;
struct xfs_trans *tp;
__be32 *agfl_bno, *b;
- struct xfs_ag_rmap *ag_rmap = &ag_rmaps[agno];
+ struct xfs_ag_rmap *ag_rmap = rmaps_for_group(false, agno);
struct bitmap *own_ag_bitmap = NULL;
int error = 0;
@@ -796,7 +878,7 @@ refcount_emit(
int error;
struct xfs_slab *rlslab;
- rlslab = ag_rmaps[agno].ar_refcount_items;
+ rlslab = rmaps_for_group(false, agno)->ar_refcount_items;
ASSERT(nr_rmaps > 0);
dbg_printf("REFL: agno=%u pblk=%u, len=%u -> refcount=%zu\n",
@@ -930,12 +1012,12 @@ compute_refcounts(
if (!xfs_has_reflink(mp))
return 0;
- if (ag_rmaps[agno].ar_xfbtree == NULL)
+ if (rmaps_for_group(false, agno)->ar_xfbtree == NULL)
return 0;
- nr_rmaps = rmap_record_count(mp, agno);
+ nr_rmaps = rmap_record_count(mp, false, agno);
- error = rmap_init_mem_cursor(mp, NULL, agno, &rmcur);
+ error = rmap_init_mem_cursor(mp, NULL, false, agno, &rmcur);
if (error)
return error;
@@ -1040,16 +1122,17 @@ count_btree_records(
uint64_t
rmap_record_count(
struct xfs_mount *mp,
+ bool isrt,
xfs_agnumber_t agno)
{
struct rmap_mem_cur rmcur;
uint64_t nr = 0;
int error;
- if (ag_rmaps[agno].ar_xfbtree == NULL)
+ if (rmaps_for_group(isrt, agno)->ar_xfbtree == NULL)
return 0;
- error = rmap_init_mem_cursor(mp, NULL, agno, &rmcur);
+ error = rmap_init_mem_cursor(mp, NULL, isrt, agno, &rmcur);
if (error)
do_error(_("%s while reading in-memory rmap btree\n"),
strerror(error));
@@ -1165,7 +1248,7 @@ rmaps_verify_btree(
}
/* Create cursors to rmap structures */
- error = rmap_init_mem_cursor(mp, NULL, agno, &rm_cur);
+ error = rmap_init_mem_cursor(mp, NULL, false, agno, &rm_cur);
if (error) {
do_warn(_("Not enough memory to check reverse mappings.\n"));
return;
@@ -1485,7 +1568,9 @@ refcount_record_count(
struct xfs_mount *mp,
xfs_agnumber_t agno)
{
- return slab_count(ag_rmaps[agno].ar_refcount_items);
+ struct xfs_ag_rmap *x = rmaps_for_group(false, agno);
+
+ return slab_count(x->ar_refcount_items);
}
/*
@@ -1496,7 +1581,9 @@ init_refcount_cursor(
xfs_agnumber_t agno,
struct xfs_slab_cursor **cur)
{
- return init_slab_cursor(ag_rmaps[agno].ar_refcount_items, NULL, cur);
+ struct xfs_ag_rmap *x = rmaps_for_group(false, agno);
+
+ return init_slab_cursor(x->ar_refcount_items, NULL, cur);
}
/*
@@ -1697,7 +1784,7 @@ rmap_store_agflcount(
if (!rmap_needs_work(mp))
return;
- ag_rmaps[agno].ar_flcount = count;
+ rmaps_for_group(false, agno)->ar_flcount = count;
}
/* Estimate the size of the ondisk rmapbt from the incore data. */
@@ -15,7 +15,7 @@ extern void rmaps_init(struct xfs_mount *);
extern void rmaps_free(struct xfs_mount *);
void rmap_add_rec(struct xfs_mount *mp, xfs_ino_t ino, int whichfork,
- struct xfs_bmbt_irec *irec);
+ struct xfs_bmbt_irec *irec, bool realtime);
void rmap_add_bmbt_rec(struct xfs_mount *mp, xfs_ino_t ino, int whichfork,
xfs_fsblock_t fsbno);
bool rmaps_are_mergeable(struct xfs_rmap_irec *r1, struct xfs_rmap_irec *r2);
@@ -26,7 +26,8 @@ int rmap_add_agbtree_mapping(struct xfs_mount *mp, xfs_agnumber_t agno,
xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner);
int rmap_commit_agbtree_mappings(struct xfs_mount *mp, xfs_agnumber_t agno);
-uint64_t rmap_record_count(struct xfs_mount *mp, xfs_agnumber_t agno);
+uint64_t rmap_record_count(struct xfs_mount *mp, bool isrt,
+ xfs_agnumber_t agno);
extern void rmap_avoid_check(void);
void rmaps_verify_btree(struct xfs_mount *mp, xfs_agnumber_t agno);
@@ -57,7 +58,7 @@ struct rmap_mem_cur {
};
int rmap_init_mem_cursor(struct xfs_mount *mp, struct xfs_trans *tp,
- xfs_agnumber_t agno, struct rmap_mem_cur *rmcur);
+ bool isrt, xfs_agnumber_t agno, struct rmap_mem_cur *rmcur);
void rmap_free_mem_cursor(struct xfs_trans *tp, struct rmap_mem_cur *rmcur,
int error);
int rmap_get_mem_rec(struct rmap_mem_cur *rmcur, struct xfs_rmap_irec *irec);