summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2022-07-14 11:15:20 -0700
committerDarrick J. Wong <djwong@kernel.org>2022-11-09 19:07:52 -0800
commita686339bb2d0cc24deb5ff6248355e9dbcbbab4e (patch)
tree15a42c02965f8abdffee79ffad08d44f77699aeb
parenta2ac2252ea8a61010d38050aac5b4c11d6b35f85 (diff)
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 <djwong@kernel.org>
-rw-r--r--fs/xfs/libxfs/xfs_bmap_btree.c4
-rw-r--r--fs/xfs/libxfs/xfs_bmap_btree.h5
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.c12
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.h5
-rw-r--r--fs/xfs/scrub/bmap_repair.c2
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 cb3f8d7637ef..9923149741d4 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.c
+++ b/fs/xfs/libxfs/xfs_bmap_btree.c
@@ -538,6 +538,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;
@@ -545,6 +546,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
@@ -863,7 +865,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_int(ip->i_mount, ifp->if_broot,
diff --git a/fs/xfs/libxfs/xfs_bmap_btree.h b/fs/xfs/libxfs/xfs_bmap_btree.h
index a9ddc9b42e61..d20321bfe2f6 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.h
+++ b/fs/xfs/libxfs/xfs_bmap_btree.h
@@ -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. */
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 0ac1c8dba2ed..b844bfd94e9c 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -395,6 +395,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;
@@ -409,16 +410,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) {
/*
@@ -430,7 +432,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;
}
@@ -447,7 +449,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;
diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h
index 7d95c402f870..3734642917a7 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.h
+++ b/fs/xfs/libxfs/xfs_inode_fork.h
@@ -277,7 +277,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
@@ -287,7 +288,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 debde5b9dca8..e44791582e72 100644
--- a/fs/xfs/scrub/bmap_repair.c
+++ b/fs/xfs/scrub/bmap_repair.c
@@ -397,7 +397,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. */