Commit 8d57c216 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: add a function to deal with corrupt buffers post-verifiers

Add a helper function to get rid of buffers that we have decided are
corrupt after the verifiers have run.  This function is intended to
handle metadata checks that can't happen in the verifiers, such as
inter-block relationship checking.  Note that we now mark the buffer
stale so that it will not end up on any LRU and will be purged on
release.
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
parent a71e4228
...@@ -722,7 +722,7 @@ xfs_alloc_update_counters( ...@@ -722,7 +722,7 @@ xfs_alloc_update_counters(
xfs_trans_agblocks_delta(tp, len); xfs_trans_agblocks_delta(tp, len);
if (unlikely(be32_to_cpu(agf->agf_freeblks) > if (unlikely(be32_to_cpu(agf->agf_freeblks) >
be32_to_cpu(agf->agf_length))) { be32_to_cpu(agf->agf_length))) {
xfs_buf_corruption_error(agbp); xfs_buf_mark_corrupt(agbp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
......
...@@ -2339,7 +2339,7 @@ xfs_attr3_leaf_lookup_int( ...@@ -2339,7 +2339,7 @@ xfs_attr3_leaf_lookup_int(
xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf);
entries = xfs_attr3_leaf_entryp(leaf); entries = xfs_attr3_leaf_entryp(leaf);
if (ichdr.count >= args->geo->blksize / 8) { if (ichdr.count >= args->geo->blksize / 8) {
xfs_buf_corruption_error(bp); xfs_buf_mark_corrupt(bp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -2358,11 +2358,11 @@ xfs_attr3_leaf_lookup_int( ...@@ -2358,11 +2358,11 @@ xfs_attr3_leaf_lookup_int(
break; break;
} }
if (!(probe >= 0 && (!ichdr.count || probe < ichdr.count))) { if (!(probe >= 0 && (!ichdr.count || probe < ichdr.count))) {
xfs_buf_corruption_error(bp); xfs_buf_mark_corrupt(bp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
if (!(span <= 4 || be32_to_cpu(entry->hashval) == hashval)) { if (!(span <= 4 || be32_to_cpu(entry->hashval) == hashval)) {
xfs_buf_corruption_error(bp); xfs_buf_mark_corrupt(bp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
......
...@@ -1762,7 +1762,7 @@ xfs_btree_lookup_get_block( ...@@ -1762,7 +1762,7 @@ xfs_btree_lookup_get_block(
out_bad: out_bad:
*blkp = NULL; *blkp = NULL;
xfs_buf_corruption_error(bp); xfs_buf_mark_corrupt(bp);
xfs_trans_brelse(cur->bc_tp, bp); xfs_trans_brelse(cur->bc_tp, bp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
......
...@@ -590,7 +590,7 @@ xfs_da3_split( ...@@ -590,7 +590,7 @@ xfs_da3_split(
node = oldblk->bp->b_addr; node = oldblk->bp->b_addr;
if (node->hdr.info.forw) { if (node->hdr.info.forw) {
if (be32_to_cpu(node->hdr.info.forw) != addblk->blkno) { if (be32_to_cpu(node->hdr.info.forw) != addblk->blkno) {
xfs_buf_corruption_error(oldblk->bp); xfs_buf_mark_corrupt(oldblk->bp);
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
goto out; goto out;
} }
...@@ -603,7 +603,7 @@ xfs_da3_split( ...@@ -603,7 +603,7 @@ xfs_da3_split(
node = oldblk->bp->b_addr; node = oldblk->bp->b_addr;
if (node->hdr.info.back) { if (node->hdr.info.back) {
if (be32_to_cpu(node->hdr.info.back) != addblk->blkno) { if (be32_to_cpu(node->hdr.info.back) != addblk->blkno) {
xfs_buf_corruption_error(oldblk->bp); xfs_buf_mark_corrupt(oldblk->bp);
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
goto out; goto out;
} }
...@@ -1624,7 +1624,7 @@ xfs_da3_node_lookup_int( ...@@ -1624,7 +1624,7 @@ xfs_da3_node_lookup_int(
} }
if (magic != XFS_DA_NODE_MAGIC && magic != XFS_DA3_NODE_MAGIC) { if (magic != XFS_DA_NODE_MAGIC && magic != XFS_DA3_NODE_MAGIC) {
xfs_buf_corruption_error(blk->bp); xfs_buf_mark_corrupt(blk->bp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -1639,7 +1639,7 @@ xfs_da3_node_lookup_int( ...@@ -1639,7 +1639,7 @@ xfs_da3_node_lookup_int(
/* Tree taller than we can handle; bail out! */ /* Tree taller than we can handle; bail out! */
if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) { if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) {
xfs_buf_corruption_error(blk->bp); xfs_buf_mark_corrupt(blk->bp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -1647,7 +1647,7 @@ xfs_da3_node_lookup_int( ...@@ -1647,7 +1647,7 @@ xfs_da3_node_lookup_int(
if (blkno == args->geo->leafblk) if (blkno == args->geo->leafblk)
expected_level = nodehdr.level - 1; expected_level = nodehdr.level - 1;
else if (expected_level != nodehdr.level) { else if (expected_level != nodehdr.level) {
xfs_buf_corruption_error(blk->bp); xfs_buf_mark_corrupt(blk->bp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} else } else
expected_level--; expected_level--;
......
...@@ -1383,7 +1383,7 @@ xfs_dir2_leaf_removename( ...@@ -1383,7 +1383,7 @@ xfs_dir2_leaf_removename(
ltp = xfs_dir2_leaf_tail_p(geo, leaf); ltp = xfs_dir2_leaf_tail_p(geo, leaf);
bestsp = xfs_dir2_leaf_bests_p(ltp); bestsp = xfs_dir2_leaf_bests_p(ltp);
if (be16_to_cpu(bestsp[db]) != oldbest) { if (be16_to_cpu(bestsp[db]) != oldbest) {
xfs_buf_corruption_error(lbp); xfs_buf_mark_corrupt(lbp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
/* /*
......
...@@ -439,7 +439,7 @@ xfs_dir2_leaf_to_node( ...@@ -439,7 +439,7 @@ xfs_dir2_leaf_to_node(
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
if (be32_to_cpu(ltp->bestcount) > if (be32_to_cpu(ltp->bestcount) >
(uint)dp->i_d.di_size / args->geo->blksize) { (uint)dp->i_d.di_size / args->geo->blksize) {
xfs_buf_corruption_error(lbp); xfs_buf_mark_corrupt(lbp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -513,7 +513,7 @@ xfs_dir2_leafn_add( ...@@ -513,7 +513,7 @@ xfs_dir2_leafn_add(
* into other peoples memory * into other peoples memory
*/ */
if (index < 0) { if (index < 0) {
xfs_buf_corruption_error(bp); xfs_buf_mark_corrupt(bp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -800,7 +800,7 @@ xfs_dir2_leafn_lookup_for_entry( ...@@ -800,7 +800,7 @@ xfs_dir2_leafn_lookup_for_entry(
xfs_dir3_leaf_check(dp, bp); xfs_dir3_leaf_check(dp, bp);
if (leafhdr.count <= 0) { if (leafhdr.count <= 0) {
xfs_buf_corruption_error(bp); xfs_buf_mark_corrupt(bp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
......
...@@ -145,7 +145,7 @@ xfs_attr3_node_inactive( ...@@ -145,7 +145,7 @@ xfs_attr3_node_inactive(
* Since this code is recursive (gasp!) we must protect ourselves. * Since this code is recursive (gasp!) we must protect ourselves.
*/ */
if (level > XFS_DA_NODE_MAXDEPTH) { if (level > XFS_DA_NODE_MAXDEPTH) {
xfs_buf_corruption_error(bp); xfs_buf_mark_corrupt(bp);
xfs_trans_brelse(*trans, bp); /* no locks for later trans */ xfs_trans_brelse(*trans, bp); /* no locks for later trans */
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -194,7 +194,7 @@ xfs_attr3_node_inactive( ...@@ -194,7 +194,7 @@ xfs_attr3_node_inactive(
error = xfs_attr3_leaf_inactive(trans, dp, child_bp); error = xfs_attr3_leaf_inactive(trans, dp, child_bp);
break; break;
default: default:
xfs_buf_corruption_error(child_bp); xfs_buf_mark_corrupt(child_bp);
xfs_trans_brelse(*trans, child_bp); xfs_trans_brelse(*trans, child_bp);
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
break; break;
...@@ -289,7 +289,7 @@ xfs_attr3_root_inactive( ...@@ -289,7 +289,7 @@ xfs_attr3_root_inactive(
break; break;
default: default:
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
xfs_buf_corruption_error(bp); xfs_buf_mark_corrupt(bp);
xfs_trans_brelse(*trans, bp); xfs_trans_brelse(*trans, bp);
break; break;
} }
......
...@@ -274,7 +274,7 @@ xfs_attr_node_list_lookup( ...@@ -274,7 +274,7 @@ xfs_attr_node_list_lookup(
return 0; return 0;
out_corruptbuf: out_corruptbuf:
xfs_buf_corruption_error(bp); xfs_buf_mark_corrupt(bp);
xfs_trans_brelse(tp, bp); xfs_trans_brelse(tp, bp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
......
...@@ -1573,6 +1573,28 @@ xfs_buf_zero( ...@@ -1573,6 +1573,28 @@ xfs_buf_zero(
} }
} }
/*
* Log a message about and stale a buffer that a caller has decided is corrupt.
*
* This function should be called for the kinds of metadata corruption that
* cannot be detect from a verifier, such as incorrect inter-block relationship
* data. Do /not/ call this function from a verifier function.
*
* The buffer must be XBF_DONE prior to the call. Afterwards, the buffer will
* be marked stale, but b_error will not be set. The caller is responsible for
* releasing the buffer or fixing it.
*/
void
__xfs_buf_mark_corrupt(
struct xfs_buf *bp,
xfs_failaddr_t fa)
{
ASSERT(bp->b_flags & XBF_DONE);
xfs_buf_corruption_error(bp);
xfs_buf_stale(bp);
}
/* /*
* Handling of buffer targets (buftargs). * Handling of buffer targets (buftargs).
*/ */
......
...@@ -272,6 +272,8 @@ static inline int xfs_buf_submit(struct xfs_buf *bp) ...@@ -272,6 +272,8 @@ static inline int xfs_buf_submit(struct xfs_buf *bp)
} }
void xfs_buf_zero(struct xfs_buf *bp, size_t boff, size_t bsize); void xfs_buf_zero(struct xfs_buf *bp, size_t boff, size_t bsize);
void __xfs_buf_mark_corrupt(struct xfs_buf *bp, xfs_failaddr_t fa);
#define xfs_buf_mark_corrupt(bp) __xfs_buf_mark_corrupt((bp), __this_address)
/* Buffer Utility Routines */ /* Buffer Utility Routines */
extern void *xfs_buf_offset(struct xfs_buf *, size_t); extern void *xfs_buf_offset(struct xfs_buf *, size_t);
......
...@@ -345,6 +345,8 @@ xfs_corruption_error( ...@@ -345,6 +345,8 @@ xfs_corruption_error(
* Complain about the kinds of metadata corruption that we can't detect from a * Complain about the kinds of metadata corruption that we can't detect from a
* verifier, such as incorrect inter-block relationship data. Does not set * verifier, such as incorrect inter-block relationship data. Does not set
* bp->b_error. * bp->b_error.
*
* Call xfs_buf_mark_corrupt, not this function.
*/ */
void void
xfs_buf_corruption_error( xfs_buf_corruption_error(
......
...@@ -2133,7 +2133,7 @@ xfs_iunlink_update_bucket( ...@@ -2133,7 +2133,7 @@ xfs_iunlink_update_bucket(
* head of the list. * head of the list.
*/ */
if (old_value == new_agino) { if (old_value == new_agino) {
xfs_buf_corruption_error(agibp); xfs_buf_mark_corrupt(agibp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -2267,7 +2267,7 @@ xfs_iunlink( ...@@ -2267,7 +2267,7 @@ xfs_iunlink(
next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]); next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
if (next_agino == agino || if (next_agino == agino ||
!xfs_verify_agino_or_null(mp, agno, next_agino)) { !xfs_verify_agino_or_null(mp, agno, next_agino)) {
xfs_buf_corruption_error(agibp); xfs_buf_mark_corrupt(agibp);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
......
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