aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2023-05-30 13:14:58 +0200
committerCarlos Maiolino <cem@kernel.org>2023-06-09 10:27:50 +0200
commit03d1a871946af6c3db5017bedb485e2e7db1f085 (patch)
tree53a5accccf02eb9d687138d4500bcc9a6293e692
parent349aa6876786cbcf9faa3aed3c577f634c03a8b0 (diff)
downloadxfsprogs-dev-03d1a871946af6c3db5017bedb485e2e7db1f085.tar.gz
xfs: standardize ondisk to incore conversion for refcount btrees
Source kernel commit: 2b30cc0bf0589d1ea0506c019b9b81de77535c87 Create a xfs_refcount_check_irec function to detect corruption in btree records. Fix all xfs_refcount_btrec_to_irec callsites to call the new helper and bubble up corruption reports. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Carlos Maiolino <cem@kernel.org>
-rw-r--r--libxfs/xfs_refcount.c45
-rw-r--r--libxfs/xfs_refcount.h2
2 files changed, 33 insertions, 14 deletions
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index 460da7e415..7028342c77 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -119,6 +119,30 @@ xfs_refcount_btrec_to_irec(
irec->rc_refcount = be32_to_cpu(rec->refc.rc_refcount);
}
+/* Simple checks for refcount records. */
+xfs_failaddr_t
+xfs_refcount_check_irec(
+ struct xfs_btree_cur *cur,
+ const struct xfs_refcount_irec *irec)
+{
+ struct xfs_perag *pag = cur->bc_ag.pag;
+
+ if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
+ return __this_address;
+
+ if (!xfs_refcount_check_domain(irec))
+ return __this_address;
+
+ /* check for valid extent range, including overflow */
+ if (!xfs_verify_agbext(pag, irec->rc_startblock, irec->rc_blockcount))
+ return __this_address;
+
+ if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT)
+ return __this_address;
+
+ return NULL;
+}
+
/*
* Get the data from the pointed-to record.
*/
@@ -131,6 +155,7 @@ xfs_refcount_get_rec(
struct xfs_mount *mp = cur->bc_mp;
struct xfs_perag *pag = cur->bc_ag.pag;
union xfs_btree_rec *rec;
+ xfs_failaddr_t fa;
int error;
error = xfs_btree_get_rec(cur, &rec, stat);
@@ -138,17 +163,8 @@ xfs_refcount_get_rec(
return error;
xfs_refcount_btrec_to_irec(rec, irec);
- if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
- goto out_bad_rec;
-
- if (!xfs_refcount_check_domain(irec))
- goto out_bad_rec;
-
- /* check for valid extent range, including overflow */
- if (!xfs_verify_agbext(pag, irec->rc_startblock, irec->rc_blockcount))
- goto out_bad_rec;
-
- if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT)
+ fa = xfs_refcount_check_irec(cur, irec);
+ if (fa)
goto out_bad_rec;
trace_xfs_refcount_get(cur->bc_mp, pag->pag_agno, irec);
@@ -156,8 +172,8 @@ xfs_refcount_get_rec(
out_bad_rec:
xfs_warn(mp,
- "Refcount BTree record corruption in AG %d detected!",
- pag->pag_agno);
+ "Refcount BTree record corruption in AG %d detected at %pS!",
+ pag->pag_agno, fa);
xfs_warn(mp,
"Start block 0x%x, block count 0x%x, references 0x%x",
irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount);
@@ -1870,7 +1886,8 @@ xfs_refcount_recover_extent(
INIT_LIST_HEAD(&rr->rr_list);
xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec);
- if (XFS_IS_CORRUPT(cur->bc_mp,
+ if (xfs_refcount_check_irec(cur, &rr->rr_rrec) != NULL ||
+ XFS_IS_CORRUPT(cur->bc_mp,
rr->rr_rrec.rc_domain != XFS_REFC_DOMAIN_COW)) {
kfree(rr);
return -EFSCORRUPTED;
diff --git a/libxfs/xfs_refcount.h b/libxfs/xfs_refcount.h
index c89f0fcd1e..fc0b58d4c3 100644
--- a/libxfs/xfs_refcount.h
+++ b/libxfs/xfs_refcount.h
@@ -117,6 +117,8 @@ extern int xfs_refcount_has_record(struct xfs_btree_cur *cur,
union xfs_btree_rec;
extern void xfs_refcount_btrec_to_irec(const union xfs_btree_rec *rec,
struct xfs_refcount_irec *irec);
+xfs_failaddr_t xfs_refcount_check_irec(struct xfs_btree_cur *cur,
+ const struct xfs_refcount_irec *irec);
extern int xfs_refcount_insert(struct xfs_btree_cur *cur,
struct xfs_refcount_irec *irec, int *stat);