]> git.baikalelectronics.ru Git - kernel.git/commitdiff
xfs: add a function to deal with corrupt buffers post-verifiers
authorDarrick J. Wong <darrick.wong@oracle.com>
Wed, 26 Oct 2022 06:28:21 +0000 (11:58 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 29 Oct 2022 08:20:33 +0000 (10:20 +0200)
commit b18a4654aa8f24463784c67ee5c2b9e31444b32c upstream.

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>
Acked-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Chandan Babu R <chandan.babu@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
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 084d39d8856bd4c0cff1380a58450cac194cfb6e..1193fd6e4bad075a01b26c9b36daedfbc995169c 100644 (file)
@@ -685,7 +685,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 c86ddbf6d105b385ccf86aa7c44feda97ab12997..e69332d8f1cb5f5e2c6e7ab72c1fe39078f96f1e 100644 (file)
@@ -2288,7 +2288,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;
        }
 
@@ -2307,11 +2307,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 a13a25e922ec656c931ad1412b98610ea2cb3217..8c43cac15832b28724c0f2014230dc7408c6e8c3 100644 (file)
@@ -1820,7 +1820,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 1e2dc65adeb85fe3318d6db04c642fbe3fac9b7e..12ef16c157dc7b2840ed39eb7d2345035fc7f190 100644 (file)
@@ -504,7 +504,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;
                }
@@ -517,7 +517,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;
                }
@@ -1544,7 +1544,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;
                }
 
@@ -1559,7 +1559,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;
                }
 
@@ -1567,7 +1567,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 388b5da12228706926a91e66534ced7fdf0ae3df..c8ee3250b749853e222cfc75eab92d4be69d306e 100644 (file)
@@ -1344,7 +1344,7 @@ xfs_dir2_leaf_removename(
        ltp = xfs_dir2_leaf_tail_p(args->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 35e698fa85fd77974e1b4efd2b031c04d7260cc3..1c8a12f229b522f2192ee381161f1b2427c4dcb9 100644 (file)
@@ -375,7 +375,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;
        }
 
@@ -449,7 +449,7 @@ xfs_dir2_leafn_add(
         * into other peoples memory
         */
        if (index < 0) {
-               xfs_buf_corruption_error(bp);
+               xfs_buf_mark_corrupt(bp);
                return -EFSCORRUPTED;
        }
 
@@ -745,7 +745,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 9c88203b537b1b6fb0878fcbf8c096a37887b3f0..f052de128fa18a32321efd5faf7fe21059993456 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;
        }
@@ -196,7 +196,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;
@@ -281,7 +281,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 8b9b500e75e81155f41e05e0f15b13b495b63c19..8c09728344497cb019606fec3ffadabe78584458 100644 (file)
@@ -271,7 +271,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 1264ac63e4e55a74d6af2e79bade5db60d66c8e6..948824d044b328da2ee08a10c50ceb8542977188 100644 (file)
@@ -1546,6 +1546,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 f6ce17d8d8480f2836c5440d35313facb5802ac9..621467ab17c875b978c0e895cbdd6a72ce0bd4b1 100644 (file)
@@ -270,6 +270,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 d8cdb27fe6ed33d773c3c1c898f16f3a2360a8fe..b32c47c20e8a4bbb601c12b9c91a1f51f1a8c470 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 30202d8c25e4fe894cc1e1b4f07ccc5b9b593fd7..5f18c5c8c5b875bb6720c0af30e6dff86042667a 100644 (file)
@@ -2149,7 +2149,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;
        }
 
@@ -2283,7 +2283,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;
        }