]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs: always log corruption errors
authorDarrick J. Wong <darrick.wong@oracle.com>
Wed, 22 Jan 2020 16:29:37 +0000 (11:29 -0500)
committerEric Sandeen <sandeen@redhat.com>
Wed, 22 Jan 2020 16:29:37 +0000 (11:29 -0500)
Source kernel commit: a5155b870d687de1a5f07e774b49b1e8ef0f6f50

Make sure we log something to dmesg whenever we return -EFSCORRUPTED up
the call stack.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
13 files changed:
libxfs/libxfs_priv.h
libxfs/util.c
libxfs/xfs_alloc.c
libxfs/xfs_attr_leaf.c
libxfs/xfs_bmap.c
libxfs/xfs_btree.c
libxfs/xfs_da_btree.c
libxfs/xfs_dir2.c
libxfs/xfs_dir2_leaf.c
libxfs/xfs_dir2_node.c
libxfs/xfs_inode_fork.c
libxfs/xfs_refcount.c
libxfs/xfs_rtbitmap.c

index 3a0282f17eccef20dce5b067f48cf515fb3792d3..90b41f0788e9893d68c85b18cb5b92500cb33655 100644 (file)
@@ -539,6 +539,8 @@ void xfs_inode_verifier_error(struct xfs_inode *ip, int error,
 
 #define xfs_buf_verifier_error(bp,e,n,bu,bus,fa) \
        xfs_verifier_error(bp, e, fa)
+void
+xfs_buf_corruption_error(struct xfs_buf *bp);
 
 /* XXX: this is clearly a bug - a shared header needs to export this */
 /* xfs_rtalloc.c */
index 885dd42bf8904d2f91d09dbcec06c8ad0abc4faa..69110076d463218eec19a43ce9d51d35594380b6 100644 (file)
@@ -636,6 +636,19 @@ xfs_inode_verifier_error(
                  ip->i_ino, name);
 }
 
+/*
+ * 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.
+ */
+void
+xfs_buf_corruption_error(
+       struct xfs_buf          *bp)
+{
+       xfs_alert(NULL, "Metadata corruption detected at %p, %s block 0x%llx",
+                 __return_address, bp->b_ops->name, bp->b_bn);
+}
+
 /*
  * This is called from I/O verifiers on v5 superblock filesystems. In the
  * kernel, it validates the metadata LSN parameter against the current LSN of
index 7cb5159e3e4695a21cb46f61d5394b67faa721af..36cd9238f1bf6be7337d16c86fc00f2587f849da 100644 (file)
@@ -697,8 +697,10 @@ xfs_alloc_update_counters(
 
        xfs_trans_agblocks_delta(tp, len);
        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);
                return -EFSCORRUPTED;
+       }
 
        xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS);
        return 0;
@@ -1043,6 +1045,7 @@ xfs_alloc_ag_vextent_small(
 
                bp = xfs_btree_get_bufs(args->mp, args->tp, args->agno, fbno);
                if (!bp) {
+                       XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, args->mp);
                        error = -EFSCORRUPTED;
                        goto error;
                }
@@ -2210,8 +2213,10 @@ xfs_free_agfl_block(
                return error;
 
        bp = xfs_btree_get_bufs(tp->t_mountp, tp, agno, agbno);
-       if (!bp)
+       if (!bp) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, tp->t_mountp);
                return -EFSCORRUPTED;
+       }
        xfs_trans_binval(tp, bp);
 
        return 0;
index fab37c10340b17c09864644c7f8adddec9a02636..92758f1ed41faef6a2633219eff0566a577db56c 100644 (file)
@@ -2342,8 +2342,10 @@ xfs_attr3_leaf_lookup_int(
        leaf = bp->b_addr;
        xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, 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);
                return -EFSCORRUPTED;
+       }
 
        /*
         * Binary search.  (note: small blocks will skip this loop)
@@ -2359,10 +2361,14 @@ xfs_attr3_leaf_lookup_int(
                else
                        break;
        }
-       if (!(probe >= 0 && (!ichdr.count || probe < ichdr.count)))
+       if (!(probe >= 0 && (!ichdr.count || probe < ichdr.count))) {
+               xfs_buf_corruption_error(bp);
                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);
                return -EFSCORRUPTED;
+       }
 
        /*
         * Since we may have duplicate hashval's, find the first matching
index d43f18afb811653f07f3cd9531c3c7f3679dd364..bd117a30a06e416050953abf75bbee1629b34f0d 100644 (file)
@@ -722,6 +722,7 @@ xfs_bmap_extents_to_btree(
        xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
        abp = xfs_btree_get_bufl(mp, tp, args.fsbno);
        if (!abp) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
                error = -EFSCORRUPTED;
                goto out_unreserve_dquot;
        }
@@ -1077,6 +1078,7 @@ xfs_bmap_add_attrfork(
        if (XFS_IFORK_Q(ip))
                goto trans_cancel;
        if (ip->i_d.di_anextents != 0) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
                error = -EFSCORRUPTED;
                goto trans_cancel;
        }
@@ -1330,6 +1332,7 @@ xfs_bmap_last_before(
        case XFS_DINODE_FMT_EXTENTS:
                break;
        default:
+               ASSERT(0);
                return -EFSCORRUPTED;
        }
 
@@ -1430,8 +1433,10 @@ xfs_bmap_last_offset(
                return 0;
 
        if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
-           XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)
+           XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) {
+               ASSERT(0);
                return -EFSCORRUPTED;
+       }
 
        error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty);
        if (error || is_empty)
@@ -5822,6 +5827,7 @@ xfs_bmap_insert_extents(
                                del_cursor);
 
        if (stop_fsb >= got.br_startoff + got.br_blockcount) {
+               ASSERT(0);
                error = -EFSCORRUPTED;
                goto del_cursor;
        }
index 5955ae36444a2f3e060fb922f928e7560745d475..5a04d3bd3a7979f4dca8c4db23320291061813d3 100644 (file)
@@ -1815,6 +1815,7 @@ xfs_btree_lookup_get_block(
 
 out_bad:
        *blkp = NULL;
+       xfs_buf_corruption_error(bp);
        xfs_trans_brelse(cur->bc_tp, bp);
        return -EFSCORRUPTED;
 }
@@ -1862,8 +1863,10 @@ xfs_btree_lookup(
        XFS_BTREE_STATS_INC(cur, lookup);
 
        /* No such thing as a zero-level tree. */
-       if (cur->bc_nlevels == 0)
+       if (cur->bc_nlevels == 0) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, cur->bc_mp);
                return -EFSCORRUPTED;
+       }
 
        block = NULL;
        keyno = 0;
index e7af4464c86ea5aacf9045903f5cf45889936af9..93a500da6675d9c4679c263decd3a962a2217d0c 100644 (file)
@@ -501,6 +501,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);
                        error = -EFSCORRUPTED;
                        goto out;
                }
@@ -513,6 +514,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);
                        error = -EFSCORRUPTED;
                        goto out;
                }
@@ -1538,8 +1540,10 @@ xfs_da3_node_lookup_int(
                        break;
                }
 
-               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);
                        return -EFSCORRUPTED;
+               }
 
                blk->magic = XFS_DA_NODE_MAGIC;
 
@@ -1551,15 +1555,18 @@ xfs_da3_node_lookup_int(
                btree = dp->d_ops->node_tree_p(node);
 
                /* 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);
                        return -EFSCORRUPTED;
+               }
 
                /* Check the level from the root. */
                if (blkno == args->geo->leafblk)
                        expected_level = nodehdr.level - 1;
-               else if (expected_level != nodehdr.level)
+               else if (expected_level != nodehdr.level) {
+                       xfs_buf_corruption_error(blk->bp);
                        return -EFSCORRUPTED;
-               else
+               else
                        expected_level--;
 
                max = nodehdr.count;
@@ -1609,12 +1616,17 @@ xfs_da3_node_lookup_int(
                }
 
                /* We can't point back to the root. */
-               if (blkno == args->geo->leafblk)
+               if (blkno == args->geo->leafblk) {
+                       XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW,
+                                       dp->i_mount);
                        return -EFSCORRUPTED;
+               }
        }
 
-       if (expected_level != 0)
+       if (expected_level != 0) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, dp->i_mount);
                return -EFSCORRUPTED;
+       }
 
        /*
         * A leaf block that ends in the hashval that we are interested in
index b3fbc4d594bd4fea0773feb253ba2217b407fad2..f34a55de8609f8696e432ac3cd86af8942e02a47 100644 (file)
@@ -598,8 +598,10 @@ xfs_dir2_isblock(
        if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
                return rval;
        rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
-       if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize)
+       if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, args->dp->i_mount);
                return -EFSCORRUPTED;
+       }
        *vp = rval;
        return 0;
 }
index ff4a04ef0ce97033cfb431a7906fee5b80f1628a..7a1e42840733ff51f4d3cbe7a29a8ac636ad321b 100644 (file)
@@ -1341,8 +1341,10 @@ xfs_dir2_leaf_removename(
        oldbest = be16_to_cpu(bf[0].length);
        ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
        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);
                return -EFSCORRUPTED;
+       }
        /*
         * Mark the former data entry unused.
         */
index d3dea3f1cb76804a4ec061c84d1e8ec78e5a57ae..783492a29f0e2a0d24e639cdb0daa40cfb881578 100644 (file)
@@ -370,8 +370,10 @@ xfs_dir2_leaf_to_node(
        leaf = lbp->b_addr;
        ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
        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);
                return -EFSCORRUPTED;
+       }
 
        /*
         * Copy freespace entries from the leaf block to the new block.
@@ -442,8 +444,10 @@ xfs_dir2_leafn_add(
         * Quick check just to make sure we are not going to index
         * into other peoples memory
         */
-       if (index < 0)
+       if (index < 0) {
+               xfs_buf_corruption_error(bp);
                return -EFSCORRUPTED;
+       }
 
        /*
         * If there are already the maximum number of leaf entries in
@@ -736,8 +740,10 @@ xfs_dir2_leafn_lookup_for_entry(
        ents = dp->d_ops->leaf_ents_p(leaf);
 
        xfs_dir3_leaf_check(dp, bp);
-       if (leafhdr.count <= 0)
+       if (leafhdr.count <= 0) {
+               xfs_buf_corruption_error(bp);
                return -EFSCORRUPTED;
+       }
 
        /*
         * Look up the hash value in the leaf entries.
index 58ba5a56ec9f956a258176ce54eb0477ffffd4a9..1d726650f429636b79eac8b9b1c1d47d73cfc544 100644 (file)
@@ -73,11 +73,15 @@ xfs_iformat_fork(
                        error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK);
                        break;
                default:
+                       xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__,
+                                       dip, sizeof(*dip), __this_address);
                        return -EFSCORRUPTED;
                }
                break;
 
        default:
+               xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
+                               sizeof(*dip), __this_address);
                return -EFSCORRUPTED;
        }
        if (error)
@@ -108,6 +112,8 @@ xfs_iformat_fork(
                error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK);
                break;
        default:
+               xfs_inode_verifier_error(ip, error, __func__, dip,
+                               sizeof(*dip), __this_address);
                error = -EFSCORRUPTED;
                break;
        }
index 8b810a30e314ada0e3d4eee476b203c7a23435ac..c68a018ad2f9375bb32564beaa6824c1c2b8cd8e 100644 (file)
@@ -1589,8 +1589,10 @@ xfs_refcount_recover_extent(
        struct list_head                *debris = priv;
        struct xfs_refcount_recovery    *rr;
 
-       if (be32_to_cpu(rec->refc.rc_refcount) != 1)
+       if (be32_to_cpu(rec->refc.rc_refcount) != 1) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, cur->bc_mp);
                return -EFSCORRUPTED;
+       }
 
        rr = kmem_alloc(sizeof(struct xfs_refcount_recovery), 0);
        xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec);
index ef6f8679fc21975d0b28f2d86ccd23e0a1da3104..84879c5ce6a5d1d3e2ab3e24737088c576c523d4 100644 (file)
@@ -15,7 +15,6 @@
 #include "xfs_bmap.h"
 #include "xfs_trans.h"
 
-
 /*
  * Realtime allocator bitmap functions shared with userspace.
  */
@@ -69,8 +68,10 @@ xfs_rtbuf_get(
        if (error)
                return error;
 
-       if (nmap == 0 || !xfs_bmap_is_real_extent(&map))
+       if (nmap == 0 || !xfs_bmap_is_real_extent(&map)) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
                return -EFSCORRUPTED;
+       }
 
        ASSERT(map.br_startblock != NULLFSBLOCK);
        error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,