]> 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 cc1320f7c50e66c6779d5df411f50209e5e812b9..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"
@@ -230,7 +218,6 @@ xfs_btree_check_sptr(
        return xfs_verify_agbno(cur->bc_mp, cur->bc_private.a.agno, agbno);
 }
 
-#ifdef DEBUG
 /*
  * Check that a given (indexed) btree pointer at a certain level of a
  * btree is valid and doesn't point past where it should.
@@ -243,17 +230,31 @@ xfs_btree_check_ptr(
        int                     level)
 {
        if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
-               XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
-                               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 {
-               XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
-                               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 0;
+       return -EFSCORRUPTED;
 }
+
+#ifdef DEBUG
+# define xfs_btree_debug_check_ptr     xfs_btree_check_ptr
+#else
+# define xfs_btree_debug_check_ptr(...)        (0)
 #endif
 
 /*
@@ -269,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;
@@ -307,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;
@@ -849,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,
@@ -984,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;
 }
 
 /*
@@ -1014,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);
 }
 
@@ -1278,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);
 
@@ -1313,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);
@@ -1434,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);
@@ -1446,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);
 }
 
 /*
@@ -1460,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);
 }
 
 /*
@@ -1481,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);
@@ -1497,7 +1505,6 @@ xfs_btree_log_ptrs(
                        xfs_ilog_fbroot(cur->bc_private.b.whichfork));
        }
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
 }
 
 /*
@@ -1539,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;
 
@@ -1569,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);
 }
 
 /*
@@ -1589,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. */
@@ -1667,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;
 }
 
@@ -1697,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. */
@@ -1765,17 +1758,14 @@ 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;
 }
 
@@ -1787,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 */
@@ -1803,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;
        }
@@ -1877,9 +1871,6 @@ xfs_btree_lookup(
        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. */
@@ -1922,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;
                        }
@@ -1973,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;
                }
        }
@@ -2000,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;
                }
@@ -2015,11 +2009,9 @@ 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;
 }
 
@@ -2165,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);
@@ -2220,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.
@@ -2237,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);
@@ -2248,7 +2233,6 @@ xfs_btree_update_keys(
                xfs_btree_log_keys(cur, bp, ptr, ptr);
        }
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        return 0;
 }
 
@@ -2268,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);
 
@@ -2303,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;
 }
 
@@ -2335,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;
@@ -2400,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);
 
@@ -2439,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);
@@ -2496,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;
 }
@@ -2537,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;
@@ -2594,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);
@@ -2672,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;
 }
@@ -2718,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);
 
@@ -2789,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);
@@ -2874,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;
 }
 
@@ -2990,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);
@@ -3008,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. */
@@ -3041,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,
@@ -3074,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;
 }
 
@@ -3102,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 */
@@ -3202,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;
 }
@@ -3230,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. */
@@ -3304,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;
 
@@ -3324,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;
        }
@@ -3401,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);
@@ -3489,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;
 }
 
@@ -3572,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;
 }
 
@@ -3608,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);
@@ -3667,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);
@@ -3690,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;
 }
 
@@ -3706,7 +3622,6 @@ xfs_btree_kill_root(
 {
        int                     error;
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
        XFS_BTREE_STATS_INC(cur, killroot);
 
        /*
@@ -3716,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;
 }
 
@@ -3744,7 +3656,6 @@ xfs_btree_dec_cursor(
                        return error;
        }
 
-       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        *stat = 1;
        return 0;
 }
@@ -3780,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;
        }
@@ -3805,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;
        }
@@ -3822,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);
@@ -4080,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;
                        }
@@ -4161,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);
 
@@ -4250,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;
@@ -4277,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.
         *
@@ -4314,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;
 }
 
@@ -4529,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
@@ -4537,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)
 {
@@ -4546,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;
 }
 
 /**
@@ -4562,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;
+       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 true;
+       return NULL;
 }
 
 /*
@@ -4593,7 +4536,6 @@ xfs_btree_sblock_verify(
  */
 uint
 xfs_btree_compute_maxlevels(
-       struct xfs_mount        *mp,
        uint                    *limits,
        unsigned long           len)
 {
@@ -4899,15 +4841,14 @@ xfs_btree_query_all(
  * 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++) {
@@ -4953,3 +4894,54 @@ xfs_btree_diff_two_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);
+}