]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: refactor btree block header checking functions
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 17 Nov 2017 04:11:31 +0000 (22:11 -0600)
committerEric Sandeen <sandeen@redhat.com>
Fri, 17 Nov 2017 04:11:31 +0000 (22:11 -0600)
Source kernel commit: 52c732eee78b47ac2eb828b1c7fa611cd37b0090

Refactor the btree block header checks to have an internal function that
returns the address of the failing check without logging errors.  The
scrubber will call the internal function, while the external version
will maintain the current logging behavior.

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/xfs_btree.c
libxfs/xfs_btree.h
libxfs/xfs_types.h

index cba213a79d1340fab6d08b8e287971f03bde0768..ca7e3241cf4b32edda1844281153100cf004c3e9 100644 (file)
@@ -155,6 +155,22 @@ enum ce { CE_DEBUG, CE_CONT, CE_NOTE, CE_WARN, CE_ALERT, CE_PANIC };
 
 #ifdef __GNUC__
 #define __return_address       __builtin_return_address(0)
+
+/*
+ * Return the address of a label.  Use barrier() so that the optimizer
+ * won't reorder code to refactor the error jumpouts into a single
+ * return, which throws off the reported address.
+ */
+#define __this_address  ({ __label__ __here; __here: barrier(); &&__here; })
+/* Optimization barrier */
+
+/* The "volatile" is due to gcc bugs */
+#define barrier() __asm__ __volatile__("": : :"memory")
+#endif
+
+/* Optimization barrier */
+#ifndef barrier
+# define barrier() __memory_barrier()
 #endif
 
 #define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1
index 8413e47ef1a61ee49a8dbf60dc4041de2e7c6f5d..96236e1eedef785920f285ae66d46bd8c6c3324c 100644 (file)
@@ -59,44 +59,63 @@ xfs_btree_magic(
        return magic;
 }
 
-STATIC int                             /* error (0 or EFSCORRUPTED) */
-xfs_btree_check_lblock(
-       struct xfs_btree_cur    *cur,   /* btree cursor */
-       struct xfs_btree_block  *block, /* btree long form block pointer */
-       int                     level,  /* level of the btree block */
-       struct xfs_buf          *bp)    /* buffer for block, if any */
+/*
+ * Check a long btree block header.  Return the address of the failing check,
+ * or NULL if everything is ok.
+ */
+xfs_failaddr_t
+__xfs_btree_check_lblock(
+       struct xfs_btree_cur    *cur,
+       struct xfs_btree_block  *block,
+       int                     level,
+       struct xfs_buf          *bp)
 {
-       int                     lblock_ok = 1; /* block passes checks */
-       struct xfs_mount        *mp;    /* file system mount point */
+       struct xfs_mount        *mp = cur->bc_mp;
        xfs_btnum_t             btnum = cur->bc_btnum;
-       int                     crc;
-
-       mp = cur->bc_mp;
-       crc = xfs_sb_version_hascrc(&mp->m_sb);
+       int                     crc = xfs_sb_version_hascrc(&mp->m_sb);
 
        if (crc) {
-               lblock_ok = lblock_ok &&
-                       uuid_equal(&block->bb_u.l.bb_uuid,
-                                  &mp->m_sb.sb_meta_uuid) &&
-                       block->bb_u.l.bb_blkno == cpu_to_be64(
-                               bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
+               if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid))
+                       return __this_address;
+               if (block->bb_u.l.bb_blkno !=
+                   cpu_to_be64(bp ? bp->b_bn : XFS_BUF_DADDR_NULL))
+                       return __this_address;
+               if (block->bb_u.l.bb_pad != cpu_to_be32(0))
+                       return __this_address;
        }
 
-       lblock_ok = lblock_ok &&
-               be32_to_cpu(block->bb_magic) == xfs_btree_magic(crc, btnum) &&
-               be16_to_cpu(block->bb_level) == level &&
-               be16_to_cpu(block->bb_numrecs) <=
-                       cur->bc_ops->get_maxrecs(cur, level) &&
-               block->bb_u.l.bb_leftsib &&
-               (block->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK) ||
-                XFS_FSB_SANITY_CHECK(mp,
-                       be64_to_cpu(block->bb_u.l.bb_leftsib))) &&
-               block->bb_u.l.bb_rightsib &&
-               (block->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK) ||
-                XFS_FSB_SANITY_CHECK(mp,
-                       be64_to_cpu(block->bb_u.l.bb_rightsib)));
-
-       if (unlikely(XFS_TEST_ERROR(!lblock_ok, mp,
+       if (be32_to_cpu(block->bb_magic) != xfs_btree_magic(crc, btnum))
+               return __this_address;
+       if (be16_to_cpu(block->bb_level) != level)
+               return __this_address;
+       if (be16_to_cpu(block->bb_numrecs) >
+           cur->bc_ops->get_maxrecs(cur, level))
+               return __this_address;
+       if (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) &&
+           !xfs_btree_check_lptr(cur, be64_to_cpu(block->bb_u.l.bb_leftsib),
+                       level + 1))
+               return __this_address;
+       if (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) &&
+           !xfs_btree_check_lptr(cur, be64_to_cpu(block->bb_u.l.bb_rightsib),
+                       level + 1))
+               return __this_address;
+
+       return NULL;
+}
+
+/* Check a long btree block header. */
+int
+xfs_btree_check_lblock(
+       struct xfs_btree_cur    *cur,
+       struct xfs_btree_block  *block,
+       int                     level,
+       struct xfs_buf          *bp)
+{
+       struct xfs_mount        *mp = cur->bc_mp;
+       xfs_failaddr_t          fa;
+
+       fa = __xfs_btree_check_lblock(cur, block, level, bp);
+       if (unlikely(XFS_TEST_ERROR(fa != NULL, mp,
                        XFS_ERRTAG_BTREE_CHECK_LBLOCK))) {
                if (bp)
                        trace_xfs_btree_corrupt(bp, _RET_IP_);
@@ -106,48 +125,61 @@ xfs_btree_check_lblock(
        return 0;
 }
 
-STATIC int                             /* error (0 or EFSCORRUPTED) */
-xfs_btree_check_sblock(
-       struct xfs_btree_cur    *cur,   /* btree cursor */
-       struct xfs_btree_block  *block, /* btree short form block pointer */
-       int                     level,  /* level of the btree block */
-       struct xfs_buf          *bp)    /* buffer containing block */
+/*
+ * Check a short btree block header.  Return the address of the failing check,
+ * or NULL if everything is ok.
+ */
+xfs_failaddr_t
+__xfs_btree_check_sblock(
+       struct xfs_btree_cur    *cur,
+       struct xfs_btree_block  *block,
+       int                     level,
+       struct xfs_buf          *bp)
 {
-       struct xfs_mount        *mp;    /* file system mount point */
-       struct xfs_buf          *agbp;  /* buffer for ag. freespace struct */
-       struct xfs_agf          *agf;   /* ag. freespace structure */
-       xfs_agblock_t           agflen; /* native ag. freespace length */
-       int                     sblock_ok = 1; /* block passes checks */
+       struct xfs_mount        *mp = cur->bc_mp;
        xfs_btnum_t             btnum = cur->bc_btnum;
-       int                     crc;
-
-       mp = cur->bc_mp;
-       crc = xfs_sb_version_hascrc(&mp->m_sb);
-       agbp = cur->bc_private.a.agbp;
-       agf = XFS_BUF_TO_AGF(agbp);
-       agflen = be32_to_cpu(agf->agf_length);
+       int                     crc = xfs_sb_version_hascrc(&mp->m_sb);
 
        if (crc) {
-               sblock_ok = sblock_ok &&
-                       uuid_equal(&block->bb_u.s.bb_uuid,
-                                  &mp->m_sb.sb_meta_uuid) &&
-                       block->bb_u.s.bb_blkno == cpu_to_be64(
-                               bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
+               if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
+                       return __this_address;
+               if (block->bb_u.s.bb_blkno !=
+                   cpu_to_be64(bp ? bp->b_bn : XFS_BUF_DADDR_NULL))
+                       return __this_address;
        }
 
-       sblock_ok = sblock_ok &&
-               be32_to_cpu(block->bb_magic) == xfs_btree_magic(crc, btnum) &&
-               be16_to_cpu(block->bb_level) == level &&
-               be16_to_cpu(block->bb_numrecs) <=
-                       cur->bc_ops->get_maxrecs(cur, level) &&
-               (block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) ||
-                be32_to_cpu(block->bb_u.s.bb_leftsib) < agflen) &&
-               block->bb_u.s.bb_leftsib &&
-               (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) ||
-                be32_to_cpu(block->bb_u.s.bb_rightsib) < agflen) &&
-               block->bb_u.s.bb_rightsib;
-
-       if (unlikely(XFS_TEST_ERROR(!sblock_ok, mp,
+       if (be32_to_cpu(block->bb_magic) != xfs_btree_magic(crc, btnum))
+               return __this_address;
+       if (be16_to_cpu(block->bb_level) != level)
+               return __this_address;
+       if (be16_to_cpu(block->bb_numrecs) >
+           cur->bc_ops->get_maxrecs(cur, level))
+               return __this_address;
+       if (block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK) &&
+           !xfs_btree_check_sptr(cur, be32_to_cpu(block->bb_u.s.bb_leftsib),
+                       level + 1))
+               return __this_address;
+       if (block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK) &&
+           !xfs_btree_check_sptr(cur, be32_to_cpu(block->bb_u.s.bb_rightsib),
+                       level + 1))
+               return __this_address;
+
+       return NULL;
+}
+
+/* Check a short btree block header. */
+STATIC int
+xfs_btree_check_sblock(
+       struct xfs_btree_cur    *cur,
+       struct xfs_btree_block  *block,
+       int                     level,
+       struct xfs_buf          *bp)
+{
+       struct xfs_mount        *mp = cur->bc_mp;
+       xfs_failaddr_t          fa;
+
+       fa = __xfs_btree_check_sblock(cur, block, level, bp);
+       if (unlikely(XFS_TEST_ERROR(fa != NULL, mp,
                        XFS_ERRTAG_BTREE_CHECK_SBLOCK))) {
                if (bp)
                        trace_xfs_btree_corrupt(bp, _RET_IP_);
index 703c9d6c2c5ed84fef09bb1478bc4485d771989d..afabc6e5bd71c8684214b80f4e24d218536b08ba 100644 (file)
@@ -255,6 +255,14 @@ typedef struct xfs_btree_cur
  */
 #define        XFS_BUF_TO_BLOCK(bp)    ((struct xfs_btree_block *)((bp)->b_addr))
 
+/*
+ * Internal long and short btree block checks.  They return NULL if the
+ * block is ok or the address of the failed check otherwise.
+ */
+xfs_failaddr_t __xfs_btree_check_lblock(struct xfs_btree_cur *cur,
+               struct xfs_btree_block *block, int level, struct xfs_buf *bp);
+xfs_failaddr_t __xfs_btree_check_sblock(struct xfs_btree_cur *cur,
+               struct xfs_btree_block *block, int level, struct xfs_buf *bp);
 
 /*
  * Check that block header is ok.
index 0220159bd4636e8febb3ece887aef02a4e519791..f04dbfb2f50d6de70c25151d169adb4e2a4f12c0 100644 (file)
@@ -47,6 +47,12 @@ typedef uint64_t     xfs_filblks_t;  /* number of blocks in a file */
 typedef int64_t                xfs_srtblock_t; /* signed version of xfs_rtblock_t */
 typedef int64_t                xfs_sfiloff_t;  /* signed block number in a file */
 
+/*
+ * New verifiers will return the instruction address of the failing check.
+ * NULL means everything is ok.
+ */
+typedef void *         xfs_failaddr_t;
+
 /*
  * Null values for the types.
  */