xfs: add a function to deal with corrupt buffers post-verifiers
authorDarrick J. Wong <darrick.wong@oracle.com>
Wed, 11 Mar 2020 17:37:54 +0000 (10:37 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Thu, 12 Mar 2020 14:58:12 +0000 (07:58 -0700)
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: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
12 files changed:
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_attr_leaf.c
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_da_btree.c
fs/xfs/libxfs/xfs_dir2_leaf.c
fs/xfs/libxfs/xfs_dir2_node.c
fs/xfs/xfs_attr_inactive.c
fs/xfs/xfs_attr_list.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_error.c
fs/xfs/xfs_inode.c

index 9e99c0c94defe488f64d9e241a0fca4d94833469..5bc58b72a16f2ff30f878f3a468457aae64a9bde 100644 (file)
@@ -722,7 +722,7 @@ xfs_alloc_update_counters(
        xfs_trans_agblocks_delta(tp, len);
        if (unlikely(be32_to_cpu(agf->agf_freeblks) >
                     be32_to_cpu(agf->agf_length))) {
-               xfs_buf_corruption_error(agbp);
+               xfs_buf_mark_corrupt(agbp);
                return -EFSCORRUPTED;
        }
 
index 4be04aeee278a0a903a4090ab81055913dfaadb2..6eda1828a079ce3eec6997a38744f61b3cc5db17 100644 (file)
@@ -2339,7 +2339,7 @@ xfs_attr3_leaf_lookup_int(
        xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf);
        entries = xfs_attr3_leaf_entryp(leaf);
        if (ichdr.count >= args->geo->blksize / 8) {
-               xfs_buf_corruption_error(bp);
+               xfs_buf_mark_corrupt(bp);
                return -EFSCORRUPTED;
        }
 
@@ -2358,11 +2358,11 @@ xfs_attr3_leaf_lookup_int(
                        break;
        }
        if (!(probe >= 0 && (!ichdr.count || probe < ichdr.count))) {
-               xfs_buf_corruption_error(bp);
+               xfs_buf_mark_corrupt(bp);
                return -EFSCORRUPTED;
        }
        if (!(span <= 4 || be32_to_cpu(entry->hashval) == hashval)) {
-               xfs_buf_corruption_error(bp);
+               xfs_buf_mark_corrupt(bp);
                return -EFSCORRUPTED;
        }
 
index fd300dc93ca473e60f9d9c8f067fb43c13a002ce..0599a3ee7d88e7486b1c262f9fc8206cb06e63f0 100644 (file)
@@ -1762,7 +1762,7 @@ xfs_btree_lookup_get_block(
 
 out_bad:
        *blkp = NULL;
-       xfs_buf_corruption_error(bp);
+       xfs_buf_mark_corrupt(bp);
        xfs_trans_brelse(cur->bc_tp, bp);
        return -EFSCORRUPTED;
 }
index e864c3d47f60af226120ac4e1019a11067c21a4f..a7880c6285dbaf4dfc49f0d2f3f973d8e2ae1fd0 100644 (file)
@@ -590,7 +590,7 @@ xfs_da3_split(
        node = oldblk->bp->b_addr;
        if (node->hdr.info.forw) {
                if (be32_to_cpu(node->hdr.info.forw) != addblk->blkno) {
-                       xfs_buf_corruption_error(oldblk->bp);
+                       xfs_buf_mark_corrupt(oldblk->bp);
                        error = -EFSCORRUPTED;
                        goto out;
                }
@@ -603,7 +603,7 @@ xfs_da3_split(
        node = oldblk->bp->b_addr;
        if (node->hdr.info.back) {
                if (be32_to_cpu(node->hdr.info.back) != addblk->blkno) {
-                       xfs_buf_corruption_error(oldblk->bp);
+                       xfs_buf_mark_corrupt(oldblk->bp);
                        error = -EFSCORRUPTED;
                        goto out;
                }
@@ -1624,7 +1624,7 @@ xfs_da3_node_lookup_int(
                }
 
                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;
                }
 
@@ -1639,7 +1639,7 @@ xfs_da3_node_lookup_int(
 
                /* Tree taller than we can handle; bail out! */
                if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) {
-                       xfs_buf_corruption_error(blk->bp);
+                       xfs_buf_mark_corrupt(blk->bp);
                        return -EFSCORRUPTED;
                }
 
@@ -1647,7 +1647,7 @@ xfs_da3_node_lookup_int(
                if (blkno == args->geo->leafblk)
                        expected_level = nodehdr.level - 1;
                else if (expected_level != nodehdr.level) {
-                       xfs_buf_corruption_error(blk->bp);
+                       xfs_buf_mark_corrupt(blk->bp);
                        return -EFSCORRUPTED;
                } else
                        expected_level--;
index a131b520aac7dc20ab666f6dc6ea08950bb2b62e..95d2a3f92d75de71091ded0b56e7d89713652d24 100644 (file)
@@ -1383,7 +1383,7 @@ xfs_dir2_leaf_removename(
        ltp = xfs_dir2_leaf_tail_p(geo, leaf);
        bestsp = xfs_dir2_leaf_bests_p(ltp);
        if (be16_to_cpu(bestsp[db]) != oldbest) {
-               xfs_buf_corruption_error(lbp);
+               xfs_buf_mark_corrupt(lbp);
                return -EFSCORRUPTED;
        }
        /*
index a0cc5e2403069fe12610f1a66e60797c4cca9dd4..dbd1e901da92bc9555783edde74bfbcc6df1a088 100644 (file)
@@ -439,7 +439,7 @@ xfs_dir2_leaf_to_node(
        ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
        if (be32_to_cpu(ltp->bestcount) >
                                (uint)dp->i_d.di_size / args->geo->blksize) {
-               xfs_buf_corruption_error(lbp);
+               xfs_buf_mark_corrupt(lbp);
                return -EFSCORRUPTED;
        }
 
@@ -513,7 +513,7 @@ xfs_dir2_leafn_add(
         * into other peoples memory
         */
        if (index < 0) {
-               xfs_buf_corruption_error(bp);
+               xfs_buf_mark_corrupt(bp);
                return -EFSCORRUPTED;
        }
 
@@ -800,7 +800,7 @@ xfs_dir2_leafn_lookup_for_entry(
 
        xfs_dir3_leaf_check(dp, bp);
        if (leafhdr.count <= 0) {
-               xfs_buf_corruption_error(bp);
+               xfs_buf_mark_corrupt(bp);
                return -EFSCORRUPTED;
        }
 
index fe8f60b59ec4d99f9b790a02009bc23743d64e45..c42f90e16b4fa3ed01a769cdbf7918a920de9e38 100644 (file)
@@ -145,7 +145,7 @@ xfs_attr3_node_inactive(
         * Since this code is recursive (gasp!) we must protect ourselves.
         */
        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 */
                return -EFSCORRUPTED;
        }
@@ -194,7 +194,7 @@ xfs_attr3_node_inactive(
                        error = xfs_attr3_leaf_inactive(trans, dp, child_bp);
                        break;
                default:
-                       xfs_buf_corruption_error(child_bp);
+                       xfs_buf_mark_corrupt(child_bp);
                        xfs_trans_brelse(*trans, child_bp);
                        error = -EFSCORRUPTED;
                        break;
@@ -289,7 +289,7 @@ xfs_attr3_root_inactive(
                break;
        default:
                error = -EFSCORRUPTED;
-               xfs_buf_corruption_error(bp);
+               xfs_buf_mark_corrupt(bp);
                xfs_trans_brelse(*trans, bp);
                break;
        }
index 017f5691abfad7ca5bc546e9f89300a26b7a3f06..5ff1d929d3b5f0fb5521e7fbb76d15777bd093ee 100644 (file)
@@ -274,7 +274,7 @@ xfs_attr_node_list_lookup(
        return 0;
 
 out_corruptbuf:
-       xfs_buf_corruption_error(bp);
+       xfs_buf_mark_corrupt(bp);
        xfs_trans_brelse(tp, bp);
        return -EFSCORRUPTED;
 }
index f8e4fee206ffe1d7d8199db0d8312009c2556f70..6552e5991f73d4904630f8623993d78287712417 100644 (file)
@@ -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).
  */
index d79a1fe5d738df70f8b08c453fdcc74c9549e779..9a04c53c2488ccdb8d9bedf4b7b0e21f770a7102 100644 (file)
@@ -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_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 */
 extern void *xfs_buf_offset(struct xfs_buf *, size_t);
index 331765afc53e427011c08fd4d9188447e9ded01d..57068d4ffba2f1524020572a9d3a2d0f090334f8 100644 (file)
@@ -345,6 +345,8 @@ xfs_corruption_error(
  * 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
  * bp->b_error.
+ *
+ * Call xfs_buf_mark_corrupt, not this function.
  */
 void
 xfs_buf_corruption_error(
index addc3ee0cb739c88a62332743615346954a90b7d..d65d2509d5e0055a10c59a692cf519b7429d1fdd 100644 (file)
@@ -2133,7 +2133,7 @@ xfs_iunlink_update_bucket(
         * head of the list.
         */
        if (old_value == new_agino) {
-               xfs_buf_corruption_error(agibp);
+               xfs_buf_mark_corrupt(agibp);
                return -EFSCORRUPTED;
        }
 
@@ -2267,7 +2267,7 @@ xfs_iunlink(
        next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
        if (next_agino == agino ||
            !xfs_verify_agino_or_null(mp, agno, next_agino)) {
-               xfs_buf_corruption_error(agibp);
+               xfs_buf_mark_corrupt(agibp);
                return -EFSCORRUPTED;
        }