]> 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>
Wed, 3 Jul 2024 21:22:14 +0000 (14:22 -0700)
committerChristoph Hellwig <hch@lst.de>
Mon, 12 Aug 2024 08:40:03 +0000 (10:40 +0200)
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 1de6d3439ab3d3490d4933c1c587c8767ce6e195..5c23c0919df8ec50e41b893e48f1b2891f574a2f 100644 (file)
@@ -269,7 +269,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 bc9d1a3fe090fa8bf29e80fd57cdc61c7aa74094..3a667a8a18ca0295fc3adc1f801778e0d859dd52 100644 (file)
@@ -524,6 +524,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;
@@ -531,6 +532,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
@@ -819,7 +821,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_bmbt_init_block(ip, ifp->if_broot, NULL, 1, 1);
index df6a60452260ea5799a38ba7cd5cc180ac98b032..53f76cfa37d088b6e498041f9d5c32d917dfc630 100644 (file)
@@ -162,8 +162,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.
@@ -184,7 +187,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 c1a3a970233c0e3d4a50e7da30333601f2364363..98f788901755031dd2dc6ce3534c25b8c0ea4317 100644 (file)
@@ -411,6 +411,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;
 
@@ -425,16 +426,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) {
                /*
@@ -446,7 +448,7 @@ xfs_iroot_realloc(
                                         GFP_KERNEL | __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;
        }
 
@@ -464,7 +466,7 @@ xfs_iroot_realloc(
        new_broot = kmalloc(new_size,
                        GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOFAIL);
        ops->move(ip, whichfork, new_broot, new_size, ifp->if_broot,
-                       ifp->if_broot_bytes, new_max);
+                       ifp->if_broot_bytes, level, new_max);
 
        kfree(ifp->if_broot);
        ifp->if_broot = new_broot;
index c7a16d5f4090e8ce8a30d5ca3ababa911707c665..53fea66481c0a001f2bbe708ec013b4f5e071cda 100644 (file)
@@ -275,7 +275,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
@@ -285,7 +286,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 b341caf627d5fda768abc063f5b4f1668df3fb5c..f1eb04c968c680f65fb4c4ba5b08f4fff324fea6 100644 (file)
@@ -284,7 +284,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. */