Check the observed reference counts against whatever's in the reflink
btree for discrepancies.
Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
---
repair/phase4.c | 20 ++++++++++
repair/rmap.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
repair/rmap.h | 6 +++
3 files changed, 139 insertions(+)
diff --git a/repair/phase4.c b/repair/phase4.c
index 64627a5..9577e34 100644
--- a/repair/phase4.c
+++ b/repair/phase4.c
@@ -188,6 +188,21 @@ _("%s while fixing inode reflink flags.\n"),
}
static void
+check_reflink_btrees(
+ work_queue_t *wq,
+ xfs_agnumber_t agno,
+ void *arg)
+{
+ int error;
+
+ error = reflink_check_refcounts(wq->mp, agno);
+ if (error)
+ do_error(
+_("%s while checking reference counts"),
+ strerror(-error));
+}
+
+static void
process_rmaps(
xfs_mount_t *mp)
{
@@ -210,6 +225,11 @@ process_rmaps(
for (i = 0; i < mp->m_sb.sb_agcount; i++)
queue_work(&wq, process_inode_reflink_flags, i, NULL);
destroy_work_queue(&wq);
+
+ create_work_queue(&wq, mp, libxfs_nproc());
+ for (i = 0; i < mp->m_sb.sb_agcount; i++)
+ queue_work(&wq, check_reflink_btrees, i, NULL);
+ destroy_work_queue(&wq);
}
void
diff --git a/repair/rmap.c b/repair/rmap.c
index cc34570..6c6d5ae 100644
--- a/repair/rmap.c
+++ b/repair/rmap.c
@@ -614,3 +614,116 @@ _("Unable to fix reflink flag on inode %"PRIu64".\n"),
return error;
}
+
+/**
+ * reflink_count() -- Return the number of reflink objects for an AG.
+ */
+size_t
+reflink_count(
+ xfs_mount_t *mp,
+ xfs_agnumber_t agno)
+{
+ return slab_count(ag_rmaps[agno].ar_reflink_items);
+}
+
+/**
+ * init_reflink_cursor() -- Return a slab cursor that will return reflink
+ * objects in order.
+ * @agno: AG number.
+ * @cur: The new cursor.
+ */
+int
+init_reflink_cursor(
+ xfs_agnumber_t agno,
+ xfs_slab_cursor_t **cur)
+{
+ return init_slab_cursor(ag_rmaps[agno].ar_reflink_items, NULL, cur);
+}
+
+/**
+ * reflink_check_refcounts() -- Compare the observed reference counts against
+ * what's in the ag btree.
+ * @mp: XFS mount object
+ * @agno: AG number
+ */
+int
+reflink_check_refcounts(
+ xfs_mount_t *mp,
+ xfs_agnumber_t agno)
+{
+ xfs_slab_cursor_t *rl_cur;
+ struct xfs_btree_cur *bt_cur = NULL;
+ int error;
+ int have;
+ int i;
+ struct xfs_buf *agbp = NULL;
+ xfs_agblock_t lbno;
+ xfs_extlen_t llen;
+ xfs_nlink_t lnr;
+ xfs_reflink_rec_incore_t *rl_rec;
+
+ if (!xfs_sb_version_hasreflink(&mp->m_sb))
+ return 0;
+
+ /* Create cursors to refcount structures */
+ error = init_reflink_cursor(agno, &rl_cur);
+ if (error)
+ return error;
+
+ error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
+ if (error)
+ goto err;
+
+ bt_cur = xfs_reflinkbt_init_cursor(mp, NULL, agbp, agno);
+ if (!bt_cur) {
+ error = -ENOMEM;
+ goto err;
+ }
+
+ rl_rec = pop_slab_cursor(rl_cur);
+ while (rl_rec) {
+ /* Look for a refcount record in the btree */
+ error = xfs_reflink_lookup_le(bt_cur,
+ rl_rec->rr_startblock, &have);
+ if (error)
+ goto err;
+ if (!have) {
+ do_warn(
+_("Missing reference count record for (%u/%u) len %u count %u\n"),
+ agno, rl_rec->rr_startblock,
+ rl_rec->rr_blockcount, rl_rec->rr_nlinks);
+ goto next_loop;
+ }
+
+ error = xfs_reflink_get_rec(bt_cur, &lbno, &llen, &lnr, &i);
+ if (error)
+ goto err;
+ if (!i) {
+ do_warn(
+_("Missing reference count record for (%u/%u) len %u count %u\n"),
+ agno, rl_rec->rr_startblock,
+ rl_rec->rr_blockcount, rl_rec->rr_nlinks);
+ goto next_loop;
+ }
+
+ /* Compare each refcount observation against the btree's */
+ if (lbno != rl_rec->rr_startblock ||
+ llen < rl_rec->rr_blockcount ||
+ lnr < rl_rec->rr_nlinks)
+ do_warn(
+_("Incorrect reference count: saw (%u/%u) len %u nlinks %u; should be (%u/%u)
len %u nlinks %u\n"),
+ agno, lbno, llen, lnr,
+ agno, rl_rec->rr_startblock,
+ rl_rec->rr_blockcount, rl_rec->rr_nlinks);
+next_loop:
+ rl_rec = pop_slab_cursor(rl_cur);
+ }
+
+err:
+ if (bt_cur)
+ xfs_btree_del_cursor(bt_cur, XFS_BTREE_NOERROR);
+ if (agbp)
+ libxfs_putbuf(agbp);
+ free_slab_cursor(&rl_cur);
+ return 0;
+}
diff --git a/repair/rmap.h b/repair/rmap.h
index 7dc709f..efb24cd 100644
--- a/repair/rmap.h
+++ b/repair/rmap.h
@@ -35,4 +35,10 @@ extern int reflink_fix_inode_flags(xfs_mount_t *mp,
xfs_agnumber_t agno);
extern int rebuild_ag_rlrmap_records(xfs_mount_t *mp, xfs_agnumber_t agno);
+extern size_t reflink_count(xfs_mount_t *mp, xfs_agnumber_t agno);
+
+extern int init_reflink_cursor(xfs_agnumber_t agno, xfs_slab_cursor_t **cur);
+
+extern int reflink_check_refcounts(xfs_mount_t *mp, xfs_agnumber_t agno);
+
#endif /* RMAP_H_ */
|