Make sure there aren't adjacent refcount records that could be merged;
this is a sign that the refcount tree algorithms aren't working
correctly.
Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
---
repair/scan.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/repair/scan.c b/repair/scan.c
index 1c2afb6..d2e588a 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -1195,6 +1195,11 @@ out:
rmap_avoid_check();
}
+struct refc_priv {
+ struct xfs_refcount_irec last_rec;
+};
+
+
static void
scan_refcbt(
struct xfs_btree_block *block,
@@ -1214,6 +1219,7 @@ scan_refcbt(
int numrecs;
int state;
xfs_agblock_t lastblock = 0;
+ struct refc_priv *refc_priv = priv;
if (magic != XFS_REFC_CRC_MAGIC) {
name = "(unknown)";
@@ -1331,6 +1337,20 @@ _("extent (%u/%u) len %u claimed, state is %d\n"),
lastblock = b;
}
+ /* Is this record mergeable with the last one? */
+ if (refc_priv->last_rec.rc_startblock +
+ refc_priv->last_rec.rc_blockcount == b &&
+ refc_priv->last_rec.rc_refcount == nr) {
+ do_warn(
+ _("record %d in block (%u/%u) of %s tree should be merged with previous
record\n"),
+ i, agno, bno, name);
+ refc_priv->last_rec.rc_blockcount += len;
+ } else {
+ refc_priv->last_rec.rc_startblock = b;
+ refc_priv->last_rec.rc_blockcount = len;
+ refc_priv->last_rec.rc_refcount = nr;
+ }
+
/* XXX: probably want to mark the reflinked areas? */
}
goto out;
@@ -2169,10 +2189,13 @@ validate_agf(
if (xfs_sb_version_hasreflink(&mp->m_sb)) {
bno = be32_to_cpu(agf->agf_refcount_root);
if (bno != 0 && verify_agbno(mp, agno, bno)) {
+ struct refc_priv priv;
+
+ memset(&priv, 0, sizeof(priv));
scan_sbtree(bno,
be32_to_cpu(agf->agf_refcount_level),
agno, 0, scan_refcbt, 1, XFS_REFC_CRC_MAGIC,
- agcnts, &xfs_refcountbt_buf_ops);
+ &priv, &xfs_refcountbt_buf_ops);
} else {
do_warn(_("bad agbno %u for refcntbt root, agno %d\n"),
bno, agno);
|