From patchwork Thu Aug 25 23:42:45 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 9300409 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id AD10560757 for ; Thu, 25 Aug 2016 23:43:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9D22629139 for ; Thu, 25 Aug 2016 23:43:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8DD8C29354; Thu, 25 Aug 2016 23:43:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from oss.sgi.com (oss.sgi.com [192.48.182.195]) (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id CA1B229139 for ; Thu, 25 Aug 2016 23:43:49 +0000 (UTC) Received: from oss.sgi.com (localhost [IPv6:::1]) by oss.sgi.com (Postfix) with ESMTP id A3EBF7FAB; Thu, 25 Aug 2016 18:42:54 -0500 (CDT) X-Original-To: xfs@oss.sgi.com Delivered-To: xfs@oss.sgi.com Received: from relay.sgi.com (relay2.corp.sgi.com [137.38.102.29]) by oss.sgi.com (Postfix) with ESMTP id 4B6DA7FA9 for ; Thu, 25 Aug 2016 18:42:52 -0500 (CDT) Received: from cuda.sgi.com (cuda3.sgi.com [192.48.176.15]) by relay2.corp.sgi.com (Postfix) with ESMTP id 1F72A304039 for ; Thu, 25 Aug 2016 16:42:52 -0700 (PDT) X-ASG-Debug-ID: 1472168569-0bf57c55b21c7b80001-NocioJ Received: from userp1040.oracle.com (userp1040.oracle.com [156.151.31.81]) by cuda.sgi.com with ESMTP id U3Rk6VFrg7nbn3Sl (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Thu, 25 Aug 2016 16:42:49 -0700 (PDT) X-Barracuda-Envelope-From: darrick.wong@oracle.com X-Barracuda-Effective-Source-IP: userp1040.oracle.com[156.151.31.81] X-Barracuda-Apparent-Source-IP: 156.151.31.81 Received: from userv0021.oracle.com (userv0021.oracle.com [156.151.31.71]) by userp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id u7PNgmoC025391 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 25 Aug 2016 23:42:48 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by userv0021.oracle.com (8.13.8/8.13.8) with ESMTP id u7PNgmmJ016855 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 25 Aug 2016 23:42:48 GMT Received: from abhmp0002.oracle.com (abhmp0002.oracle.com [141.146.116.8]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id u7PNglZm019780; Thu, 25 Aug 2016 23:42:47 GMT Received: from localhost (/10.145.178.207) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 25 Aug 2016 16:42:47 -0700 Subject: [PATCH 23/25] xfs: cross-reference refcount btree during scrub From: "Darrick J. Wong" X-ASG-Orig-Subj: [PATCH 23/25] xfs: cross-reference refcount btree during scrub To: david@fromorbit.com, darrick.wong@oracle.com Date: Thu, 25 Aug 2016 16:42:45 -0700 Message-ID: <147216856568.3108.7611118372039280000.stgit@birch.djwong.org> In-Reply-To: <147216841262.3108.10746252464845687338.stgit@birch.djwong.org> References: <147216841262.3108.10746252464845687338.stgit@birch.djwong.org> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Source-IP: userv0021.oracle.com [156.151.31.71] X-Barracuda-Connect: userp1040.oracle.com[156.151.31.81] X-Barracuda-Start-Time: 1472168569 X-Barracuda-Encrypted: ECDHE-RSA-AES256-GCM-SHA384 X-Barracuda-URL: https://192.48.176.15:443/cgi-mod/mark.cgi X-Barracuda-Scan-Msg-Size: 11146 X-Virus-Scanned: by bsmtpd at sgi.com X-Barracuda-BRTS-Status: 1 X-Barracuda-Spam-Score: 0.00 X-Barracuda-Spam-Status: No, SCORE=0.00 using per-user scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=2.7 tests=BSF_SC0_MISMATCH_TO, UNPARSEABLE_RELAY X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.32328 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.00 BSF_SC0_MISMATCH_TO Envelope rcpt doesn't match header 0.00 UNPARSEABLE_RELAY Informational: message has unparseable relay lines Cc: linux-xfs@vger.kernel.org, xfs@oss.sgi.com X-BeenThere: xfs@oss.sgi.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: XFS Filesystem from SGI List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: xfs-bounces@oss.sgi.com Sender: xfs-bounces@oss.sgi.com X-Virus-Scanned: ClamAV using ClamSMTP During metadata btree scrub, we should cross-reference with the reference counts. Signed-off-by: Darrick J. Wong --- 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;