]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: add a function to deal with corrupt buffers post-verifiers
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 1 May 2020 21:37:08 +0000 (17:37 -0400)
committerEric Sandeen <sandeen@redhat.com>
Fri, 1 May 2020 21:37:08 +0000 (17:37 -0400)
Source kernel commit: 8d57c21600a514d7a9237327c2496ae159bab5bb

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>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
libxfs/libxfs_priv.h
libxfs/rdwr.c
libxfs/xfs_alloc.c
libxfs/xfs_attr_leaf.c
libxfs/xfs_btree.c
libxfs/xfs_da_btree.c
libxfs/xfs_dir2_leaf.c
libxfs/xfs_dir2_node.c

index 6533ccb53af0814723fdc5ab2137984ce7615fab..120ff3dc6d181ac75f795a9d70abea8544b583dd 100644 (file)
@@ -383,6 +383,9 @@ static inline struct xfs_buf *xfs_buf_incore(struct xfs_buftarg *target,
 #define xfs_buf_zero(bp, off, len) \
        memset((bp)->b_addr + off, 0, len);
 
+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)
+
 /* mount stuff */
 #define XFS_MOUNT_32BITINODES          LIBXFS_MOUNT_32BITINODES
 #define XFS_MOUNT_ATTR2                        LIBXFS_MOUNT_ATTR2
index fd65651209aacc8b7144c8c9dcef7347b8ba274d..a236a84b8705338b16c0fe092ceb9867af1b3681 100644 (file)
@@ -1618,3 +1618,25 @@ libxfs_buf_priority(
 {
        return cache_node_get_priority(&bp->b_node);
 }
+
+/*
+ * 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);
+}
index b3abab493dbc1d1e0cd9764de9bd9e24d115963a..fdd92da398da6634c6cae139779801bc3f4dd77a 100644 (file)
@@ -718,7 +718,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 edd01eef53ceb7650a6cc4085bd3d5b318b26ccd..832979c996a5cc61b0d3a7b7a587c0056d5b9b84 100644 (file)
@@ -2336,7 +2336,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;
        }
 
@@ -2355,11 +2355,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 57862dfad8ab1eec3587485308d9c8e17908058c..51be86e4845e474966f8f8c47f612d1e7b87f9ce 100644 (file)
@@ -1759,7 +1759,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 7f26d12439b822233ea4208b87d021fbe1f9b14e..d785312fc27fc172b452ac32823b48055a737b0b 100644 (file)
@@ -587,7 +587,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;
                }
@@ -600,7 +600,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;
                }
@@ -1621,7 +1621,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;
                }
 
@@ -1636,7 +1636,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;
                }
 
@@ -1644,7 +1644,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 d73e54eb18b48c8a5386174eec322c83dd92762b..0cecd698f18bc8bc0f4a753b3387c7665f3c3902 100644 (file)
@@ -1381,7 +1381,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 ffa136b99becddc0b8b536a2b10ba22de1307bb2..3dd999c3be8fc4673b547ed2d7aeb162b173ee51 100644 (file)
@@ -436,7 +436,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;
        }
 
@@ -510,7 +510,7 @@ xfs_dir2_leafn_add(
         * into other peoples memory
         */
        if (index < 0) {
-               xfs_buf_corruption_error(bp);
+               xfs_buf_mark_corrupt(bp);
                return -EFSCORRUPTED;
        }
 
@@ -797,7 +797,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;
        }