@@ -119,6 +119,8 @@ xfs_scrub_superblock_xref(
return;
xfs_scrub_xref_not_free(sc, &sc->sa.bno_cur, bno, 1);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.ino_cur, bno, 1);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.fino_cur, bno, 1);
/* scrub teardown will take care of sc->sa for us */
}
@@ -491,6 +493,9 @@ xfs_scrub_agf_xref(
break;
}
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.ino_cur, bno, 1);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.fino_cur, bno, 1);
+
/* scrub teardown will take care of sc->sa for us */
}
@@ -595,6 +600,8 @@ xfs_scrub_agfl_block_xref(
xfs_agblock_t bno)
{
xfs_scrub_xref_not_free(sc, &sc->sa.bno_cur, bno, 1);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.ino_cur, bno, 1);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.fino_cur, bno, 1);
}
/* Scrub an AGFL block. */
@@ -649,6 +656,8 @@ xfs_scrub_agfl_xref(
return;
xfs_scrub_xref_not_free(sc, &sc->sa.bno_cur, bno, 1);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.ino_cur, bno, 1);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.fino_cur, bno, 1);
/*
* Scrub teardown will take care of sc->sa for us. Leave sc->sa
@@ -729,7 +738,11 @@ xfs_scrub_agi_xref(
struct xfs_scrub_context *sc)
{
struct xfs_mount *mp = sc->mp;
+ struct xfs_btree_cur **pcur;
+ struct xfs_agi *agi = XFS_BUF_TO_AGI(sc->sa.agi_bp);
xfs_agblock_t bno;
+ xfs_agino_t icount;
+ xfs_agino_t freecount;
int error;
bno = XFS_AGI_BLOCK(mp);
@@ -739,6 +752,18 @@ xfs_scrub_agi_xref(
return;
xfs_scrub_xref_not_free(sc, &sc->sa.bno_cur, bno, 1);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.ino_cur, bno, 1);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.fino_cur, bno, 1);
+
+ /* Check agi_count/agi_freecount */
+ pcur = &sc->sa.ino_cur;
+ if (*pcur) {
+ error = xfs_ialloc_count_inodes(*pcur, &icount, &freecount);
+ if (xfs_scrub_should_xref(sc, &error, pcur) &&
+ (be32_to_cpu(agi->agi_count) != icount ||
+ be32_to_cpu(agi->agi_freecount) != freecount))
+ xfs_scrub_block_xref_set_corrupt(sc, sc->sa.agi_bp);
+ }
/* scrub teardown will take care of sc->sa for us */
}
@@ -94,6 +94,9 @@ xfs_scrub_allocbt_xref(
xfs_scrub_btree_xref_set_corrupt(sc, *pcur, 0);
break;
}
+
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.ino_cur, bno, len);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.fino_cur, bno, len);
}
/* Scrub a bnobt/cntbt record. */
@@ -134,6 +134,8 @@ xfs_scrub_bmap_extent_xref(
return;
xfs_scrub_xref_not_free(info->sc, &sa.bno_cur, agbno, len);
+ xfs_scrub_xref_not_inodes(info->sc, &sa.ino_cur, agbno, len);
+ xfs_scrub_xref_not_inodes(info->sc, &sa.fino_cur, agbno, len);
xfs_scrub_ag_free(info->sc, &sa);
}
@@ -67,7 +67,29 @@ xfs_scrub_iallocbt_chunk_xref(
xfs_agblock_t bno,
xfs_extlen_t len)
{
+ struct xfs_btree_cur **pcur;
+ bool has_irec;
+ int error;
+
xfs_scrub_xref_not_free(sc, &sc->sa.bno_cur, bno, len);
+
+ /*
+ * If we're checking the finobt, cross-reference with the inobt.
+ * Otherwise we're checking the inobt; if there is an finobt,
+ * make sure we have a record or not depending on freecount.
+ */
+ if (sc->sm->sm_type == XFS_SCRUB_TYPE_FINOBT)
+ pcur = &sc->sa.ino_cur;
+ else
+ pcur = &sc->sa.fino_cur;
+ if (*pcur) {
+ error = xfs_ialloc_has_inode_record(*pcur,
+ agino, agino, &has_irec);
+ if (xfs_scrub_should_xref(sc, &error, pcur) &&
+ ((irec->ir_freecount > 0 && !has_irec) ||
+ (irec->ir_freecount == 0 && has_irec)))
+ xfs_scrub_btree_xref_set_corrupt(sc, *pcur, 0);
+ }
}
/* Is this chunk worth checking? */
@@ -351,3 +373,44 @@ xfs_scrub_finobt(
{
return xfs_scrub_iallocbt(sc, XFS_BTNUM_FINO);
}
+
+static inline void
+__xfs_scrub_xref_check_inodes(
+ struct xfs_scrub_context *sc,
+ struct xfs_btree_cur **pcur,
+ xfs_agblock_t bno,
+ xfs_extlen_t len,
+ bool fs_ok)
+{
+ bool has_inodes;
+ int error;
+
+ if (!(*pcur))
+ return;
+
+ error = xfs_ialloc_has_inodes_at_extent(*pcur, bno, len, &has_inodes);
+ if (xfs_scrub_should_xref(sc, &error, pcur) && has_inodes != fs_ok)
+ xfs_scrub_btree_xref_set_corrupt(sc, *pcur, 0);
+}
+
+/* xref check that the extent is not covered by inodes */
+void
+xfs_scrub_xref_not_inodes(
+ struct xfs_scrub_context *sc,
+ struct xfs_btree_cur **pcur,
+ xfs_agblock_t bno,
+ xfs_extlen_t len)
+{
+ __xfs_scrub_xref_check_inodes(sc, pcur, bno, len, false);
+}
+
+/* xref check that the extent is covered by inodes */
+void
+xfs_scrub_xref_are_inodes(
+ struct xfs_scrub_context *sc,
+ struct xfs_btree_cur **pcur,
+ xfs_agblock_t bno,
+ xfs_extlen_t len)
+{
+ __xfs_scrub_xref_check_inodes(sc, pcur, bno, len, true);
+}
@@ -597,6 +597,8 @@ xfs_scrub_inode_xref(
return;
xfs_scrub_xref_not_free(sc, &sa.bno_cur, agbno, 1);
+ xfs_scrub_xref_are_inodes(sc, &sc->sa.ino_cur, agbno, 1);
+ xfs_scrub_xref_are_inodes(sc, &sc->sa.fino_cur, agbno, 1);
xfs_scrub_ag_free(sc, &sa);
}
@@ -59,6 +59,8 @@ xfs_scrub_refcountbt_xref(
xfs_nlink_t refcount)
{
xfs_scrub_xref_not_free(sc, &sc->sa.bno_cur, bno, len);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.ino_cur, bno, len);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.fino_cur, bno, len);
}
/* Scrub a refcountbt record. */
@@ -61,6 +61,12 @@ xfs_scrub_rmapbt_xref(
xfs_extlen_t len = irec->rm_blockcount;
xfs_scrub_xref_not_free(sc, &sc->sa.bno_cur, bno, len);
+ if (irec->rm_owner == XFS_RMAP_OWN_INODES) {
+ xfs_scrub_xref_are_inodes(sc, &sc->sa.ino_cur, bno, len);
+ } else {
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.ino_cur, bno, len);
+ xfs_scrub_xref_not_inodes(sc, &sc->sa.fino_cur, bno, len);
+ }
}
/* Scrub an rmapbt record. */
@@ -127,5 +127,11 @@ xfs_scrub_quota(struct xfs_scrub_context *sc)
void xfs_scrub_xref_not_free(struct xfs_scrub_context *sc,
struct xfs_btree_cur **pcur, xfs_agblock_t bno,
xfs_extlen_t len);
+void xfs_scrub_xref_not_inodes(struct xfs_scrub_context *sc,
+ struct xfs_btree_cur **pcur, xfs_agblock_t bno,
+ xfs_extlen_t len);
+void xfs_scrub_xref_are_inodes(struct xfs_scrub_context *sc,
+ struct xfs_btree_cur **pcur, xfs_agblock_t bno,
+ xfs_extlen_t len);
#endif /* __XFS_SCRUB_SCRUB_H__ */