[PATCH 21/25] xfs: cross-reference inode btrees during scrub
Darrick J. Wong
darrick.wong at oracle.com
Thu Aug 25 18:42:33 CDT 2016
Cross-reference the inode btrees with the other metadata when we
scrub the filesystem.
Signed-off-by: Darrick J. Wong <darrick.wong at oracle.com>
---
fs/xfs/libxfs/xfs_ialloc.c | 58 ++++++++++++
fs/xfs/libxfs/xfs_ialloc.h | 4 +
fs/xfs/xfs_scrub.c | 205 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 267 insertions(+)
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index ab05f63..d6521fd 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -2665,3 +2665,61 @@ xfs_ialloc_pagi_init(
xfs_trans_brelse(tp, bp);
return 0;
}
+
+/* Is there an inode record covering a given range of inode numbers? */
+int
+xfs_ialloc_has_inode_record(
+ struct xfs_btree_cur *cur,
+ xfs_agino_t low,
+ xfs_agino_t high,
+ bool *exists)
+{
+ struct xfs_inobt_rec_incore irec;
+ xfs_agino_t agino;
+ __uint16_t holemask;
+ int has;
+ int i;
+ int error;
+
+ *exists = false;
+ error = xfs_inobt_lookup(cur, low, XFS_LOOKUP_LE, &has);
+ while (error == 0 && has) {
+ error = xfs_inobt_get_rec(cur, &irec, &has);
+ if (error || irec.ir_startino > high)
+ break;
+
+ agino = irec.ir_startino;
+ holemask = irec.ir_holemask;
+ for (i = 0; i < XFS_INOBT_HOLEMASK_BITS; holemask >>= 1,
+ i++, agino += XFS_INODES_PER_HOLEMASK_BIT) {
+ if (holemask & 1)
+ continue;
+ if (agino + XFS_INODES_PER_HOLEMASK_BIT > low &&
+ agino <= high) {
+ *exists = true;
+ goto out;
+ }
+ }
+
+ error = xfs_btree_increment(cur, 0, &has);
+ }
+out:
+ return error;
+}
+
+/* Is there an inode record covering a given extent? */
+int
+xfs_ialloc_has_inodes_at_extent(
+ struct xfs_btree_cur *cur,
+ xfs_agblock_t bno,
+ xfs_extlen_t len,
+ bool *exists)
+{
+ xfs_agino_t low;
+ xfs_agino_t high;
+
+ low = XFS_OFFBNO_TO_AGINO(cur->bc_mp, bno, 0);
+ high = XFS_OFFBNO_TO_AGINO(cur->bc_mp, bno + len, 0) - 1;
+
+ return xfs_ialloc_has_inode_record(cur, low, high, exists);
+}
diff --git a/fs/xfs/libxfs/xfs_ialloc.h b/fs/xfs/libxfs/xfs_ialloc.h
index 8e5861d..f20d958 100644
--- a/fs/xfs/libxfs/xfs_ialloc.h
+++ b/fs/xfs/libxfs/xfs_ialloc.h
@@ -171,5 +171,9 @@ int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp,
union xfs_btree_rec;
void xfs_inobt_btrec_to_irec(struct xfs_mount *mp, union xfs_btree_rec *rec,
struct xfs_inobt_rec_incore *irec);
+int xfs_ialloc_has_inodes_at_extent(struct xfs_btree_cur *cur,
+ xfs_agblock_t bno, xfs_extlen_t len, bool *exists);
+int xfs_ialloc_has_inode_record(struct xfs_btree_cur *cur, xfs_agino_t low,
+ xfs_agino_t high, bool *exists);
#endif /* __XFS_IALLOC_H__ */
diff --git a/fs/xfs/xfs_scrub.c b/fs/xfs/xfs_scrub.c
index 63a7434..cc85584 100644
--- a/fs/xfs/xfs_scrub.c
+++ b/fs/xfs/xfs_scrub.c
@@ -814,6 +814,7 @@ xfs_scrub_sb(
struct xfs_sb sb;
xfs_agnumber_t agno;
bool is_freesp;
+ bool has_inodes;
int error;
int err2;
@@ -888,6 +889,26 @@ btree_xref:
XFS_SCRUB_CHECK(mp, bp, "superblock", !is_freesp);
xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+ /* Cross-reference with inobt. */
+ xcur = xfs_inobt_init_cursor(mp, NULL, agi_bp, agno, XFS_BTNUM_INO);
+ err2 = xfs_ialloc_has_inodes_at_extent(xcur, XFS_SB_BLOCK(mp), 1,
+ &has_inodes);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, bp, "superblock", !has_inodes);
+ xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+
+ /* Cross-reference with finobt. */
+ if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
+ xcur = xfs_inobt_init_cursor(mp, NULL, agi_bp, agno,
+ XFS_BTNUM_FINO);
+ err2 = xfs_ialloc_has_inodes_at_extent(xcur, XFS_SB_BLOCK(mp),
+ 1, &has_inodes);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, bp, "superblock", !has_inodes);
+ xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR :
+ XFS_BTREE_NOERROR);
+ }
+
xfs_scrub_put_ag_headers(&agi_bp, &agf_bp);
out:
xfs_buf_relse(bp);
@@ -911,6 +932,7 @@ xfs_scrub_agf(
xfs_daddr_t daddr;
xfs_daddr_t eofs;
bool is_freesp;
+ bool has_inodes;
int error;
int err2;
@@ -976,6 +998,26 @@ xfs_scrub_agf(
XFS_SCRUB_CHECK(mp, agf_bp, "AGF", !is_freesp);
xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+ /* Cross-reference with inobt. */
+ xcur = xfs_inobt_init_cursor(mp, NULL, agi_bp, agno, XFS_BTNUM_INO);
+ err2 = xfs_ialloc_has_inodes_at_extent(xcur, XFS_AGF_BLOCK(mp), 1,
+ &has_inodes);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, agf_bp, "AGF", !has_inodes);
+ xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+
+ /* Cross-reference with finobt. */
+ if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
+ xcur = xfs_inobt_init_cursor(mp, NULL, agi_bp, agno,
+ XFS_BTNUM_FINO);
+ err2 = xfs_ialloc_has_inodes_at_extent(xcur, XFS_AGF_BLOCK(mp),
+ 1, &has_inodes);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, agf_bp, "AGF", !has_inodes);
+ xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR :
+ XFS_BTREE_NOERROR);
+ }
+
xfs_scrub_put_ag_headers(&agi_bp, &agf_bp);
return error;
}
@@ -993,11 +1035,14 @@ xfs_scrub_agfl(
struct xfs_buf *agfl_bp;
__be32 *agfl_bno;
struct xfs_btree_cur *xcur = NULL;
+ struct xfs_btree_cur *icur = NULL;
+ struct xfs_btree_cur *fcur = NULL;
xfs_agnumber_t agno;
xfs_agblock_t agbno;
xfs_agblock_t eoag;
xfs_daddr_t eofs;
bool is_freesp;
+ bool has_inodes;
int i;
int error;
int err2;
@@ -1025,6 +1070,23 @@ xfs_scrub_agfl(
if (!err2)
XFS_SCRUB_CHECK(mp, agfl_bp, "AGFL", !is_freesp);
+ /* Cross-reference with inobt. */
+ icur = xfs_inobt_init_cursor(mp, NULL, agi_bp, agno, XFS_BTNUM_INO);
+ err2 = xfs_ialloc_has_inodes_at_extent(icur, XFS_AGFL_BLOCK(mp), 1,
+ &has_inodes);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, agfl_bp, "AGFL", !has_inodes);
+
+ /* Cross-reference with finobt. */
+ if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
+ fcur = xfs_inobt_init_cursor(mp, NULL, agi_bp, agno,
+ XFS_BTNUM_FINO);
+ err2 = xfs_ialloc_has_inodes_at_extent(fcur, XFS_AGFL_BLOCK(mp),
+ 1, &has_inodes);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, agfl_bp, "AGFL", !has_inodes);
+ }
+
agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agfl_bp);
for (i = be32_to_cpu(agf->agf_flfirst);
i <= be32_to_cpu(agf->agf_fllast);
@@ -1045,8 +1107,26 @@ xfs_scrub_agfl(
err2 = xfs_alloc_has_record(xcur, agbno, 1, &is_freesp);
if (!err2)
XFS_SCRUB_CHECK(mp, agfl_bp, "AGFL", !is_freesp);
+
+ /* Cross-reference with inobt. */
+ err2 = xfs_ialloc_has_inodes_at_extent(icur, agbno, 1,
+ &has_inodes);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, agfl_bp, "AGFL", !has_inodes);
+
+ /* Cross-reference with finobt. */
+ if (fcur) {
+ err2 = xfs_ialloc_has_inodes_at_extent(fcur, agbno, 1,
+ &has_inodes);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, agfl_bp, "AGFL",
+ !has_inodes);
+ }
}
+ if (fcur)
+ xfs_btree_del_cursor(fcur, XFS_BTREE_ERROR);
+ xfs_btree_del_cursor(icur, XFS_BTREE_ERROR);
xfs_btree_del_cursor(xcur, XFS_BTREE_ERROR);
xfs_buf_relse(agfl_bp);
err_no_agfl:
@@ -1072,6 +1152,7 @@ xfs_scrub_agi(
xfs_daddr_t daddr;
xfs_daddr_t eofs;
bool is_freesp;
+ bool has_inodes;
int error;
int err2;
@@ -1110,6 +1191,26 @@ xfs_scrub_agi(
XFS_SCRUB_CHECK(mp, agi_bp, "AGI", !is_freesp);
xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+ /* Cross-reference with inobt. */
+ xcur = xfs_inobt_init_cursor(mp, NULL, agi_bp, agno, XFS_BTNUM_INO);
+ err2 = xfs_ialloc_has_inodes_at_extent(xcur, XFS_AGI_BLOCK(mp), 1,
+ &has_inodes);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, agi_bp, "AGI", !has_inodes);
+ xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+
+ /* Cross-reference with finobt. */
+ if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
+ xcur = xfs_inobt_init_cursor(mp, NULL, agi_bp, agno,
+ XFS_BTNUM_FINO);
+ err2 = xfs_ialloc_has_inodes_at_extent(xcur, XFS_AGI_BLOCK(mp),
+ 1, &has_inodes);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, agi_bp, "AGI", !has_inodes);
+ xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR :
+ XFS_BTREE_NOERROR);
+ }
+
xfs_scrub_put_ag_headers(&agi_bp, &agf_bp);
return error;
}
@@ -1129,6 +1230,7 @@ xfs_scrub_allocbt_helper(
xfs_agblock_t bno;
xfs_extlen_t flen;
xfs_extlen_t len;
+ bool has_inodes;
int has_otherrec;
int error = 0;
int err2;
@@ -1168,6 +1270,20 @@ xfs_scrub_allocbt_helper(
}
skip_freesp_xref:
+ /* Cross-reference with inobt. */
+ err2 = xfs_ialloc_has_inodes_at_extent(bs->ino_cur, bno, len,
+ &has_inodes);
+ if (!err2)
+ XFS_BTREC_SCRUB_CHECK(bs, !has_inodes);
+
+ /* Cross-reference with finobt. */
+ if (bs->fino_cur) {
+ err2 = xfs_ialloc_has_inodes_at_extent(bs->fino_cur, bno, len,
+ &has_inodes);
+ if (!err2)
+ XFS_BTREC_SCRUB_CHECK(bs, !has_inodes);
+ }
+
return error;
}
@@ -1230,6 +1346,7 @@ xfs_scrub_iallocbt_helper(
{
struct xfs_mount *mp = bs->cur->bc_mp;
struct xfs_agf *agf;
+ struct xfs_btree_cur *other_cur;
struct xfs_inobt_rec_incore irec;
__uint16_t holemask;
xfs_agino_t agino;
@@ -1237,6 +1354,7 @@ xfs_scrub_iallocbt_helper(
xfs_agblock_t eoag;
xfs_extlen_t len;
bool is_freesp;
+ bool has_inodes;
int holecount;
int i;
int error = 0;
@@ -1275,6 +1393,18 @@ xfs_scrub_iallocbt_helper(
if (!err2)
XFS_BTREC_SCRUB_CHECK(bs, !is_freesp);
+ /* If we have a finobt, cross-reference with it. */
+ if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
+ other_cur = bs->fino_cur ? bs->fino_cur : bs->ino_cur;
+ if (bs->cur->bc_btnum == XFS_BTNUM_FINO ||
+ irec.ir_freecount) {
+ err2 = xfs_ialloc_has_inode_record(other_cur,
+ agino, agino, &has_inodes);
+ if (!err2)
+ XFS_BTREC_SCRUB_CHECK(bs, has_inodes);
+ }
+ }
+
goto out;
}
@@ -1312,6 +1442,18 @@ xfs_scrub_iallocbt_helper(
&is_freesp);
if (!err2)
XFS_BTREC_SCRUB_CHECK(bs, !is_freesp);
+
+ /* If we have a finobt, cross-reference with it. */
+ if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
+ other_cur = bs->fino_cur ? bs->fino_cur : bs->ino_cur;
+ if (bs->cur->bc_btnum == XFS_BTNUM_FINO ||
+ irec.ir_freecount) {
+ err2 = xfs_ialloc_has_inode_record(other_cur,
+ agino, agino, &has_inodes);
+ if (!err2)
+ XFS_BTREC_SCRUB_CHECK(bs, has_inodes);
+ }
+ }
}
XFS_BTREC_SCRUB_CHECK(bs, holecount <= XFS_INODES_PER_CHUNK);
@@ -1388,6 +1530,7 @@ xfs_scrub_rmapbt_helper(
bool is_unwritten;
bool is_bmbt;
bool is_attr;
+ bool has_inodes;
int error = 0;
int err2;
@@ -1429,6 +1572,25 @@ xfs_scrub_rmapbt_helper(
if (!err2)
XFS_BTREC_SCRUB_CHECK(bs, !is_freesp);
+ /* Cross-reference with inobt. */
+ err2 = xfs_ialloc_has_inodes_at_extent(bs->ino_cur, irec.rm_startblock,
+ irec.rm_blockcount, &has_inodes);
+ if (!err2)
+ XFS_BTREC_SCRUB_CHECK(bs,
+ irec.rm_owner == XFS_RMAP_OWN_INODES ||
+ !has_inodes);
+
+ /* Cross-reference with finobt. */
+ if (bs->fino_cur) {
+ err2 = xfs_ialloc_has_inodes_at_extent(bs->fino_cur,
+ irec.rm_startblock, irec.rm_blockcount,
+ &has_inodes);
+ if (!err2)
+ XFS_BTREC_SCRUB_CHECK(bs,
+ irec.rm_owner == XFS_RMAP_OWN_INODES ||
+ !has_inodes);
+ }
+
return error;
}
@@ -1478,6 +1640,7 @@ xfs_scrub_refcountbt_helper(
struct xfs_refcount_irec irec;
xfs_agblock_t eoag;
bool is_freesp;
+ bool has_inodes;
int error = 0;
int err2;
@@ -1507,6 +1670,21 @@ xfs_scrub_refcountbt_helper(
if (!err2)
XFS_BTREC_SCRUB_CHECK(bs, !is_freesp);
+ /* Cross-reference with inobt. */
+ err2 = xfs_ialloc_has_inodes_at_extent(bs->ino_cur, irec.rc_startblock,
+ irec.rc_blockcount, &has_inodes);
+ if (!err2)
+ XFS_BTREC_SCRUB_CHECK(bs, !has_inodes);
+
+ /* Cross-reference with finobt. */
+ if (bs->fino_cur) {
+ err2 = xfs_ialloc_has_inodes_at_extent(bs->fino_cur,
+ irec.rc_startblock, irec.rc_blockcount,
+ &has_inodes);
+ if (!err2)
+ XFS_BTREC_SCRUB_CHECK(bs, !has_inodes);
+ }
+
return error;
}
@@ -1645,6 +1823,7 @@ xfs_scrub_bmap_extent(
xfs_agnumber_t agno;
xfs_fsblock_t bno;
bool is_freesp;
+ bool has_inodes;
int error = 0;
int err2 = 0;
@@ -1702,6 +1881,32 @@ xfs_scrub_bmap_extent(
XFS_BTREC_SCRUB_CHECK(&info->bs, !is_freesp);
xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR :
XFS_BTREE_NOERROR);
+
+ /* Cross-reference with inobt. */
+ xcur = xfs_inobt_init_cursor(mp, NULL, agi_bp, agno,
+ XFS_BTNUM_INO);
+ err2 = xfs_ialloc_has_inodes_at_extent(xcur,
+ irec->br_startblock, irec->br_blockcount,
+ &has_inodes);
+ if (!err2)
+ XFS_INO_SCRUB_CHECK(ip, bp, info->type, !has_inodes);
+ xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR :
+ XFS_BTREE_NOERROR);
+
+ /* Cross-reference with finobt. */
+ if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
+ xcur = xfs_inobt_init_cursor(mp, NULL, agi_bp, agno,
+ XFS_BTNUM_FINO);
+ err2 = xfs_ialloc_has_inodes_at_extent(xcur,
+ irec->br_startblock,
+ irec->br_blockcount,
+ &has_inodes);
+ if (!err2)
+ XFS_INO_SCRUB_CHECK(ip, bp, info->type,
+ !has_inodes);
+ xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR :
+ XFS_BTREE_NOERROR);
+ }
}
xfs_scrub_put_ag_headers(&agi_bp, &agf_bp);
More information about the xfs
mailing list