]> 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 0ccf4f1d135858d53f12b11ad61d5fa45f194ab3..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
 
 /*
@@ -325,7 +326,7 @@ xfs_btree_sblock_verify_crc(
 
        if (xfs_sb_version_hascrc(&mp->m_sb)) {
                if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.s.bb_lsn)))
-                       return __this_address;
+                       return false;
                return xfs_buf_verify_cksum(bp, XFS_BTREE_SBLOCK_CRC_OFF);
        }
 
@@ -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);
@@ -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;
        }
@@ -1892,7 +1913,13 @@ 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;
                                *stat = 0;
@@ -1942,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;
                }
        }
@@ -2350,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);
 
@@ -2389,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);
@@ -2537,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);
@@ -2657,9 +2678,7 @@ __xfs_btree_split(
        int                     rrecs;
        int                     src_index;
        int                     error;          /* error return value */
-#ifdef DEBUG
        int                     i;
-#endif
 
        XFS_BTREE_STATS_INC(cur, split);
 
@@ -2725,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);
@@ -2923,9 +2940,7 @@ 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_STATS_INC(cur, newroot);
 
@@ -2972,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,
@@ -3229,9 +3242,7 @@ 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;
 
        ncur = NULL;
@@ -3321,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);
@@ -3524,8 +3531,8 @@ xfs_btree_kill_iroot(
        int                     error;
 #ifdef DEBUG
        union xfs_btree_ptr     ptr;
-       int                     i;
 #endif
+       int                     i;
 
        ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
        ASSERT(cur->bc_nlevels > 1);
@@ -3581,13 +3588,13 @@ 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);
+               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);
@@ -3721,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);
@@ -4060,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);
 
@@ -4836,14 +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(
        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++) {
@@ -4919,3 +4924,24 @@ xfs_btree_has_record(
        *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);
+}