]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - libxfs/xfs_btree.c
libxfs: refactor manage_zones()
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_btree.c
index 7df320d9cd2d2f63935064fa80a15e79f490d41e..eb78a9a204402aa36051d9b2cd447e11c0f7fcd6 100644 (file)
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
  * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include "libxfs_priv.h"
 #include "xfs_fs.h"
@@ -27,6 +15,7 @@
 #include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_btree.h"
+#include "xfs_errortag.h"
 #include "xfs_trace.h"
 #include "xfs_cksum.h"
 #include "xfs_alloc.h"
@@ -39,7 +28,7 @@ kmem_zone_t   *xfs_btree_cur_zone;
 /*
  * Btree magic numbers.
  */
-static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = {
+static const uint32_t xfs_magics[2][XFS_BTNUM_MAX] = {
        { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, 0, XFS_BMAP_MAGIC, XFS_IBT_MAGIC,
          XFS_FIBT_MAGIC, 0 },
        { XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC, XFS_RMAP_CRC_MAGIC,
@@ -47,58 +36,76 @@ static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = {
          XFS_REFC_CRC_MAGIC }
 };
 
-__uint32_t
+uint32_t
 xfs_btree_magic(
        int                     crc,
        xfs_btnum_t             btnum)
 {
-       __uint32_t              magic = xfs_magics[crc][btnum];
+       uint32_t                magic = xfs_magics[crc][btnum];
 
        /* Ensure we asked for crc for crc-only magics. */
        ASSERT(magic != 0);
        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,
-                       XFS_ERRTAG_BTREE_CHECK_LBLOCK,
-                       XFS_RANDOM_BTREE_CHECK_LBLOCK))) {
+       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. */
+static 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_);
                XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
@@ -107,50 +114,62 @@ 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,
-                       XFS_ERRTAG_BTREE_CHECK_SBLOCK,
-                       XFS_RANDOM_BTREE_CHECK_SBLOCK))) {
+       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_);
                XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
@@ -175,60 +194,67 @@ xfs_btree_check_block(
                return xfs_btree_check_sblock(cur, block, level, bp);
 }
 
-/*
- * Check that (long) pointer is ok.
- */
-int                                    /* error (0 or EFSCORRUPTED) */
+/* Check that this long pointer is valid and points within the fs. */
+bool
 xfs_btree_check_lptr(
-       struct xfs_btree_cur    *cur,   /* btree cursor */
-       xfs_fsblock_t           bno,    /* btree block disk address */
-       int                     level)  /* btree block level */
+       struct xfs_btree_cur    *cur,
+       xfs_fsblock_t           fsbno,
+       int                     level)
 {
-       XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
-               level > 0 &&
-               bno != NULLFSBLOCK &&
-               XFS_FSB_SANITY_CHECK(cur->bc_mp, bno));
-       return 0;
+       if (level <= 0)
+               return false;
+       return xfs_verify_fsbno(cur->bc_mp, fsbno);
 }
 
-#ifdef DEBUG
-/*
- * Check that (short) pointer is ok.
- */
-STATIC int                             /* error (0 or EFSCORRUPTED) */
+/* Check that this short pointer is valid and points within the AG. */
+bool
 xfs_btree_check_sptr(
-       struct xfs_btree_cur    *cur,   /* btree cursor */
-       xfs_agblock_t           bno,    /* btree block disk address */
-       int                     level)  /* btree block level */
+       struct xfs_btree_cur    *cur,
+       xfs_agblock_t           agbno,
+       int                     level)
 {
-       xfs_agblock_t           agblocks = cur->bc_mp->m_sb.sb_agblocks;
-
-       XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
-               level > 0 &&
-               bno != NULLAGBLOCK &&
-               bno != 0 &&
-               bno < agblocks);
-       return 0;
+       if (level <= 0)
+               return false;
+       return xfs_verify_agbno(cur->bc_mp, cur->bc_private.a.agno, agbno);
 }
 
 /*
- * Check that block ptr is ok.
+ * Check that a given (indexed) btree pointer at a certain level of a
+ * btree is valid and doesn't point past where it should.
  */
-STATIC int                             /* error (0 or EFSCORRUPTED) */
+static int
 xfs_btree_check_ptr(
-       struct xfs_btree_cur    *cur,   /* btree cursor */
-       union xfs_btree_ptr     *ptr,   /* btree block disk address */
-       int                     index,  /* offset from ptr to check */
-       int                     level)  /* btree block level */
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_ptr     *ptr,
+       int                     index,
+       int                     level)
 {
        if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
-               return xfs_btree_check_lptr(cur,
-                               be64_to_cpu((&ptr->l)[index]), level);
+               if (xfs_btree_check_lptr(cur, be64_to_cpu((&ptr->l)[index]),
+                               level))
+                       return 0;
+               xfs_err(cur->bc_mp,
+"Inode %llu fork %d: Corrupt btree %d pointer at level %d index %d.",
+                               cur->bc_private.b.ip->i_ino,
+                               cur->bc_private.b.whichfork, cur->bc_btnum,
+                               level, index);
        } else {
-               return xfs_btree_check_sptr(cur,
-                               be32_to_cpu((&ptr->s)[index]), level);
+               if (xfs_btree_check_sptr(cur, be32_to_cpu((&ptr->s)[index]),
+                               level))
+                       return 0;
+               xfs_err(cur->bc_mp,
+"AG %u: Corrupt btree %d pointer at level %d index %d.",
+                               cur->bc_private.a.agno, cur->bc_btnum,
+                               level, index);
        }
+
+       return -EFSCORRUPTED;
 }
+
+#ifdef DEBUG
+# define xfs_btree_debug_check_ptr     xfs_btree_check_ptr
+#else
+# define xfs_btree_debug_check_ptr(...)        (0)
 #endif
 
 /*
@@ -244,7 +270,7 @@ xfs_btree_lblock_calc_crc(
        struct xfs_buf          *bp)
 {
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
-       struct xfs_buf_log_item *bip = bp->b_fspriv;
+       struct xfs_buf_log_item *bip = bp->b_log_item;
 
        if (!xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
                return;
@@ -282,7 +308,7 @@ xfs_btree_sblock_calc_crc(
        struct xfs_buf          *bp)
 {
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
-       struct xfs_buf_log_item *bip = bp->b_fspriv;
+       struct xfs_buf_log_item *bip = bp->b_log_item;
 
        if (!xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
                return;
@@ -564,7 +590,7 @@ xfs_btree_ptr_offset(
 /*
  * Return a pointer to the n-th record in the btree block.
  */
-STATIC union xfs_btree_rec *
+union xfs_btree_rec *
 xfs_btree_rec_addr(
        struct xfs_btree_cur    *cur,
        int                     n,
@@ -577,7 +603,7 @@ xfs_btree_rec_addr(
 /*
  * Return a pointer to the n-th key in the btree block.
  */
-STATIC union xfs_btree_key *
+union xfs_btree_key *
 xfs_btree_key_addr(
        struct xfs_btree_cur    *cur,
        int                     n,
@@ -590,7 +616,7 @@ xfs_btree_key_addr(
 /*
  * Return a pointer to the n-th high key in the btree block.
  */
-STATIC union xfs_btree_key *
+union xfs_btree_key *
 xfs_btree_high_key_addr(
        struct xfs_btree_cur    *cur,
        int                     n,
@@ -603,7 +629,7 @@ xfs_btree_high_key_addr(
 /*
  * Return a pointer to the n-th block pointer in the btree block.
  */
-STATIC union xfs_btree_ptr *
+union xfs_btree_ptr *
 xfs_btree_ptr_addr(
        struct xfs_btree_cur    *cur,
        int                     n,
@@ -637,7 +663,7 @@ xfs_btree_get_iroot(
  * Retrieve the block pointer from the cursor at the given level.
  * This may be an inode btree root or from a buffer.
  */
-STATIC struct xfs_btree_block *                /* generic btree block pointer */
+struct xfs_btree_block *               /* generic btree block pointer */
 xfs_btree_get_block(
        struct xfs_btree_cur    *cur,   /* btree cursor */
        int                     level,  /* level in btree */
@@ -726,7 +752,8 @@ xfs_btree_firstrec(
         * Get the block pointer for this level.
         */
        block = xfs_btree_get_block(cur, level, &bp);
-       xfs_btree_check_block(cur, block, level, bp);
+       if (xfs_btree_check_block(cur, block, level, bp))
+               return 0;
        /*
         * It's empty, there is no such record.
         */
@@ -755,7 +782,8 @@ xfs_btree_lastrec(
         * Get the block pointer for this level.
         */
        block = xfs_btree_get_block(cur, level, &bp);
-       xfs_btree_check_block(cur, block, level, bp);
+       if (xfs_btree_check_block(cur, block, level, bp))
+               return 0;
        /*
         * It's empty, there is no such record.
         */
@@ -774,14 +802,14 @@ xfs_btree_lastrec(
  */
 void
 xfs_btree_offsets(
-       __int64_t       fields,         /* bitmask of fields */
+       int64_t         fields,         /* bitmask of fields */
        const short     *offsets,       /* table of field offsets */
        int             nbits,          /* number of bits to inspect */
        int             *first,         /* output: first byte offset */
        int             *last)          /* output: last byte offset */
 {
        int             i;              /* current bit number */
-       __int64_t       imask;          /* mask for current bit number */
+       int64_t         imask;          /* mask for current bit number */
 
        ASSERT(fields != 0);
        /*
@@ -822,7 +850,7 @@ xfs_btree_read_bufl(
        xfs_daddr_t             d;              /* real disk block address */
        int                     error;
 
-       if (!XFS_FSB_SANITY_CHECK(mp, fsbno))
+       if (!xfs_verify_fsbno(mp, fsbno))
                return -EFSCORRUPTED;
        d = XFS_FSB_TO_DADDR(mp, fsbno);
        error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d,
@@ -957,22 +985,30 @@ xfs_btree_readahead(
        return xfs_btree_readahead_sblock(cur, lr, block);
 }
 
-STATIC xfs_daddr_t
+STATIC int
 xfs_btree_ptr_to_daddr(
        struct xfs_btree_cur    *cur,
-       union xfs_btree_ptr     *ptr)
+       union xfs_btree_ptr     *ptr,
+       xfs_daddr_t             *daddr)
 {
-       if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
-               ASSERT(ptr->l != cpu_to_be64(NULLFSBLOCK));
+       xfs_fsblock_t           fsbno;
+       xfs_agblock_t           agbno;
+       int                     error;
 
-               return XFS_FSB_TO_DADDR(cur->bc_mp, be64_to_cpu(ptr->l));
-       } else {
-               ASSERT(cur->bc_private.a.agno != NULLAGNUMBER);
-               ASSERT(ptr->s != cpu_to_be32(NULLAGBLOCK));
+       error = xfs_btree_check_ptr(cur, ptr, 0, 1);
+       if (error)
+               return error;
 
-               return XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno,
-                                       be32_to_cpu(ptr->s));
+       if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
+               fsbno = be64_to_cpu(ptr->l);
+               *daddr = XFS_FSB_TO_DADDR(cur->bc_mp, fsbno);
+       } else {
+               agbno = be32_to_cpu(ptr->s);
+               *daddr = XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno,
+                               agbno);
        }
+
+       return 0;
 }
 
 /*
@@ -987,8 +1023,11 @@ xfs_btree_readahead_ptr(
        union xfs_btree_ptr     *ptr,
        xfs_extlen_t            count)
 {
-       xfs_buf_readahead(cur->bc_mp->m_ddev_targp,
-                         xfs_btree_ptr_to_daddr(cur, ptr),
+       xfs_daddr_t             daddr;
+
+       if (xfs_btree_ptr_to_daddr(cur, ptr, &daddr))
+               return;
+       xfs_buf_readahead(cur->bc_mp->m_ddev_targp, daddr,
                          cur->bc_mp->m_bsize * count, cur->bc_ops->buf_ops);
 }
 
@@ -1023,7 +1062,7 @@ xfs_btree_setbuf(
        }
 }
 
-STATIC int
+bool
 xfs_btree_ptr_is_null(
        struct xfs_btree_cur    *cur,
        union xfs_btree_ptr     *ptr)
@@ -1048,7 +1087,7 @@ xfs_btree_set_ptr_null(
 /*
  * Get/set/init sibling pointers
  */
-STATIC void
+void
 xfs_btree_get_sibling(
        struct xfs_btree_cur    *cur,
        struct xfs_btree_block  *block,
@@ -1251,11 +1290,14 @@ xfs_btree_get_buf_block(
 {
        struct xfs_mount        *mp = cur->bc_mp;
        xfs_daddr_t             d;
+       int                     error;
 
        /* need to sort out how callers deal with failures first */
        ASSERT(!(flags & XBF_TRYLOCK));
 
-       d = xfs_btree_ptr_to_daddr(cur, ptr);
+       error = xfs_btree_ptr_to_daddr(cur, ptr, &d);
+       if (error)
+               return error;
        *bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d,
                                 mp->m_bsize, flags);
 
@@ -1286,7 +1328,9 @@ xfs_btree_read_buf_block(
        /* need to sort out how callers deal with failures first */
        ASSERT(!(flags & XBF_TRYLOCK));
 
-       d = xfs_btree_ptr_to_daddr(cur, ptr);
+       error = xfs_btree_ptr_to_daddr(cur, ptr, &d);
+       if (error)
+               return error;
        error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d,
                                   mp->m_bsize, flags, bpp,
                                   cur->bc_ops->buf_ops);
@@ -1407,8 +1451,6 @@ xfs_btree_log_keys(
        int                     first,
        int                     last)
 {
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);
 
        if (bp) {
                xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF);
@@ -1419,8 +1461,6 @@ xfs_btree_log_keys(
                xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip,
                                xfs_ilog_fbroot(cur->bc_private.b.whichfork));
        }
-
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
 }
 
 /*
@@ -1433,15 +1473,12 @@ xfs_btree_log_recs(
        int                     first,
        int                     last)
 {
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);
 
        xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF);
        xfs_trans_log_buf(cur->bc_tp, bp,
                          xfs_btree_rec_offset(cur, first),
                          xfs_btree_rec_offset(cur, last + 1) - 1);
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
 }
 
 /*
@@ -1454,8 +1491,6 @@ xfs_btree_log_ptrs(
        int                     first,  /* index of first pointer to log */
        int                     last)   /* index of last pointer to log */
 {
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);
 
        if (bp) {
                struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
@@ -1470,7 +1505,6 @@ xfs_btree_log_ptrs(
                        xfs_ilog_fbroot(cur->bc_private.b.whichfork));
        }
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
 }
 
 /*
@@ -1512,9 +1546,6 @@ xfs_btree_log_block(
                XFS_BTREE_LBLOCK_CRC_LEN
        };
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGBI(cur, bp, fields);
-
        if (bp) {
                int nbits;
 
@@ -1542,8 +1573,6 @@ xfs_btree_log_block(
                xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip,
                        xfs_ilog_fbroot(cur->bc_private.b.whichfork));
        }
-
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
 }
 
 /*
@@ -1562,9 +1591,6 @@ xfs_btree_increment(
        int                     error;          /* error return value */
        int                     lev;
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGI(cur, level);
-
        ASSERT(level < cur->bc_nlevels);
 
        /* Read-ahead to the right at this level. */
@@ -1640,17 +1666,14 @@ xfs_btree_increment(
                cur->bc_ptrs[lev] = 1;
        }
 out1:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 1;
        return 0;
 
 out0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 0;
        return 0;
 
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
 }
 
@@ -1670,9 +1693,6 @@ xfs_btree_decrement(
        int                     lev;
        union xfs_btree_ptr     ptr;
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGI(cur, level);
-
        ASSERT(level < cur->bc_nlevels);
 
        /* Read-ahead to the left at this level. */
@@ -1738,21 +1758,18 @@ xfs_btree_decrement(
                cur->bc_ptrs[lev] = xfs_btree_get_numrecs(block);
        }
 out1:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 1;
        return 0;
 
 out0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 0;
        return 0;
 
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
 }
 
-STATIC int
+int
 xfs_btree_lookup_get_block(
        struct xfs_btree_cur    *cur,   /* btree cursor */
        int                     level,  /* level in the btree */
@@ -1760,6 +1777,7 @@ xfs_btree_lookup_get_block(
        struct xfs_btree_block  **blkp) /* return btree block */
 {
        struct xfs_buf          *bp;    /* buffer pointer for btree block */
+       xfs_daddr_t             daddr;
        int                     error = 0;
 
        /* special case the root block if in an inode */
@@ -1776,7 +1794,10 @@ xfs_btree_lookup_get_block(
         * Otherwise throw it away and get a new one.
         */
        bp = cur->bc_bufs[level];
-       if (bp && XFS_BUF_ADDR(bp) == xfs_btree_ptr_to_daddr(cur, pp)) {
+       error = xfs_btree_ptr_to_daddr(cur, pp, &daddr);
+       if (error)
+               return error;
+       if (bp && XFS_BUF_ADDR(bp) == daddr) {
                *blkp = XFS_BUF_TO_BLOCK(bp);
                return 0;
        }
@@ -1787,6 +1808,7 @@ xfs_btree_lookup_get_block(
 
        /* Check the inode owner since the verifiers don't. */
        if (xfs_sb_version_hascrc(&cur->bc_mp->m_sb) &&
+           !(cur->bc_private.b.flags & XFS_BTCUR_BPRV_INVALID_OWNER) &&
            (cur->bc_flags & XFS_BTREE_LONG_PTRS) &&
            be64_to_cpu((*blkp)->bb_u.l.bb_owner) !=
                        cur->bc_private.b.ip->i_ino)
@@ -1842,16 +1864,13 @@ xfs_btree_lookup(
        int                     *stat)  /* success/failure */
 {
        struct xfs_btree_block  *block; /* current btree block */
-       __int64_t               diff;   /* difference for the current key */
+       int64_t                 diff;   /* difference for the current key */
        int                     error;  /* error return value */
        int                     keyno;  /* current key number */
        int                     level;  /* level in the btree */
        union xfs_btree_ptr     *pp;    /* ptr to btree block */
        union xfs_btree_ptr     ptr;    /* ptr to btree block */
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGI(cur, dir);
-
        XFS_BTREE_STATS_INC(cur, lookup);
 
        /* No such thing as a zero-level tree. */
@@ -1894,10 +1913,15 @@ xfs_btree_lookup(
                        high = xfs_btree_get_numrecs(block);
                        if (!high) {
                                /* Block is empty, must be an empty leaf. */
-                               ASSERT(level == 0 && cur->bc_nlevels == 1);
+                               if (level != 0 || cur->bc_nlevels != 1) {
+                                       XFS_CORRUPTION_ERROR(__func__,
+                                                       XFS_ERRLEVEL_LOW,
+                                                       cur->bc_mp, block,
+                                                       sizeof(*block));
+                                       return -EFSCORRUPTED;
+                               }
 
                                cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE;
-                               XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
                                *stat = 0;
                                return 0;
                        }
@@ -1945,11 +1969,10 @@ xfs_btree_lookup(
                                keyno = 1;
                        pp = xfs_btree_ptr_addr(cur, keyno, block);
 
-#ifdef DEBUG
-                       error = xfs_btree_check_ptr(cur, pp, 0, level);
+                       error = xfs_btree_debug_check_ptr(cur, pp, 0, level);
                        if (error)
                                goto error0;
-#endif
+
                        cur->bc_ptrs[level] = keyno;
                }
        }
@@ -1972,7 +1995,6 @@ xfs_btree_lookup(
                        if (error)
                                goto error0;
                        XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1);
-                       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
                        *stat = 1;
                        return 0;
                }
@@ -1987,16 +2009,14 @@ xfs_btree_lookup(
                *stat = 1;
        else
                *stat = 0;
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        return 0;
 
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
 }
 
 /* Find the high key storage area from a regular key. */
-STATIC union xfs_btree_key *
+union xfs_btree_key *
 xfs_btree_high_key_from_key(
        struct xfs_btree_cur    *cur,
        union xfs_btree_key     *key)
@@ -2070,7 +2090,7 @@ xfs_btree_get_node_keys(
 }
 
 /* Derive the keys for any btree block. */
-STATIC void
+void
 xfs_btree_get_keys(
        struct xfs_btree_cur    *cur,
        struct xfs_btree_block  *block,
@@ -2137,10 +2157,8 @@ __xfs_btree_updkeys(
                trace_xfs_btree_updkeys(cur, level, bp);
 #ifdef DEBUG
                error = xfs_btree_check_block(cur, block, level, bp);
-               if (error) {
-                       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+               if (error)
                        return error;
-               }
 #endif
                ptr = cur->bc_ptrs[level];
                nlkey = xfs_btree_key_addr(cur, ptr, block);
@@ -2192,9 +2210,6 @@ xfs_btree_update_keys(
        if (cur->bc_flags & XFS_BTREE_OVERLAPPING)
                return __xfs_btree_updkeys(cur, level, block, bp, false);
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGIK(cur, level, keyp);
-
        /*
         * Go up the tree from this level toward the root.
         * At each level, update the key value to the value input.
@@ -2209,10 +2224,8 @@ xfs_btree_update_keys(
                block = xfs_btree_get_block(cur, level, &bp);
 #ifdef DEBUG
                error = xfs_btree_check_block(cur, block, level, bp);
-               if (error) {
-                       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+               if (error)
                        return error;
-               }
 #endif
                ptr = cur->bc_ptrs[level];
                kp = xfs_btree_key_addr(cur, ptr, block);
@@ -2220,7 +2233,6 @@ xfs_btree_update_keys(
                xfs_btree_log_keys(cur, bp, ptr, ptr);
        }
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        return 0;
 }
 
@@ -2240,9 +2252,6 @@ xfs_btree_update(
        int                     ptr;
        union xfs_btree_rec     *rp;
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGR(cur, rec);
-
        /* Pick up the current block. */
        block = xfs_btree_get_block(cur, 0, &bp);
 
@@ -2275,11 +2284,9 @@ xfs_btree_update(
                        goto error0;
        }
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        return 0;
 
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
 }
 
@@ -2307,9 +2314,6 @@ xfs_btree_lshift(
        int                     error;          /* error return value */
        int                     i;
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGI(cur, level);
-
        if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
            level == cur->bc_nlevels - 1)
                goto out0;
@@ -2372,11 +2376,11 @@ xfs_btree_lshift(
 
                lpp = xfs_btree_ptr_addr(cur, lrecs, left);
                rpp = xfs_btree_ptr_addr(cur, 1, right);
-#ifdef DEBUG
-               error = xfs_btree_check_ptr(cur, rpp, 0, level);
+
+               error = xfs_btree_debug_check_ptr(cur, rpp, 0, level);
                if (error)
                        goto error0;
-#endif
+
                xfs_btree_copy_keys(cur, lkp, rkp, 1);
                xfs_btree_copy_ptrs(cur, lpp, rpp, 1);
 
@@ -2411,15 +2415,14 @@ xfs_btree_lshift(
        XFS_BTREE_STATS_ADD(cur, moves, rrecs - 1);
        if (level > 0) {
                /* It's a nonleaf. operate on keys and ptrs */
-#ifdef DEBUG
                int                     i;              /* loop index */
 
                for (i = 0; i < rrecs; i++) {
-                       error = xfs_btree_check_ptr(cur, rpp, i + 1, level);
+                       error = xfs_btree_debug_check_ptr(cur, rpp, i + 1, level);
                        if (error)
                                goto error0;
                }
-#endif
+
                xfs_btree_shift_keys(cur,
                                xfs_btree_key_addr(cur, 2, right),
                                -1, rrecs);
@@ -2468,21 +2471,17 @@ xfs_btree_lshift(
        /* Slide the cursor value left one. */
        cur->bc_ptrs[level]--;
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 1;
        return 0;
 
 out0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 0;
        return 0;
 
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
 
 error1:
-       XFS_BTREE_TRACE_CURSOR(tcur, XBT_ERROR);
        xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
        return error;
 }
@@ -2509,9 +2508,6 @@ xfs_btree_rshift(
        int                     error;          /* error return value */
        int                     i;              /* loop counter */
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGI(cur, level);
-
        if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
            (level == cur->bc_nlevels - 1))
                goto out0;
@@ -2566,22 +2562,18 @@ xfs_btree_rshift(
                rkp = xfs_btree_key_addr(cur, 1, right);
                rpp = xfs_btree_ptr_addr(cur, 1, right);
 
-#ifdef DEBUG
                for (i = rrecs - 1; i >= 0; i--) {
-                       error = xfs_btree_check_ptr(cur, rpp, i, level);
+                       error = xfs_btree_debug_check_ptr(cur, rpp, i, level);
                        if (error)
                                goto error0;
                }
-#endif
 
                xfs_btree_shift_keys(cur, rkp, 1, rrecs);
                xfs_btree_shift_ptrs(cur, rpp, 1, rrecs);
 
-#ifdef DEBUG
-               error = xfs_btree_check_ptr(cur, lpp, 0, level);
+               error = xfs_btree_debug_check_ptr(cur, lpp, 0, level);
                if (error)
                        goto error0;
-#endif
 
                /* Now put the new data in, and log it. */
                xfs_btree_copy_keys(cur, rkp, lkp, 1);
@@ -2644,21 +2636,17 @@ xfs_btree_rshift(
 
        xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 1;
        return 0;
 
 out0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 0;
        return 0;
 
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
 
 error1:
-       XFS_BTREE_TRACE_CURSOR(tcur, XBT_ERROR);
        xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
        return error;
 }
@@ -2690,12 +2678,7 @@ __xfs_btree_split(
        int                     rrecs;
        int                     src_index;
        int                     error;          /* error return value */
-#ifdef DEBUG
        int                     i;
-#endif
-
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGIPK(cur, level, *ptrp, key);
 
        XFS_BTREE_STATS_INC(cur, split);
 
@@ -2761,13 +2744,11 @@ __xfs_btree_split(
                rkp = xfs_btree_key_addr(cur, 1, right);
                rpp = xfs_btree_ptr_addr(cur, 1, right);
 
-#ifdef DEBUG
                for (i = src_index; i < rrecs; i++) {
-                       error = xfs_btree_check_ptr(cur, lpp, i, level);
+                       error = xfs_btree_debug_check_ptr(cur, lpp, i, level);
                        if (error)
                                goto error0;
                }
-#endif
 
                /* Copy the keys & pointers to the new block. */
                xfs_btree_copy_keys(cur, rkp, lkp, rrecs);
@@ -2846,16 +2827,13 @@ __xfs_btree_split(
                (*curp)->bc_ptrs[level + 1]++;
        }
        *ptrp = rptr;
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 1;
        return 0;
 out0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 0;
        return 0;
 
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
 }
 
@@ -2883,7 +2861,7 @@ xfs_btree_split_worker(
        struct xfs_btree_split_args     *args = container_of(work,
                                                struct xfs_btree_split_args, work);
        unsigned long           pflags;
-       unsigned long           new_pflags = PF_FSTRANS;
+       unsigned long           new_pflags = PF_MEMALLOC_NOFS;
 
        /*
         * we are in a transaction context here, but may also be doing work
@@ -2962,11 +2940,8 @@ xfs_btree_new_iroot(
        union xfs_btree_ptr     nptr;           /* new block addr */
        int                     level;          /* btree level */
        int                     error;          /* error return code */
-#ifdef DEBUG
        int                     i;              /* loop counter */
-#endif
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
        XFS_BTREE_STATS_INC(cur, newroot);
 
        ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
@@ -2980,10 +2955,9 @@ xfs_btree_new_iroot(
        error = cur->bc_ops->alloc_block(cur, pp, &nptr, stat);
        if (error)
                goto error0;
-       if (*stat == 0) {
-               XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
+       if (*stat == 0)
                return 0;
-       }
+
        XFS_BTREE_STATS_INC(cur, alloc);
 
        /* Copy the root into a real block. */
@@ -3013,20 +2987,18 @@ xfs_btree_new_iroot(
        xfs_btree_copy_keys(cur, ckp, kp, xfs_btree_get_numrecs(cblock));
 
        cpp = xfs_btree_ptr_addr(cur, 1, cblock);
-#ifdef DEBUG
        for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) {
-               error = xfs_btree_check_ptr(cur, pp, i, level);
+               error = xfs_btree_debug_check_ptr(cur, pp, i, level);
                if (error)
                        goto error0;
        }
-#endif
+
        xfs_btree_copy_ptrs(cur, cpp, pp, xfs_btree_get_numrecs(cblock));
 
-#ifdef DEBUG
-       error = xfs_btree_check_ptr(cur, &nptr, 0, level);
+       error = xfs_btree_debug_check_ptr(cur, &nptr, 0, level);
        if (error)
                goto error0;
-#endif
+
        xfs_btree_copy_ptrs(cur, pp, &nptr, 1);
 
        xfs_iroot_realloc(cur->bc_private.b.ip,
@@ -3046,10 +3018,8 @@ xfs_btree_new_iroot(
        *logflags |=
                XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_private.b.whichfork);
        *stat = 1;
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        return 0;
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
 }
 
@@ -3074,7 +3044,6 @@ xfs_btree_new_root(
        union xfs_btree_ptr     rptr;
        union xfs_btree_ptr     lptr;
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
        XFS_BTREE_STATS_INC(cur, newroot);
 
        /* initialise our start point from the cursor */
@@ -3174,14 +3143,11 @@ xfs_btree_new_root(
        xfs_btree_setbuf(cur, cur->bc_nlevels, nbp);
        cur->bc_ptrs[cur->bc_nlevels] = nptr;
        cur->bc_nlevels++;
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 1;
        return 0;
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
 out0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 0;
        return 0;
 }
@@ -3202,7 +3168,7 @@ xfs_btree_make_block_unfull(
 
        if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
            level == cur->bc_nlevels - 1) {
-               struct xfs_inode *ip = cur->bc_private.b.ip;
+               struct xfs_inode *ip = cur->bc_private.b.ip;
 
                if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) {
                        /* A root block that can be made bigger. */
@@ -3276,14 +3242,9 @@ xfs_btree_insrec(
        int                     ptr;    /* key/record index */
        int                     numrecs;/* number of records */
        int                     error;  /* error return value */
-#ifdef DEBUG
        int                     i;
-#endif
        xfs_daddr_t             old_bn;
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGIPR(cur, level, *ptrp, &rec);
-
        ncur = NULL;
        lkey = &nkey;
 
@@ -3296,14 +3257,12 @@ xfs_btree_insrec(
                error = xfs_btree_new_root(cur, stat);
                xfs_btree_set_ptr_null(cur, ptrp);
 
-               XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
                return error;
        }
 
        /* If we're off the left edge, return failure. */
        ptr = cur->bc_ptrs[level];
        if (ptr == 0) {
-               XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
                *stat = 0;
                return 0;
        }
@@ -3373,22 +3332,18 @@ xfs_btree_insrec(
                kp = xfs_btree_key_addr(cur, ptr, block);
                pp = xfs_btree_ptr_addr(cur, ptr, block);
 
-#ifdef DEBUG
                for (i = numrecs - ptr; i >= 0; i--) {
-                       error = xfs_btree_check_ptr(cur, pp, i, level);
+                       error = xfs_btree_debug_check_ptr(cur, pp, i, level);
                        if (error)
                                return error;
                }
-#endif
 
                xfs_btree_shift_keys(cur, kp, 1, numrecs - ptr + 1);
                xfs_btree_shift_ptrs(cur, pp, 1, numrecs - ptr + 1);
 
-#ifdef DEBUG
-               error = xfs_btree_check_ptr(cur, ptrp, 0, level);
+               error = xfs_btree_debug_check_ptr(cur, ptrp, 0, level);
                if (error)
                        goto error0;
-#endif
 
                /* Now put the new data in, bump numrecs and log it. */
                xfs_btree_copy_keys(cur, kp, key, 1);
@@ -3461,12 +3416,10 @@ xfs_btree_insrec(
                *curp = ncur;
        }
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 1;
        return 0;
 
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
 }
 
@@ -3544,11 +3497,9 @@ xfs_btree_insert(
                }
        } while (!xfs_btree_ptr_is_null(cur, &nptr));
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = i;
        return 0;
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
 }
 
@@ -3580,10 +3531,8 @@ xfs_btree_kill_iroot(
        int                     error;
 #ifdef DEBUG
        union xfs_btree_ptr     ptr;
-       int                     i;
 #endif
-
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
+       int                     i;
 
        ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
        ASSERT(cur->bc_nlevels > 1);
@@ -3639,22 +3588,18 @@ xfs_btree_kill_iroot(
 
        pp = xfs_btree_ptr_addr(cur, 1, block);
        cpp = xfs_btree_ptr_addr(cur, 1, cblock);
-#ifdef DEBUG
+
        for (i = 0; i < numrecs; i++) {
-               error = xfs_btree_check_ptr(cur, cpp, i, level - 1);
-               if (error) {
-                       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+               error = xfs_btree_debug_check_ptr(cur, cpp, i, level - 1);
+               if (error)
                        return error;
-               }
        }
-#endif
+
        xfs_btree_copy_ptrs(cur, pp, cpp, numrecs);
 
        error = xfs_btree_free_block(cur, cbp);
-       if (error) {
-               XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+       if (error)
                return error;
-       }
 
        cur->bc_bufs[level - 1] = NULL;
        be16_add_cpu(&block->bb_level, -1);
@@ -3662,7 +3607,6 @@ xfs_btree_kill_iroot(
                XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_private.b.whichfork));
        cur->bc_nlevels--;
 out0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        return 0;
 }
 
@@ -3678,7 +3622,6 @@ xfs_btree_kill_root(
 {
        int                     error;
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
        XFS_BTREE_STATS_INC(cur, killroot);
 
        /*
@@ -3688,16 +3631,13 @@ xfs_btree_kill_root(
        cur->bc_ops->set_root(cur, newroot, -1);
 
        error = xfs_btree_free_block(cur, bp);
-       if (error) {
-               XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+       if (error)
                return error;
-       }
 
        cur->bc_bufs[level] = NULL;
        cur->bc_ra[level] = 0;
        cur->bc_nlevels--;
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        return 0;
 }
 
@@ -3716,7 +3656,6 @@ xfs_btree_dec_cursor(
                        return error;
        }
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 1;
        return 0;
 }
@@ -3752,15 +3691,11 @@ xfs_btree_delrec(
        struct xfs_btree_cur    *tcur;          /* temporary btree cursor */
        int                     numrecs;        /* temporary numrec count */
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGI(cur, level);
-
        tcur = NULL;
 
        /* Get the index of the entry being deleted, check for nothing there. */
        ptr = cur->bc_ptrs[level];
        if (ptr == 0) {
-               XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
                *stat = 0;
                return 0;
        }
@@ -3777,7 +3712,6 @@ xfs_btree_delrec(
 
        /* Fail if we're off the end of the block. */
        if (ptr > numrecs) {
-               XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
                *stat = 0;
                return 0;
        }
@@ -3794,13 +3728,11 @@ xfs_btree_delrec(
                lkp = xfs_btree_key_addr(cur, ptr + 1, block);
                lpp = xfs_btree_ptr_addr(cur, ptr + 1, block);
 
-#ifdef DEBUG
                for (i = 0; i < numrecs - ptr; i++) {
-                       error = xfs_btree_check_ptr(cur, lpp, i, level);
+                       error = xfs_btree_debug_check_ptr(cur, lpp, i, level);
                        if (error)
                                goto error0;
                }
-#endif
 
                if (ptr < numrecs) {
                        xfs_btree_shift_keys(cur, lkp, -1, numrecs - ptr);
@@ -4052,7 +3984,7 @@ xfs_btree_delrec(
                                tcur = NULL;
                                if (level == 0)
                                        cur->bc_ptrs[0]++;
-                               XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
+
                                *stat = 1;
                                return 0;
                        }
@@ -4133,13 +4065,13 @@ xfs_btree_delrec(
                lpp = xfs_btree_ptr_addr(cur, lrecs + 1, left);
                rkp = xfs_btree_key_addr(cur, 1, right);
                rpp = xfs_btree_ptr_addr(cur, 1, right);
-#ifdef DEBUG
+
                for (i = 1; i < rrecs; i++) {
-                       error = xfs_btree_check_ptr(cur, rpp, i, level);
+                       error = xfs_btree_debug_check_ptr(cur, rpp, i, level);
                        if (error)
                                goto error0;
                }
-#endif
+
                xfs_btree_copy_keys(cur, lkp, rkp, rrecs);
                xfs_btree_copy_ptrs(cur, lpp, rpp, rrecs);
 
@@ -4222,13 +4154,11 @@ xfs_btree_delrec(
         * call updkeys directly.
         */
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        /* Return value means the next level up has something to do. */
        *stat = 2;
        return 0;
 
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        if (tcur)
                xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
        return error;
@@ -4249,8 +4179,6 @@ xfs_btree_delete(
        int                     i;
        bool                    joined = false;
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-
        /*
         * Go up the tree, starting at leaf level.
         *
@@ -4286,11 +4214,9 @@ xfs_btree_delete(
                }
        }
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = i;
        return 0;
 error0:
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
 }
 
@@ -4395,7 +4321,7 @@ xfs_btree_visit_blocks(
                        xfs_btree_readahead_ptr(cur, ptr, 1);
 
                        /* save for the next iteration of the loop */
-                       lptr = *ptr;
+                       xfs_btree_copy_ptrs(cur, &lptr, ptr, 1);
                }
 
                /* for each buffer in the level */
@@ -4435,7 +4361,7 @@ xfs_btree_visit_blocks(
  * recovery completion writes the changes to disk.
  */
 struct xfs_btree_block_change_owner_info {
-       __uint64_t              new_owner;
+       uint64_t                new_owner;
        struct list_head        *buffer_list;
 };
 
@@ -4451,10 +4377,15 @@ xfs_btree_block_change_owner(
 
        /* modify the owner */
        block = xfs_btree_get_block(cur, level, &bp);
-       if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
+       if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
+               if (block->bb_u.l.bb_owner == cpu_to_be64(bbcoi->new_owner))
+                       return 0;
                block->bb_u.l.bb_owner = cpu_to_be64(bbcoi->new_owner);
-       else
+       } else {
+               if (block->bb_u.s.bb_owner == cpu_to_be32(bbcoi->new_owner))
+                       return 0;
                block->bb_u.s.bb_owner = cpu_to_be32(bbcoi->new_owner);
+       }
 
        /*
         * If the block is a root block hosted in an inode, we might not have a
@@ -4463,16 +4394,19 @@ xfs_btree_block_change_owner(
         * block is formatted into the on-disk inode fork. We still change it,
         * though, so everything is consistent in memory.
         */
-       if (bp) {
-               if (cur->bc_tp) {
-                       xfs_trans_ordered_buf(cur->bc_tp, bp);
+       if (!bp) {
+               ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
+               ASSERT(level == cur->bc_nlevels - 1);
+               return 0;
+       }
+
+       if (cur->bc_tp) {
+               if (!xfs_trans_ordered_buf(cur->bc_tp, bp)) {
                        xfs_btree_log_block(cur, bp, XFS_BB_OWNER);
-               } else {
-                       xfs_buf_delwri_queue(bp, bbcoi->buffer_list);
+                       return -EAGAIN;
                }
        } else {
-               ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
-               ASSERT(level == cur->bc_nlevels - 1);
+               xfs_buf_delwri_queue(bp, bbcoi->buffer_list);
        }
 
        return 0;
@@ -4481,7 +4415,7 @@ xfs_btree_block_change_owner(
 int
 xfs_btree_change_owner(
        struct xfs_btree_cur    *cur,
-       __uint64_t              new_owner,
+       uint64_t                new_owner,
        struct list_head        *buffer_list)
 {
        struct xfs_btree_block_change_owner_info        bbcoi;
@@ -4493,6 +4427,51 @@ xfs_btree_change_owner(
                        &bbcoi);
 }
 
+/* Verify the v5 fields of a long-format btree block. */
+xfs_failaddr_t
+xfs_btree_lblock_v5hdr_verify(
+       struct xfs_buf          *bp,
+       uint64_t                owner)
+{
+       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
+
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return __this_address;
+       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->b_bn))
+               return __this_address;
+       if (owner != XFS_RMAP_OWN_UNKNOWN &&
+           be64_to_cpu(block->bb_u.l.bb_owner) != owner)
+               return __this_address;
+       return NULL;
+}
+
+/* Verify a long-format btree block. */
+xfs_failaddr_t
+xfs_btree_lblock_verify(
+       struct xfs_buf          *bp,
+       unsigned int            max_recs)
+{
+       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
+
+       /* numrecs verification */
+       if (be16_to_cpu(block->bb_numrecs) > max_recs)
+               return __this_address;
+
+       /* sibling pointer verification */
+       if (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) &&
+           !xfs_verify_fsbno(mp, be64_to_cpu(block->bb_u.l.bb_leftsib)))
+               return __this_address;
+       if (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) &&
+           !xfs_verify_fsbno(mp, be64_to_cpu(block->bb_u.l.bb_rightsib)))
+               return __this_address;
+
+       return NULL;
+}
+
 /**
  * xfs_btree_sblock_v5hdr_verify() -- verify the v5 fields of a short-format
  *                                   btree block
@@ -4501,7 +4480,7 @@ xfs_btree_change_owner(
  * @max_recs: pointer to the m_*_mxr max records field in the xfs mount
  * @pag_max_level: pointer to the per-ag max level field
  */
-bool
+xfs_failaddr_t
 xfs_btree_sblock_v5hdr_verify(
        struct xfs_buf          *bp)
 {
@@ -4510,14 +4489,14 @@ xfs_btree_sblock_v5hdr_verify(
        struct xfs_perag        *pag = bp->b_pag;
 
        if (!xfs_sb_version_hascrc(&mp->m_sb))
-               return false;
+               return __this_address;
        if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
-               return false;
+               return __this_address;
        if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
-               return false;
+               return __this_address;
        if (pag && be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno)
-               return false;
-       return true;
+               return __this_address;
+       return NULL;
 }
 
 /**
@@ -4526,29 +4505,29 @@ xfs_btree_sblock_v5hdr_verify(
  * @bp: buffer containing the btree block
  * @max_recs: maximum records allowed in this btree node
  */
-bool
+xfs_failaddr_t
 xfs_btree_sblock_verify(
        struct xfs_buf          *bp,
        unsigned int            max_recs)
 {
        struct xfs_mount        *mp = bp->b_target->bt_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
+       xfs_agblock_t           agno;
 
        /* numrecs verification */
        if (be16_to_cpu(block->bb_numrecs) > max_recs)
-               return false;
+               return __this_address;
 
        /* sibling pointer verification */
-       if (!block->bb_u.s.bb_leftsib ||
-           (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks &&
-            block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK)))
-               return false;
-       if (!block->bb_u.s.bb_rightsib ||
-           (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks &&
-            block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK)))
-               return false;
-
-       return true;
+       agno = xfs_daddr_to_agno(mp, XFS_BUF_ADDR(bp));
+       if (block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK) &&
+           !xfs_verify_agbno(mp, agno, be32_to_cpu(block->bb_u.s.bb_leftsib)))
+               return __this_address;
+       if (block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK) &&
+           !xfs_verify_agbno(mp, agno, be32_to_cpu(block->bb_u.s.bb_rightsib)))
+               return __this_address;
+
+       return NULL;
 }
 
 /*
@@ -4557,7 +4536,6 @@ xfs_btree_sblock_verify(
  */
 uint
 xfs_btree_compute_maxlevels(
-       struct xfs_mount        *mp,
        uint                    *limits,
        unsigned long           len)
 {
@@ -4585,7 +4563,7 @@ xfs_btree_simple_query_range(
 {
        union xfs_btree_rec             *recp;
        union xfs_btree_key             rec_key;
-       __int64_t                       diff;
+       int64_t                         diff;
        int                             stat;
        bool                            firstrec = true;
        int                             error;
@@ -4682,8 +4660,8 @@ xfs_btree_overlapped_query_range(
        union xfs_btree_key             *hkp;
        union xfs_btree_rec             *recp;
        struct xfs_btree_block          *block;
-       __int64_t                       ldiff;
-       __int64_t                       hdiff;
+       int64_t                         ldiff;
+       int64_t                         hdiff;
        int                             level;
        struct xfs_buf                  *bp;
        int                             i;
@@ -4849,27 +4827,28 @@ xfs_btree_query_all(
        xfs_btree_query_range_fn        fn,
        void                            *priv)
 {
-       union xfs_btree_irec            low_rec;
-       union xfs_btree_irec            high_rec;
+       union xfs_btree_key             low_key;
+       union xfs_btree_key             high_key;
 
-       memset(&low_rec, 0, sizeof(low_rec));
-       memset(&high_rec, 0xFF, sizeof(high_rec));
-       return xfs_btree_query_range(cur, &low_rec, &high_rec, fn, priv);
+       memset(&cur->bc_rec, 0, sizeof(cur->bc_rec));
+       memset(&low_key, 0, sizeof(low_key));
+       memset(&high_key, 0xFF, sizeof(high_key));
+
+       return xfs_btree_simple_query_range(cur, &low_key, &high_key, fn, priv);
 }
 
 /*
  * Calculate the number of blocks needed to store a given number of records
  * in a short-format (per-AG metadata) btree.
  */
-xfs_extlen_t
+unsigned long long
 xfs_btree_calc_size(
-       struct xfs_mount        *mp,
        uint                    *limits,
        unsigned long long      len)
 {
        int                     level;
        int                     maxrecs;
-       xfs_extlen_t            rval;
+       unsigned long long      rval;
 
        maxrecs = limits[0];
        for (level = 0, rval = 0; len > 1; level++) {
@@ -4903,3 +4882,66 @@ xfs_btree_count_blocks(
        return xfs_btree_visit_blocks(cur, xfs_btree_count_blocks_helper,
                        blocks);
 }
+
+/* Compare two btree pointers. */
+int64_t
+xfs_btree_diff_two_ptrs(
+       struct xfs_btree_cur            *cur,
+       const union xfs_btree_ptr       *a,
+       const union xfs_btree_ptr       *b)
+{
+       if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
+               return (int64_t)be64_to_cpu(a->l) - be64_to_cpu(b->l);
+       return (int64_t)be32_to_cpu(a->s) - be32_to_cpu(b->s);
+}
+
+/* If there's an extent, we're done. */
+STATIC int
+xfs_btree_has_record_helper(
+       struct xfs_btree_cur            *cur,
+       union xfs_btree_rec             *rec,
+       void                            *priv)
+{
+       return XFS_BTREE_QUERY_RANGE_ABORT;
+}
+
+/* Is there a record covering a given range of keys? */
+int
+xfs_btree_has_record(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_irec    *low,
+       union xfs_btree_irec    *high,
+       bool                    *exists)
+{
+       int                     error;
+
+       error = xfs_btree_query_range(cur, low, high,
+                       &xfs_btree_has_record_helper, NULL);
+       if (error == XFS_BTREE_QUERY_RANGE_ABORT) {
+               *exists = true;
+               return 0;
+       }
+       *exists = false;
+       return error;
+}
+
+/* Are there more records in this btree? */
+bool
+xfs_btree_has_more_records(
+       struct xfs_btree_cur    *cur)
+{
+       struct xfs_btree_block  *block;
+       struct xfs_buf          *bp;
+
+       block = xfs_btree_get_block(cur, 0, &bp);
+
+       /* There are still records in this block. */
+       if (cur->bc_ptrs[0] < xfs_btree_get_numrecs(block))
+               return true;
+
+       /* There are more record blocks. */
+       if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
+               return block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK);
+       else
+               return block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK);
+}