From: "Darrick J. Wong" <darrick.wong@oracle.com>
To: david@fromorbit.com, darrick.wong@oracle.com
Cc: linux-xfs@vger.kernel.org, xfs@oss.sgi.com
Subject: [PATCH 23/25] xfs: cross-reference refcount btree during scrub
Date: Thu, 25 Aug 2016 16:42:45 -0700 [thread overview]
Message-ID: <147216856568.3108.7611118372039280000.stgit@birch.djwong.org> (raw)
In-Reply-To: <147216841262.3108.10746252464845687338.stgit@birch.djwong.org>
During metadata btree scrub, we should cross-reference with the
reference counts.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
fs/xfs/libxfs/xfs_refcount.c | 19 ++++
fs/xfs/libxfs/xfs_refcount.h | 3 +
fs/xfs/xfs_scrub.c | 184 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 206 insertions(+)
diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
index 9136745..af82ea3 100644
--- a/fs/xfs/libxfs/xfs_refcount.c
+++ b/fs/xfs/libxfs/xfs_refcount.c
@@ -1535,3 +1535,22 @@ xfs_refcount_free_cow_extent(
return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_FREE_COW,
fsb, len);
}
+
+/* Is there a record covering a given extent? */
+int
+xfs_refcount_has_record(
+ struct xfs_btree_cur *cur,
+ xfs_agblock_t bno,
+ xfs_extlen_t len,
+ bool *exists)
+{
+ union xfs_btree_irec low;
+ union xfs_btree_irec high;
+
+ memset(&low, 0, sizeof(low));
+ low.rc.rc_startblock = bno;
+ memset(&high, 0xFF, sizeof(high));
+ high.rc.rc_startblock = bno + len - 1;
+
+ return xfs_btree_has_record(cur, &low, &high, exists);
+}
diff --git a/fs/xfs/libxfs/xfs_refcount.h b/fs/xfs/libxfs/xfs_refcount.h
index 105c246..a00400f 100644
--- a/fs/xfs/libxfs/xfs_refcount.h
+++ b/fs/xfs/libxfs/xfs_refcount.h
@@ -64,4 +64,7 @@ extern int xfs_refcount_free_cow_extent(struct xfs_mount *mp,
struct xfs_defer_ops *dfops, xfs_fsblock_t fsb,
xfs_extlen_t len);
+extern int xfs_refcount_has_record(struct xfs_btree_cur *cur,
+ xfs_agblock_t bno, xfs_extlen_t len, bool *exists);
+
#endif /* __XFS_REFCOUNT_H__ */
diff --git a/fs/xfs/xfs_scrub.c b/fs/xfs/xfs_scrub.c
index 34c23f7..ff55d8c 100644
--- a/fs/xfs/xfs_scrub.c
+++ b/fs/xfs/xfs_scrub.c
@@ -867,6 +867,7 @@ xfs_scrub_sb(
bool is_freesp;
bool has_inodes;
bool has_rmap;
+ bool has_refcount;
int error;
int err2;
@@ -973,6 +974,17 @@ btree_xref:
XFS_BTREE_NOERROR);
}
+ /* Cross-reference with the refcountbt. */
+ if (xfs_sb_version_hasreflink(&mp->m_sb)) {
+ xcur = xfs_refcountbt_init_cursor(mp, NULL, agf_bp, agno, NULL);
+ err2 = xfs_refcount_has_record(xcur, XFS_SB_BLOCK(mp), 1,
+ &has_refcount);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, bp, "superblock", !has_refcount);
+ 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);
@@ -1000,6 +1012,7 @@ xfs_scrub_agf(
bool is_freesp;
bool has_inodes;
bool has_rmap;
+ bool has_refcount;
int error;
int err2;
@@ -1103,6 +1116,23 @@ skip_rmap_xref:
XFS_BTREE_NOERROR);
}
+ /* Cross-reference with the refcountbt. */
+ if (xfs_sb_version_hasreflink(&mp->m_sb)) {
+ xcur = xfs_refcountbt_init_cursor(mp, NULL, agf_bp, agno, NULL);
+ err2 = xfs_refcount_has_record(xcur, XFS_AGF_BLOCK(mp), 1,
+ &has_refcount);
+ if (err2)
+ goto skip_refc_xref;
+ XFS_SCRUB_CHECK(mp, agf_bp, "AGF", !has_refcount);
+ err2 = xfs_btree_count_blocks(xcur, &blocks);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, agf_bp, "AGF", blocks ==
+ be32_to_cpu(agf->agf_refcount_blocks));
+skip_refc_xref:
+ xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR :
+ XFS_BTREE_NOERROR);
+ }
+
xfs_scrub_put_ag_headers(&agi_bp, &agf_bp);
return error;
}
@@ -1123,6 +1153,7 @@ xfs_scrub_agfl(
struct xfs_btree_cur *icur = NULL;
struct xfs_btree_cur *fcur = NULL;
struct xfs_btree_cur *rcur = NULL;
+ struct xfs_btree_cur *ccur = NULL;
struct xfs_owner_info oinfo;
xfs_agnumber_t agno;
xfs_agblock_t agbno;
@@ -1131,6 +1162,7 @@ xfs_scrub_agfl(
bool is_freesp;
bool has_inodes;
bool has_rmap;
+ bool has_refcount;
int i;
int error;
int err2;
@@ -1185,6 +1217,15 @@ xfs_scrub_agfl(
XFS_SCRUB_CHECK(mp, agfl_bp, "AGFL", has_rmap);
}
+ /* Set up cross-reference with refcountbt. */
+ if (xfs_sb_version_hasreflink(&mp->m_sb)) {
+ ccur = xfs_refcountbt_init_cursor(mp, NULL, agf_bp, agno, NULL);
+ err2 = xfs_refcount_has_record(ccur, XFS_AGFL_BLOCK(mp), 1,
+ &has_refcount);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, agfl_bp, "AGFL", !has_refcount);
+ }
+
xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_AG);
agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agfl_bp);
for (i = be32_to_cpu(agf->agf_flfirst);
@@ -1229,8 +1270,19 @@ xfs_scrub_agfl(
if (!err2)
XFS_SCRUB_CHECK(mp, agfl_bp, "AGFL", has_rmap);
}
+
+ /* Cross-reference with the refcountbt. */
+ if (ccur) {
+ err2 = xfs_refcount_has_record(ccur, agbno, 1,
+ &has_refcount);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, agfl_bp, "AGFL",
+ !has_refcount);
+ }
}
+ if (ccur)
+ xfs_btree_del_cursor(ccur, XFS_BTREE_ERROR);
if (rcur)
xfs_btree_del_cursor(rcur, XFS_BTREE_ERROR);
if (fcur)
@@ -1264,6 +1316,7 @@ xfs_scrub_agi(
bool is_freesp;
bool has_inodes;
bool has_rmap;
+ bool has_refcount;
int error;
int err2;
@@ -1334,6 +1387,17 @@ xfs_scrub_agi(
XFS_BTREE_NOERROR);
}
+ /* Cross-reference with the refcountbt. */
+ if (xfs_sb_version_hasreflink(&mp->m_sb)) {
+ xcur = xfs_refcountbt_init_cursor(mp, NULL, agf_bp, agno, NULL);
+ err2 = xfs_refcount_has_record(xcur, XFS_AGI_BLOCK(mp), 1,
+ &has_refcount);
+ if (!err2)
+ XFS_SCRUB_CHECK(mp, agi_bp, "AGI", !has_refcount);
+ xfs_btree_del_cursor(xcur, err2 ? XFS_BTREE_ERROR :
+ XFS_BTREE_NOERROR);
+ }
+
xfs_scrub_put_ag_headers(&agi_bp, &agf_bp);
return error;
}
@@ -1355,6 +1419,7 @@ xfs_scrub_allocbt_helper(
xfs_extlen_t len;
bool has_rmap;
bool has_inodes;
+ bool has_refcount;
int has_otherrec;
int error = 0;
int err2;
@@ -1415,6 +1480,14 @@ skip_freesp_xref:
XFS_BTREC_SCRUB_CHECK(bs, !has_rmap);
}
+ /* Cross-reference with the refcountbt. */
+ if (bs->refc_cur) {
+ err2 = xfs_refcount_has_record(bs->refc_cur, bno, len,
+ &has_refcount);
+ if (!err2)
+ XFS_BTREC_SCRUB_CHECK(bs, !has_refcount);
+ }
+
return error;
}
@@ -1488,6 +1561,7 @@ xfs_scrub_iallocbt_helper(
bool is_freesp;
bool has_inodes;
bool has_rmap;
+ bool has_refcount;
int holecount;
int i;
int error = 0;
@@ -1547,6 +1621,14 @@ xfs_scrub_iallocbt_helper(
XFS_BTREC_SCRUB_CHECK(bs, has_rmap);
}
+ /* Cross-reference with the refcountbt. */
+ if (bs->refc_cur) {
+ err2 = xfs_refcount_has_record(bs->refc_cur, bno,
+ len, &has_refcount);
+ if (!err2)
+ XFS_BTREC_SCRUB_CHECK(bs, !has_refcount);
+ }
+
goto out;
}
@@ -1604,6 +1686,14 @@ xfs_scrub_iallocbt_helper(
if (!err2)
XFS_BTREC_SCRUB_CHECK(bs, has_rmap);
}
+
+ /* Cross-reference with the refcountbt. */
+ if (bs->refc_cur) {
+ err2 = xfs_refcount_has_record(bs->refc_cur, bno,
+ len, &has_refcount);
+ if (!err2)
+ XFS_BTREC_SCRUB_CHECK(bs, !has_refcount);
+ }
}
XFS_BTREC_SCRUB_CHECK(bs, holecount <= XFS_INODES_PER_CHUNK);
@@ -1674,13 +1764,17 @@ xfs_scrub_rmapbt_helper(
struct xfs_mount *mp = bs->cur->bc_mp;
struct xfs_agf *agf;
struct xfs_rmap_irec irec;
+ struct xfs_refcount_irec crec;
xfs_agblock_t eoag;
+ xfs_agblock_t fbno;
+ xfs_extlen_t flen;
bool is_freesp;
bool non_inode;
bool is_unwritten;
bool is_bmbt;
bool is_attr;
bool has_inodes;
+ int has_refcount;
int error = 0;
int err2;
@@ -1741,6 +1835,45 @@ xfs_scrub_rmapbt_helper(
!has_inodes);
}
+ /* Cross-reference with the refcount btree. */
+ if (bs->refc_cur) {
+ if (irec.rm_owner == XFS_RMAP_OWN_COW) {
+ /* Check this CoW staging extent. */
+ err2 = xfs_refcount_lookup_le(bs->refc_cur,
+ irec.rm_startblock, &has_refcount);
+ if (err2)
+ goto skip_refc_xref;
+ XFS_BTREC_SCRUB_GOTO(bs, has_refcount, skip_refc_xref);
+
+ err2 = xfs_refcount_get_rec(bs->refc_cur, &crec,
+ &has_refcount);
+ if (err2)
+ goto skip_refc_xref;
+ XFS_BTREC_SCRUB_GOTO(bs, has_refcount, skip_refc_xref);
+ XFS_BTREC_SCRUB_CHECK(bs, crec.rc_startblock <=
+ irec.rm_startblock);
+ XFS_BTREC_SCRUB_CHECK(bs, crec.rc_startblock +
+ crec.rc_blockcount >
+ crec.rc_startblock);
+ XFS_BTREC_SCRUB_CHECK(bs, crec.rc_startblock +
+ crec.rc_blockcount >=
+ irec.rm_startblock +
+ irec.rm_blockcount);
+ XFS_BTREC_SCRUB_CHECK(bs,
+ crec.rc_refcount == 1);
+ } else {
+ /* If this is shared, the inode flag must be set. */
+ err2 = xfs_refcount_find_shared(bs->refc_cur,
+ irec.rm_startblock, irec.rm_blockcount,
+ &fbno, &flen, false);
+ if (!err2)
+ XFS_BTREC_SCRUB_CHECK(bs, flen == 0 ||
+ (!non_inode && !is_attr &&
+ !is_bmbt && !is_unwritten));
+ }
+skip_refc_xref:;
+ }
+
return error;
}
@@ -2164,12 +2297,16 @@ xfs_scrub_bmap_extent(
xfs_agnumber_t agno;
xfs_fsblock_t bno;
struct xfs_rmap_irec rmap;
+ struct xfs_refcount_irec crec;
uint64_t owner;
xfs_fileoff_t offset;
+ xfs_agblock_t fbno;
+ xfs_extlen_t flen;
bool is_freesp;
bool has_inodes;
unsigned int rflags;
int has_rmap;
+ int has_refcount;
int error = 0;
int err2 = 0;
@@ -2348,6 +2485,53 @@ skip_rmap_xref:
XFS_BTREE_NOERROR);
}
+ /*
+ * If this is a non-shared file on a reflink filesystem,
+ * check the refcountbt to see if the flag is wrong.
+ */
+ if (xfs_sb_version_hasreflink(&mp->m_sb) && !info->is_rt) {
+ xcur = xfs_refcountbt_init_cursor(mp, NULL, agf_bp, agno, NULL);
+
+ if (info->whichfork == XFS_COW_FORK) {
+ /* Check this CoW staging extent. */
+ err2 = xfs_refcount_lookup_le(xcur, bno, &has_refcount);
+ if (err2)
+ goto skip_refc_xref;
+ XFS_INO_SCRUB_GOTO(ip, NULL, info->type, has_refcount,
+ skip_refc_xref);
+
+ err2 = xfs_refcount_get_rec(xcur, &crec, &has_refcount);
+ if (err2)
+ goto skip_refc_xref;
+ XFS_INO_SCRUB_GOTO(ip, NULL, info->type, has_refcount,
+ skip_refc_xref);
+
+ XFS_INO_SCRUB_CHECK(ip, NULL, info->type,
+ crec.rc_startblock <= bno);
+ XFS_INO_SCRUB_CHECK(ip, NULL, info->type,
+ crec.rc_startblock +
+ crec.rc_blockcount >
+ crec.rc_startblock);
+ XFS_INO_SCRUB_CHECK(ip, NULL, info->type,
+ crec.rc_startblock +
+ crec.rc_blockcount >=
+ bno + irec->br_blockcount);
+ XFS_INO_SCRUB_CHECK(ip, NULL, info->type,
+ crec.rc_refcount == 1);
+ } else {
+ /* If this is shared, the inode flag must be set. */
+ err2 = xfs_refcount_find_shared(xcur, bno,
+ irec->br_blockcount, &fbno, &flen,
+ false);
+ if (!err2)
+ XFS_INO_SCRUB_CHECK(ip, bp, info->type,
+ flen == 0 ||
+ xfs_is_reflink_inode(ip));
+ }
+skip_refc_xref:
+ xfs_btree_del_cursor(xcur, XFS_BTREE_NOERROR);
+ }
+
xfs_scrub_put_ag_headers(&agi_bp, &agf_bp);
out:
info->lastoff = irec->br_startoff + irec->br_blockcount;
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
next prev parent reply other threads:[~2016-08-25 23:42 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-08-25 23:40 [PATCH v8 00/25] xfs: online scrub support Darrick J. Wong
2016-08-25 23:40 ` [PATCH 01/25] xfs: introduce the XFS_IOC_GETFSMAP ioctl Darrick J. Wong
2016-08-25 23:40 ` [PATCH 02/25] xfs: report shared extents in getfsmapx Darrick J. Wong
2016-08-25 23:40 ` [PATCH 03/25] xfs: have getfsmap fall back to the freesp btrees when rmap is not present Darrick J. Wong
2016-08-25 23:40 ` [PATCH 04/25] xfs: getfsmap should fall back to rtbitmap when rtrmapbt " Darrick J. Wong
2016-08-25 23:40 ` [PATCH 05/25] xfs: add scrub tracepoints Darrick J. Wong
2016-08-25 23:40 ` [PATCH 06/25] xfs: generic functions to scrub metadata and btrees Darrick J. Wong
2016-08-25 23:40 ` [PATCH 07/25] xfs: create an ioctl to scrub AG metadata Darrick J. Wong
2016-08-25 23:41 ` [PATCH 08/25] xfs: scrub the backup superblocks Darrick J. Wong
2016-08-25 23:41 ` [PATCH 09/25] xfs: scrub AGF and AGFL Darrick J. Wong
2016-08-25 23:41 ` [PATCH 10/25] xfs: scrub the AGI Darrick J. Wong
2016-08-25 23:41 ` [PATCH 11/25] xfs: support scrubbing free space btrees Darrick J. Wong
2016-08-25 23:41 ` [PATCH 12/25] xfs: support scrubbing inode btrees Darrick J. Wong
2016-08-25 23:41 ` [PATCH 13/25] xfs: support scrubbing rmap btree Darrick J. Wong
2016-08-25 23:41 ` [PATCH 14/25] xfs: support scrubbing refcount btree Darrick J. Wong
2016-08-25 23:41 ` [PATCH 15/25] xfs: scrub inodes Darrick J. Wong
2016-08-25 23:41 ` [PATCH 16/25] xfs: scrub inode block mappings Darrick J. Wong
2016-08-25 23:42 ` [PATCH 17/25] xfs: scrub realtime bitmap/summary Darrick J. Wong
2016-08-25 23:42 ` [PATCH 18/25] xfs: scrub should cross-reference with the bnobt Darrick J. Wong
2016-08-25 23:42 ` [PATCH 19/25] xfs: cross-reference bnobt records with cntbt Darrick J. Wong
2016-08-25 23:42 ` [PATCH 20/25] xfs: cross-reference extents with AG header Darrick J. Wong
2016-08-25 23:42 ` [PATCH 21/25] xfs: cross-reference inode btrees during scrub Darrick J. Wong
2016-08-25 23:42 ` [PATCH 22/25] xfs: cross-reference reverse-mapping btree Darrick J. Wong
2016-08-25 23:42 ` Darrick J. Wong [this message]
2016-08-25 23:42 ` [PATCH 24/25] xfs: scrub should cross-reference the realtime bitmap Darrick J. Wong
2016-08-25 23:42 ` [PATCH 25/25] xfs: query the per-AG reservation counters Darrick J. Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=147216856568.3108.7611118372039280000.stgit@birch.djwong.org \
--to=darrick.wong@oracle.com \
--cc=david@fromorbit.com \
--cc=linux-xfs@vger.kernel.org \
--cc=xfs@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.