Home Home > GIT Browse > openSUSE-15.0
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Iliopoulos <ailiopoulos@suse.com>2019-05-17 17:19:19 +0200
committerAnthony Iliopoulos <ailiopoulos@suse.com>2019-05-17 17:19:19 +0200
commit59af3d528725871a42229f6e84776d4af03a463b (patch)
treefabd3328fa50b7cc88802581608c5c953e63a662
parenta98bae69f689ffcad33ed6dc223fc0c5968d6b09 (diff)
xfs: refactor btree block header checking functions
(bsc#1123663).
-rw-r--r--patches.fixes/xfs-refactor-btree-block-header-checking-functions.patch279
-rw-r--r--series.conf1
2 files changed, 280 insertions, 0 deletions
diff --git a/patches.fixes/xfs-refactor-btree-block-header-checking-functions.patch b/patches.fixes/xfs-refactor-btree-block-header-checking-functions.patch
new file mode 100644
index 0000000000..0091045f8a
--- /dev/null
+++ b/patches.fixes/xfs-refactor-btree-block-header-checking-functions.patch
@@ -0,0 +1,279 @@
+From 52c732eee78b47ac2eb828b1c7fa611cd37b0090 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Tue, 17 Oct 2017 21:37:33 -0700
+Subject: [PATCH] xfs: refactor btree block header checking functions
+Git-commit: 52c732eee78b47ac2eb828b1c7fa611cd37b0090
+Patch-mainline: v4.15-rc1
+References: bsc#1123663
+
+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>
+Acked-by: Anthony Iliopoulos <ailiopoulos@suse.com>
+
+---
+ fs/xfs/libxfs/xfs_btree.c | 168 +++++++++++++++++++++++++++-------------------
+ fs/xfs/libxfs/xfs_btree.h | 8 +++
+ fs/xfs/libxfs/xfs_types.h | 6 ++
+ fs/xfs/xfs_linux.h | 7 ++
+ 4 files changed, 121 insertions(+), 68 deletions(-)
+
+diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
+index ae19f242c237..8bb20e1cf57b 100644
+--- a/fs/xfs/libxfs/xfs_btree.c
++++ b/fs/xfs/libxfs/xfs_btree.c
+@@ -63,44 +63,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_);
+@@ -110,48 +129,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_);
+diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
+index 8f52eda8eb82..3f8001de2493 100644
+--- a/fs/xfs/libxfs/xfs_btree.h
++++ b/fs/xfs/libxfs/xfs_btree.h
+@@ -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.
+diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
+index 0220159bd463..f04dbfb2f50d 100644
+--- a/fs/xfs/libxfs/xfs_types.h
++++ b/fs/xfs/libxfs/xfs_types.h
+@@ -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.
+ */
+diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h
+index dcd1292664b3..00a5efeec496 100644
+--- a/fs/xfs/xfs_linux.h
++++ b/fs/xfs/xfs_linux.h
+@@ -142,6 +142,13 @@ typedef __u32 xfs_nlink_t;
+ #define SYNCHRONIZE() barrier()
+ #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; })
++
+ #define XFS_PROJID_DEFAULT 0
+
+ #define MIN(a,b) (min(a,b))
+--
+2.16.4
+
diff --git a/series.conf b/series.conf
index f089aed6da..40dcfadd23 100644
--- a/series.conf
+++ b/series.conf
@@ -8239,6 +8239,7 @@
patches.fixes/xfs-return-a-distinct-error-code-value-for-IGET_INCO.patch
patches.fixes/xfs-create-block-pointer-check-functions.patch
patches.fixes/xfs-refactor-btree-pointer-checks.patch
+ patches.fixes/xfs-refactor-btree-block-header-checking-functions.patch
patches.fixes/0029-xfs-add-a-xfs_bmap_fork_to_state-helper.patch
patches.fixes/0030-xfs-make-better-use-of-the-state-variable-in-xfs_bma.patch
patches.fixes/0031-xfs-remove-post-bmap-tracing-in-xfs_bmap_local_to_ex.patch