]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs: support leaves in the incore btree root block in xfs_iroot_realloc
authorDarrick J. Wong <djwong@kernel.org>
Tue, 7 Mar 2023 03:55:36 +0000 (19:55 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 22 Nov 2023 23:03:36 +0000 (15:03 -0800)
Add some logic to xfs_iroot_realloc so that we can handle leaf records
in the btree root block correctly.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
db/bmap_inflate.c
libxfs/xfs_bmap_btree.c
libxfs/xfs_bmap_btree.h
libxfs/xfs_inode_fork.c
libxfs/xfs_inode_fork.h
repair/bmap_repair.c

index fc9f12e5e344428ed89377aacf1cdfabd5074bc2..e9db97d265483f2bac778bbe98e432dafc90659d 100644 (file)
@@ -282,7 +282,7 @@ iroot_size(
        unsigned int            nr_this_level,
        void                    *priv)
 {
-       return xfs_bmap_broot_space_calc(cur->bc_mp, nr_this_level);
+       return xfs_bmap_broot_space_calc(cur->bc_mp, level, nr_this_level);
 }
 
 static int
index 9c72ccab414bacb12d12a89efd9323689871f77e..f2ba117d9374c1969037122be716b0cdbaabe532 100644 (file)
@@ -520,6 +520,7 @@ xfs_bmbt_broot_move(
        size_t                  dst_bytes,
        struct xfs_btree_block  *src_broot,
        size_t                  src_bytes,
+       unsigned int            level,
        unsigned int            numrecs)
 {
        struct xfs_mount        *mp = ip->i_mount;
@@ -527,6 +528,7 @@ xfs_bmbt_broot_move(
        void                    *sptr;
 
        ASSERT(xfs_bmap_bmdr_space(src_broot) <= xfs_inode_fork_size(ip, whichfork));
+       ASSERT(level > 0);
 
        /*
         * We always have to move the pointers because they are not butted
@@ -837,7 +839,7 @@ xfs_bmbt_iroot_alloc(
        struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
 
        xfs_iroot_alloc(ip, whichfork,
-                       xfs_bmap_broot_space_calc(ip->i_mount, 1));
+                       xfs_bmap_broot_space_calc(ip->i_mount, 1, 1));
 
        /* Fill in the root. */
        xfs_btree_init_block(ip->i_mount, ifp->if_broot, &xfs_bmbt_ops, 1, 1,
index a9ddc9b42e614a4ea35b810b1ffbd71df1a83fe6..d20321bfe2f60191d36c1ae5afd3c688ffffbf47 100644 (file)
@@ -161,8 +161,11 @@ xfs_bmap_broot_ptr_addr(
 static inline size_t
 xfs_bmap_broot_space_calc(
        struct xfs_mount        *mp,
+       unsigned int            level,
        unsigned int            nrecs)
 {
+       ASSERT(level > 0);
+
        /*
         * If the bmbt root block is empty, we should be converting the fork
         * to extents format.  Hence, the size is zero.
@@ -183,7 +186,7 @@ xfs_bmap_broot_space(
        struct xfs_mount        *mp,
        struct xfs_bmdr_block   *bb)
 {
-       return xfs_bmap_broot_space_calc(mp, be16_to_cpu(bb->bb_numrecs));
+       return xfs_bmap_broot_space_calc(mp, 1, be16_to_cpu(bb->bb_numrecs));
 }
 
 /* Compute the space required for the ondisk root block. */
index 626f735431d764be080acd78c57ceaacd0c87dcd..1835918ace4b7379e7455582c246676ff630cc20 100644 (file)
@@ -407,6 +407,7 @@ xfs_iroot_realloc(
        struct xfs_btree_block          *new_broot;
        size_t                          new_size;
        size_t                          old_size = ifp->if_broot_bytes;
+       unsigned int                    level;
        int                             cur_max;
        int                             new_max;
 
@@ -421,16 +422,17 @@ xfs_iroot_realloc(
        if (old_size == 0) {
                ASSERT(rec_diff > 0);
 
-               new_size = ops->size(mp, rec_diff);
+               new_size = ops->size(mp, 0, rec_diff);
                xfs_iroot_alloc(ip, whichfork, new_size);
                return;
        }
 
        /* Compute the new and old record count and space requirements. */
-       cur_max = ops->maxrecs(mp, old_size, false);
+       level = be16_to_cpu(ifp->if_broot->bb_level);
+       cur_max = ops->maxrecs(mp, old_size, level == 0);
        new_max = cur_max + rec_diff;
        ASSERT(new_max >= 0);
-       new_size = ops->size(mp, new_max);
+       new_size = ops->size(mp, level, new_max);
 
        if (rec_diff > 0) {
                /*
@@ -442,7 +444,7 @@ xfs_iroot_realloc(
                                         GFP_NOFS | __GFP_NOFAIL);
                ifp->if_broot_bytes = new_size;
                ops->move(ip, whichfork, ifp->if_broot, new_size,
-                               ifp->if_broot, old_size, cur_max);
+                               ifp->if_broot, old_size, level, cur_max);
                return;
        }
 
@@ -459,7 +461,7 @@ xfs_iroot_realloc(
        /* Reallocate the btree root and move the contents. */
        new_broot = kmem_alloc(new_size, KM_NOFS);
        ops->move(ip, whichfork, new_broot, new_size, ifp->if_broot,
-                       ifp->if_broot_bytes, new_max);
+                       ifp->if_broot_bytes, level, new_max);
 
        kmem_free(ifp->if_broot);
        ifp->if_broot = new_broot;
index 1ac9a7a8b5f5e10dc59e3e67fd3513b0dfb50d8c..9a0136f82738dcd2ddb5958b5c57ed406e14187e 100644 (file)
@@ -279,7 +279,8 @@ struct xfs_ifork_broot_ops {
                        bool leaf);
 
        /* Calculate the bytes required for the incore btree root block. */
-       size_t (*size)(struct xfs_mount *mp, unsigned int nrecs);
+       size_t (*size)(struct xfs_mount *mp, unsigned int level,
+                       unsigned int nrecs);
 
        /*
         * Move an incore btree root from one buffer to another.  Note that
@@ -289,7 +290,7 @@ struct xfs_ifork_broot_ops {
        void (*move)(struct xfs_inode *ip, int whichfork,
                        struct xfs_btree_block *dst_broot, size_t dst_bytes,
                        struct xfs_btree_block *src_broot, size_t src_bytes,
-                       unsigned int numrecs);
+                       unsigned int level, unsigned int numrecs);
 };
 
 void xfs_iroot_realloc(struct xfs_inode *ip, int whichfork,
index 198652463ab58173b9b05bcab7badf336da3a3dd..120619a81c7b705e5cbe9f345903b353fd5c4614 100644 (file)
@@ -285,7 +285,7 @@ xrep_bmap_iroot_size(
 {
        ASSERT(level > 0);
 
-       return xfs_bmap_broot_space_calc(cur->bc_mp, nr_this_level);
+       return xfs_bmap_broot_space_calc(cur->bc_mp, level, nr_this_level);
 }
 
 /* Update the inode counters. */