[PATCH 05/10] xfs: move the zero records logic into xfs_bmap_broot_space_calc

Darrick J. Wong
2024-08-27T23:35:02Z

From: Darrick J. Wong <djwong@kernel.org>

The bmap btree cannot ever have zero key/pointer records in an incore
btree block. If the number of records drops to zero, that means we're
converting the fork to extents format and are trying to remove the tree.
This logic won't hold for the future realtime rmap btree, so move the
logic into the bmbt code.

This helps us remove a level of indentation in xfs_iroot_realloc because
we can handle the zero-size case in a single place instead of repeatedly
checking it. We'll refactor further in the next patch.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
fs/xfs/libxfs/xfs_bmap_btree.h | 7 +++++
fs/xfs/libxfs/xfs_inode_fork.c | 56 ++++++++++++++--------------------------
2 files changed, 27 insertions(+), 36 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_bmap_btree.h b/fs/xfs/libxfs/xfs_bmap_btree.h
index af47174fca084..b7842c3420f04 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.h
+++ b/fs/xfs/libxfs/xfs_bmap_btree.h
@@ -163,6 +163,13 @@ xfs_bmap_broot_space_calc(
struct xfs_mount *mp,
unsigned int nrecs)
{
+ /*
+ * If the bmbt root block is empty, we should be converting the fork
+ * to extents format. Hence, the size is zero.
+ */
+ if (nrecs == 0)
+ return 0;
+
return xfs_bmbt_block_len(mp) + \
(nrecs * (sizeof(struct xfs_bmbt_key) + sizeof(xfs_bmbt_ptr_t)));
}
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 973e027e3d883..acb1e9cc45b76 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -447,48 +447,32 @@ xfs_iroot_realloc(
cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
new_max = cur_max + rec_diff;
ASSERT(new_max >= 0);
- if (new_max > 0)
- new_size = xfs_bmap_broot_space_calc(mp, new_max);
- else
- new_size = 0;
- if (new_size > 0) {
- new_broot = kmalloc(new_size, GFP_KERNEL | __GFP_NOFAIL);
- /*
- * First copy over the btree block header.
- */
- memcpy(new_broot, ifp->if_broot,
- xfs_bmbt_block_len(ip->i_mount));
- } else {
- new_broot = NULL;
+
+ new_size = xfs_bmap_broot_space_calc(mp, new_max);
+ if (new_size == 0) {
+ kfree(ifp->if_broot);
+ ifp->if_broot = NULL;
+ ifp->if_broot_bytes = 0;
+ return;
}

- /*
- * Only copy the keys and pointers if there are any.
- */
- if (new_max > 0) {
- /*
- * First copy the keys.
- */
- op = (char *)xfs_bmbt_key_addr(mp, ifp->if_broot, 1);
- np = (char *)xfs_bmbt_key_addr(mp, new_broot, 1);
- memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_key_t));
+ new_broot = kmalloc(new_size, GFP_KERNEL | __GFP_NOFAIL);
+ memcpy(new_broot, ifp->if_broot, xfs_bmbt_block_len(ip->i_mount));
+
+ op = (char *)xfs_bmbt_key_addr(mp, ifp->if_broot, 1);
+ np = (char *)xfs_bmbt_key_addr(mp, new_broot, 1);
+ memcpy(np, op, new_max * sizeof(xfs_bmbt_key_t));
+
+ op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,
+ ifp->if_broot_bytes);
+ np = (char *)xfs_bmap_broot_ptr_addr(mp, new_broot, 1, (int)new_size);
+ memcpy(np, op, new_max * sizeof(xfs_fsblock_t));

- /*
- * Then copy the pointers.
- */
- op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,
- ifp->if_broot_bytes);
- np = (char *)xfs_bmap_broot_ptr_addr(mp, new_broot, 1,
- (int)new_size);
- memcpy(np, op, new_max * (uint)sizeof(xfs_fsblock_t));
- }
kfree(ifp->if_broot);
ifp->if_broot = new_broot;
ifp->if_broot_bytes = (int)new_size;
- if (ifp->if_broot)
- ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=
- xfs_inode_fork_size(ip, whichfork));
- return;
+ ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=
+ xfs_inode_fork_size(ip, whichfork));
}