Commit c4e34172 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: standardize ondisk to incore conversion for rmap btrees

Create a xfs_rmap_check_irec function to detect corruption in btree
records.  Fix all xfs_rmap_btrec_to_irec callsites to call the new
helper and bubble up corruption reports.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
parent 39ab26d5
...@@ -205,6 +205,36 @@ xfs_rmap_btrec_to_irec( ...@@ -205,6 +205,36 @@ xfs_rmap_btrec_to_irec(
irec); irec);
} }
/* Simple checks for rmap records. */
xfs_failaddr_t
xfs_rmap_check_irec(
struct xfs_btree_cur *cur,
const struct xfs_rmap_irec *irec)
{
struct xfs_mount *mp = cur->bc_mp;
if (irec->rm_blockcount == 0)
return __this_address;
if (irec->rm_startblock <= XFS_AGFL_BLOCK(mp)) {
if (irec->rm_owner != XFS_RMAP_OWN_FS)
return __this_address;
if (irec->rm_blockcount != XFS_AGFL_BLOCK(mp) + 1)
return __this_address;
} else {
/* check for valid extent range, including overflow */
if (!xfs_verify_agbext(cur->bc_ag.pag, irec->rm_startblock,
irec->rm_blockcount))
return __this_address;
}
if (!(xfs_verify_ino(mp, irec->rm_owner) ||
(irec->rm_owner <= XFS_RMAP_OWN_FS &&
irec->rm_owner >= XFS_RMAP_OWN_MIN)))
return __this_address;
return NULL;
}
/* /*
* Get the data from the pointed-to record. * Get the data from the pointed-to record.
*/ */
...@@ -217,39 +247,24 @@ xfs_rmap_get_rec( ...@@ -217,39 +247,24 @@ xfs_rmap_get_rec(
struct xfs_mount *mp = cur->bc_mp; struct xfs_mount *mp = cur->bc_mp;
struct xfs_perag *pag = cur->bc_ag.pag; struct xfs_perag *pag = cur->bc_ag.pag;
union xfs_btree_rec *rec; union xfs_btree_rec *rec;
xfs_failaddr_t fa;
int error; int error;
error = xfs_btree_get_rec(cur, &rec, stat); error = xfs_btree_get_rec(cur, &rec, stat);
if (error || !*stat) if (error || !*stat)
return error; return error;
if (xfs_rmap_btrec_to_irec(rec, irec)) fa = xfs_rmap_btrec_to_irec(rec, irec);
goto out_bad_rec; if (!fa)
fa = xfs_rmap_check_irec(cur, irec);
if (irec->rm_blockcount == 0) if (fa)
goto out_bad_rec;
if (irec->rm_startblock <= XFS_AGFL_BLOCK(mp)) {
if (irec->rm_owner != XFS_RMAP_OWN_FS)
goto out_bad_rec;
if (irec->rm_blockcount != XFS_AGFL_BLOCK(mp) + 1)
goto out_bad_rec;
} else {
/* check for valid extent range, including overflow */
if (!xfs_verify_agbext(pag, irec->rm_startblock,
irec->rm_blockcount))
goto out_bad_rec;
}
if (!(xfs_verify_ino(mp, irec->rm_owner) ||
(irec->rm_owner <= XFS_RMAP_OWN_FS &&
irec->rm_owner >= XFS_RMAP_OWN_MIN)))
goto out_bad_rec; goto out_bad_rec;
return 0; return 0;
out_bad_rec: out_bad_rec:
xfs_warn(mp, xfs_warn(mp,
"Reverse Mapping BTree record corruption in AG %d detected!", "Reverse Mapping BTree record corruption in AG %d detected at %pS!",
pag->pag_agno); pag->pag_agno, fa);
xfs_warn(mp, xfs_warn(mp,
"Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x", "Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
irec->rm_owner, irec->rm_flags, irec->rm_startblock, irec->rm_owner, irec->rm_flags, irec->rm_startblock,
...@@ -2321,7 +2336,8 @@ xfs_rmap_query_range_helper( ...@@ -2321,7 +2336,8 @@ xfs_rmap_query_range_helper(
struct xfs_rmap_query_range_info *query = priv; struct xfs_rmap_query_range_info *query = priv;
struct xfs_rmap_irec irec; struct xfs_rmap_irec irec;
if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL) if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL ||
xfs_rmap_check_irec(cur, &irec) != NULL)
return -EFSCORRUPTED; return -EFSCORRUPTED;
return query->fn(cur, &irec, query->priv); return query->fn(cur, &irec, query->priv);
......
...@@ -195,6 +195,9 @@ int xfs_rmap_compare(const struct xfs_rmap_irec *a, ...@@ -195,6 +195,9 @@ int xfs_rmap_compare(const struct xfs_rmap_irec *a,
union xfs_btree_rec; union xfs_btree_rec;
xfs_failaddr_t xfs_rmap_btrec_to_irec(const union xfs_btree_rec *rec, xfs_failaddr_t xfs_rmap_btrec_to_irec(const union xfs_btree_rec *rec,
struct xfs_rmap_irec *irec); struct xfs_rmap_irec *irec);
xfs_failaddr_t xfs_rmap_check_irec(struct xfs_btree_cur *cur,
const struct xfs_rmap_irec *irec);
int xfs_rmap_has_record(struct xfs_btree_cur *cur, xfs_agblock_t bno, int xfs_rmap_has_record(struct xfs_btree_cur *cur, xfs_agblock_t bno,
xfs_extlen_t len, bool *exists); xfs_extlen_t len, bool *exists);
int xfs_rmap_record_exists(struct xfs_btree_cur *cur, xfs_agblock_t bno, int xfs_rmap_record_exists(struct xfs_btree_cur *cur, xfs_agblock_t bno,
......
...@@ -93,43 +93,18 @@ xchk_rmapbt_rec( ...@@ -93,43 +93,18 @@ xchk_rmapbt_rec(
struct xchk_btree *bs, struct xchk_btree *bs,
const union xfs_btree_rec *rec) const union xfs_btree_rec *rec)
{ {
struct xfs_mount *mp = bs->cur->bc_mp;
struct xfs_rmap_irec irec; struct xfs_rmap_irec irec;
struct xfs_perag *pag = bs->cur->bc_ag.pag;
bool non_inode; bool non_inode;
bool is_unwritten; bool is_unwritten;
bool is_bmbt; bool is_bmbt;
bool is_attr; bool is_attr;
if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL) { if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL ||
xfs_rmap_check_irec(bs->cur, &irec) != NULL) {
xchk_btree_set_corrupt(bs->sc, bs->cur, 0); xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
return 0; return 0;
} }
/* Check extent. */
if (irec.rm_startblock + irec.rm_blockcount <= irec.rm_startblock)
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
if (irec.rm_owner == XFS_RMAP_OWN_FS) {
/*
* xfs_verify_agbno returns false for static fs metadata.
* Since that only exists at the start of the AG, validate
* that by hand.
*/
if (irec.rm_startblock != 0 ||
irec.rm_blockcount != XFS_AGFL_BLOCK(mp) + 1)
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
} else {
/*
* Otherwise we must point somewhere past the static metadata
* but before the end of the FS. Run the regular check.
*/
if (!xfs_verify_agbno(pag, irec.rm_startblock) ||
!xfs_verify_agbno(pag, irec.rm_startblock +
irec.rm_blockcount - 1))
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
}
/* Check flags. */ /* Check flags. */
non_inode = XFS_RMAP_NON_INODE_OWNER(irec.rm_owner); non_inode = XFS_RMAP_NON_INODE_OWNER(irec.rm_owner);
is_bmbt = irec.rm_flags & XFS_RMAP_BMBT_BLOCK; is_bmbt = irec.rm_flags & XFS_RMAP_BMBT_BLOCK;
...@@ -148,16 +123,6 @@ xchk_rmapbt_rec( ...@@ -148,16 +123,6 @@ xchk_rmapbt_rec(
if (non_inode && (is_bmbt || is_unwritten || is_attr)) if (non_inode && (is_bmbt || is_unwritten || is_attr))
xchk_btree_set_corrupt(bs->sc, bs->cur, 0); xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
if (!non_inode) {
if (!xfs_verify_ino(mp, irec.rm_owner))
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
} else {
/* Non-inode owner within the magic values? */
if (irec.rm_owner <= XFS_RMAP_OWN_MIN ||
irec.rm_owner > XFS_RMAP_OWN_FS)
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
}
xchk_rmapbt_xref(bs->sc, &irec); xchk_rmapbt_xref(bs->sc, &irec);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment