Skip to content

Commit 2b30cc0

Browse files
author
Darrick J. Wong
committed
xfs: standardize ondisk to incore conversion for refcount btrees
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>
1 parent 366a0b8 commit 2b30cc0

3 files changed

Lines changed: 36 additions & 25 deletions

File tree

fs/xfs/libxfs/xfs_refcount.c

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,30 @@ xfs_refcount_btrec_to_irec(
120120
irec->rc_refcount = be32_to_cpu(rec->refc.rc_refcount);
121121
}
122122

123+
/* Simple checks for refcount records. */
124+
xfs_failaddr_t
125+
xfs_refcount_check_irec(
126+
struct xfs_btree_cur *cur,
127+
const struct xfs_refcount_irec *irec)
128+
{
129+
struct xfs_perag *pag = cur->bc_ag.pag;
130+
131+
if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
132+
return __this_address;
133+
134+
if (!xfs_refcount_check_domain(irec))
135+
return __this_address;
136+
137+
/* check for valid extent range, including overflow */
138+
if (!xfs_verify_agbext(pag, irec->rc_startblock, irec->rc_blockcount))
139+
return __this_address;
140+
141+
if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT)
142+
return __this_address;
143+
144+
return NULL;
145+
}
146+
123147
/*
124148
* Get the data from the pointed-to record.
125149
*/
@@ -132,33 +156,25 @@ xfs_refcount_get_rec(
132156
struct xfs_mount *mp = cur->bc_mp;
133157
struct xfs_perag *pag = cur->bc_ag.pag;
134158
union xfs_btree_rec *rec;
159+
xfs_failaddr_t fa;
135160
int error;
136161

137162
error = xfs_btree_get_rec(cur, &rec, stat);
138163
if (error || !*stat)
139164
return error;
140165

141166
xfs_refcount_btrec_to_irec(rec, irec);
142-
if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
143-
goto out_bad_rec;
144-
145-
if (!xfs_refcount_check_domain(irec))
146-
goto out_bad_rec;
147-
148-
/* check for valid extent range, including overflow */
149-
if (!xfs_verify_agbext(pag, irec->rc_startblock, irec->rc_blockcount))
150-
goto out_bad_rec;
151-
152-
if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT)
167+
fa = xfs_refcount_check_irec(cur, irec);
168+
if (fa)
153169
goto out_bad_rec;
154170

155171
trace_xfs_refcount_get(cur->bc_mp, pag->pag_agno, irec);
156172
return 0;
157173

158174
out_bad_rec:
159175
xfs_warn(mp,
160-
"Refcount BTree record corruption in AG %d detected!",
161-
pag->pag_agno);
176+
"Refcount BTree record corruption in AG %d detected at %pS!",
177+
pag->pag_agno, fa);
162178
xfs_warn(mp,
163179
"Start block 0x%x, block count 0x%x, references 0x%x",
164180
irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount);
@@ -1871,7 +1887,8 @@ xfs_refcount_recover_extent(
18711887
INIT_LIST_HEAD(&rr->rr_list);
18721888
xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec);
18731889

1874-
if (XFS_IS_CORRUPT(cur->bc_mp,
1890+
if (xfs_refcount_check_irec(cur, &rr->rr_rrec) != NULL ||
1891+
XFS_IS_CORRUPT(cur->bc_mp,
18751892
rr->rr_rrec.rc_domain != XFS_REFC_DOMAIN_COW)) {
18761893
kfree(rr);
18771894
return -EFSCORRUPTED;

fs/xfs/libxfs/xfs_refcount.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ extern int xfs_refcount_has_record(struct xfs_btree_cur *cur,
117117
union xfs_btree_rec;
118118
extern void xfs_refcount_btrec_to_irec(const union xfs_btree_rec *rec,
119119
struct xfs_refcount_irec *irec);
120+
xfs_failaddr_t xfs_refcount_check_irec(struct xfs_btree_cur *cur,
121+
const struct xfs_refcount_irec *irec);
120122
extern int xfs_refcount_insert(struct xfs_btree_cur *cur,
121123
struct xfs_refcount_irec *irec, int *stat);
122124

fs/xfs/scrub/refcount.c

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -340,24 +340,16 @@ xchk_refcountbt_rec(
340340
{
341341
struct xfs_refcount_irec irec;
342342
xfs_agblock_t *cow_blocks = bs->private;
343-
struct xfs_perag *pag = bs->cur->bc_ag.pag;
344343

345344
xfs_refcount_btrec_to_irec(rec, &irec);
346-
347-
/* Check the domain and refcount are not incompatible. */
348-
if (!xfs_refcount_check_domain(&irec))
345+
if (xfs_refcount_check_irec(bs->cur, &irec) != NULL) {
349346
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
347+
return 0;
348+
}
350349

351350
if (irec.rc_domain == XFS_REFC_DOMAIN_COW)
352351
(*cow_blocks) += irec.rc_blockcount;
353352

354-
/* Check the extent. */
355-
if (!xfs_verify_agbext(pag, irec.rc_startblock, irec.rc_blockcount))
356-
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
357-
358-
if (irec.rc_refcount == 0)
359-
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
360-
361353
xchk_refcountbt_xref(bs->sc, &irec);
362354

363355
return 0;

0 commit comments

Comments
 (0)