From 302d8ea5a9bdb91a2db10aba194453e5ecd68405 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 3 Jul 2024 14:22:14 -0700 Subject: [PATCH] xfs: support leaves in the incore btree root block in xfs_iroot_realloc 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 --- db/bmap_inflate.c | 2 +- libxfs/xfs_bmap_btree.c | 4 +++- libxfs/xfs_bmap_btree.h | 5 ++++- libxfs/xfs_inode_fork.c | 12 +++++++----- libxfs/xfs_inode_fork.h | 5 +++-- repair/bmap_repair.c | 2 +- 6 files changed, 19 insertions(+), 11 deletions(-) diff --git a/db/bmap_inflate.c b/db/bmap_inflate.c index 1de6d3439..5c23c0919 100644 --- a/db/bmap_inflate.c +++ b/db/bmap_inflate.c @@ -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 diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c index bc9d1a3fe..3a667a8a1 100644 --- a/libxfs/xfs_bmap_btree.c +++ b/libxfs/xfs_bmap_btree.c @@ -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); diff --git a/libxfs/xfs_bmap_btree.h b/libxfs/xfs_bmap_btree.h index df6a60452..53f76cfa3 100644 --- a/libxfs/xfs_bmap_btree.h +++ b/libxfs/xfs_bmap_btree.h @@ -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. */ diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c index c1a3a9702..98f788901 100644 --- a/libxfs/xfs_inode_fork.c +++ b/libxfs/xfs_inode_fork.c @@ -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; diff --git a/libxfs/xfs_inode_fork.h b/libxfs/xfs_inode_fork.h index c7a16d5f4..53fea6648 100644 --- a/libxfs/xfs_inode_fork.h +++ b/libxfs/xfs_inode_fork.h @@ -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, diff --git a/repair/bmap_repair.c b/repair/bmap_repair.c index b341caf62..f1eb04c96 100644 --- a/repair/bmap_repair.c +++ b/repair/bmap_repair.c @@ -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. */ -- 2.50.1