From c37d5c0740409bff3fd6288bbc30f6e3e4f85f34 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 15 Aug 2024 11:48:37 -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 --- fs/xfs/libxfs/xfs_bmap_btree.c | 4 +++- fs/xfs/libxfs/xfs_bmap_btree.h | 5 ++++- fs/xfs/libxfs/xfs_inode_fork.c | 12 +++++++----- fs/xfs/libxfs/xfs_inode_fork.h | 5 +++-- fs/xfs/scrub/bmap_repair.c | 2 +- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c index c541cbe29bc5..4ff74e30cefb 100644 --- a/fs/xfs/libxfs/xfs_bmap_btree.c +++ b/fs/xfs/libxfs/xfs_bmap_btree.c @@ -525,6 +525,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; @@ -532,6 +533,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 @@ -820,7 +822,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/fs/xfs/libxfs/xfs_bmap_btree.h b/fs/xfs/libxfs/xfs_bmap_btree.h index df6a60452260..53f76cfa37d0 100644 --- a/fs/xfs/libxfs/xfs_bmap_btree.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c index b34ee3336d49..1606d59ca8f4 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.c +++ b/fs/xfs/libxfs/xfs_inode_fork.c @@ -413,6 +413,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; @@ -427,16 +428,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) { /* @@ -448,7 +450,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; } @@ -466,7 +468,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/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h index c7a16d5f4090..53fea66481c0 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.h +++ b/fs/xfs/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/fs/xfs/scrub/bmap_repair.c b/fs/xfs/scrub/bmap_repair.c index 49dc38acc66b..2c51157f4bdd 100644 --- a/fs/xfs/scrub/bmap_repair.c +++ b/fs/xfs/scrub/bmap_repair.c @@ -480,7 +480,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