summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-09-01 11:15:44 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-10-22 16:40:53 -0700
commitb77e454582eb2cc69a1db776b664ecea9f0e75ca (patch)
tree460c0b7e70edfd6ae83686f228e600aad44c8b99
parent23d77e3a004d43ca1e6053d805fa31f672ea91d7 (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 ce1a738dbfed..ce7f0e34a121 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.c
+++ b/fs/xfs/libxfs/xfs_bmap_btree.c
@@ -520,6 +520,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;
@@ -527,6 +528,7 @@ xfs_bmbt_broot_move(
void *sptr;
ASSERT(xfs_bmap_bmdr_space(src_broot) <= XFS_IFORK_SIZE(ip, whichfork));
+ ASSERT(level > 0);
/*
* We always have to move the pointers because they are not butted
@@ -796,7 +798,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 13920e1acb53..aa5e48826dd4 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.h
+++ b/fs/xfs/libxfs/xfs_bmap_btree.h
@@ -156,8 +156,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.
@@ -178,7 +181,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 1326db84b833..801a6f7dbd0c 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -390,6 +390,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;
@@ -404,16 +405,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) {
/*
@@ -425,7 +427,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;
}
@@ -442,7 +444,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 89aad41a8832..cf82be263b48 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.h
+++ b/fs/xfs/libxfs/xfs_inode_fork.h
@@ -248,7 +248,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
@@ -258,7 +259,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 2b50b6873d7f..000a6818a28c 100644
--- a/fs/xfs/scrub/bmap_repair.c
+++ b/fs/xfs/scrub/bmap_repair.c
@@ -334,7 +334,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. */