[PATCH 21/25] xfs: cross-reference inode btrees during scrub

"Darrick J. Wong" <[email protected]>
Newsgroups gmane.comp.file-systems.xfs.general
Message-ID <[email protected]>
Cross-reference the inode btrees with the other metadata when we
scrub the filesystem.

Signed-off-by: Darrick J. Wong <[email protected]>
---
 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);

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.