xfs: standardize ondisk to incore conversion for free space btrees
Create a xfs_alloc_btrec_to_irec function to convert an ondisk record to an incore record, and a xfs_alloc_check_irec function to detect corruption. Replace all the open-coded logic with calls to the new helpers and bubble up corruption reports. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
This commit is contained in:
parent
88accf1722
commit
35e3b9a117
|
@ -233,6 +233,34 @@ xfs_alloc_update(
|
|||
return xfs_btree_update(cur, &rec);
|
||||
}
|
||||
|
||||
/* Convert the ondisk btree record to its incore representation. */
|
||||
void
|
||||
xfs_alloc_btrec_to_irec(
|
||||
const union xfs_btree_rec *rec,
|
||||
struct xfs_alloc_rec_incore *irec)
|
||||
{
|
||||
irec->ar_startblock = be32_to_cpu(rec->alloc.ar_startblock);
|
||||
irec->ar_blockcount = be32_to_cpu(rec->alloc.ar_blockcount);
|
||||
}
|
||||
|
||||
/* Simple checks for free space records. */
|
||||
xfs_failaddr_t
|
||||
xfs_alloc_check_irec(
|
||||
struct xfs_btree_cur *cur,
|
||||
const struct xfs_alloc_rec_incore *irec)
|
||||
{
|
||||
struct xfs_perag *pag = cur->bc_ag.pag;
|
||||
|
||||
if (irec->ar_blockcount == 0)
|
||||
return __this_address;
|
||||
|
||||
/* check for valid extent range, including overflow */
|
||||
if (!xfs_verify_agbext(pag, irec->ar_startblock, irec->ar_blockcount))
|
||||
return __this_address;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the data from the pointed-to record.
|
||||
*/
|
||||
|
@ -243,34 +271,34 @@ xfs_alloc_get_rec(
|
|||
xfs_extlen_t *len, /* output: length of extent */
|
||||
int *stat) /* output: success/failure */
|
||||
{
|
||||
struct xfs_alloc_rec_incore irec;
|
||||
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);
|
||||
if (error || !(*stat))
|
||||
return error;
|
||||
|
||||
*bno = be32_to_cpu(rec->alloc.ar_startblock);
|
||||
*len = be32_to_cpu(rec->alloc.ar_blockcount);
|
||||
|
||||
if (*len == 0)
|
||||
goto out_bad_rec;
|
||||
|
||||
/* check for valid extent range, including overflow */
|
||||
if (!xfs_verify_agbext(pag, *bno, *len))
|
||||
xfs_alloc_btrec_to_irec(rec, &irec);
|
||||
fa = xfs_alloc_check_irec(cur, &irec);
|
||||
if (fa)
|
||||
goto out_bad_rec;
|
||||
|
||||
*bno = irec.ar_startblock;
|
||||
*len = irec.ar_blockcount;
|
||||
return 0;
|
||||
|
||||
out_bad_rec:
|
||||
xfs_warn(mp,
|
||||
"%s Freespace BTree record corruption in AG %d detected!",
|
||||
"%s Freespace BTree record corruption in AG %d detected at %pS!",
|
||||
cur->bc_btnum == XFS_BTNUM_BNO ? "Block" : "Size",
|
||||
pag->pag_agno);
|
||||
pag->pag_agno, fa);
|
||||
xfs_warn(mp,
|
||||
"start block 0x%x block count 0x%x", *bno, *len);
|
||||
"start block 0x%x block count 0x%x", irec.ar_startblock,
|
||||
irec.ar_blockcount);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
|
@ -3665,8 +3693,10 @@ xfs_alloc_query_range_helper(
|
|||
struct xfs_alloc_query_range_info *query = priv;
|
||||
struct xfs_alloc_rec_incore irec;
|
||||
|
||||
irec.ar_startblock = be32_to_cpu(rec->alloc.ar_startblock);
|
||||
irec.ar_blockcount = be32_to_cpu(rec->alloc.ar_blockcount);
|
||||
xfs_alloc_btrec_to_irec(rec, &irec);
|
||||
if (xfs_alloc_check_irec(cur, &irec) != NULL)
|
||||
return -EFSCORRUPTED;
|
||||
|
||||
return query->fn(cur, &irec, query->priv);
|
||||
}
|
||||
|
||||
|
|
|
@ -181,6 +181,12 @@ xfs_alloc_get_rec(
|
|||
xfs_extlen_t *len, /* output: length of extent */
|
||||
int *stat); /* output: success/failure */
|
||||
|
||||
union xfs_btree_rec;
|
||||
void xfs_alloc_btrec_to_irec(const union xfs_btree_rec *rec,
|
||||
struct xfs_alloc_rec_incore *irec);
|
||||
xfs_failaddr_t xfs_alloc_check_irec(struct xfs_btree_cur *cur,
|
||||
const struct xfs_alloc_rec_incore *irec);
|
||||
|
||||
int xfs_read_agf(struct xfs_perag *pag, struct xfs_trans *tp, int flags,
|
||||
struct xfs_buf **agfbpp);
|
||||
int xfs_alloc_read_agf(struct xfs_perag *pag, struct xfs_trans *tp, int flags,
|
||||
|
|
|
@ -78,9 +78,11 @@ xchk_allocbt_xref_other(
|
|||
STATIC void
|
||||
xchk_allocbt_xref(
|
||||
struct xfs_scrub *sc,
|
||||
xfs_agblock_t agbno,
|
||||
xfs_extlen_t len)
|
||||
const struct xfs_alloc_rec_incore *irec)
|
||||
{
|
||||
xfs_agblock_t agbno = irec->ar_startblock;
|
||||
xfs_extlen_t len = irec->ar_blockcount;
|
||||
|
||||
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
|
||||
return;
|
||||
|
||||
|
@ -93,20 +95,18 @@ xchk_allocbt_xref(
|
|||
/* Scrub a bnobt/cntbt record. */
|
||||
STATIC int
|
||||
xchk_allocbt_rec(
|
||||
struct xchk_btree *bs,
|
||||
const union xfs_btree_rec *rec)
|
||||
struct xchk_btree *bs,
|
||||
const union xfs_btree_rec *rec)
|
||||
{
|
||||
struct xfs_perag *pag = bs->cur->bc_ag.pag;
|
||||
xfs_agblock_t bno;
|
||||
xfs_extlen_t len;
|
||||
struct xfs_alloc_rec_incore irec;
|
||||
|
||||
bno = be32_to_cpu(rec->alloc.ar_startblock);
|
||||
len = be32_to_cpu(rec->alloc.ar_blockcount);
|
||||
|
||||
if (!xfs_verify_agbext(pag, bno, len))
|
||||
xfs_alloc_btrec_to_irec(rec, &irec);
|
||||
if (xfs_alloc_check_irec(bs->cur, &irec) != NULL) {
|
||||
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xchk_allocbt_xref(bs->sc, bno, len);
|
||||
xchk_allocbt_xref(bs->sc, &irec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue