summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2020-10-25 17:16:10 -0700
committerDarrick J. Wong <darrick.wong@oracle.com>2020-10-26 18:32:33 -0700
commit89ab00538d737dc65f40478a7ec458b92d14060b (patch)
tree3256159e2519116f5005d065512216d0fa09679b /fs
parent404f680bd3fe61449c6e3ed2f9780159c894facf (diff)
xfs: generalize the btree root reallocation function
In preparation for storing realtime rmap btree roots in an inode fork, make xfs_iroot_realloc take an ops structure that takes care of all the btree-specific geometry pieces. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/libxfs/xfs_bmap_btree.c51
-rw-r--r--fs/xfs/libxfs/xfs_btree.c22
-rw-r--r--fs/xfs/libxfs/xfs_btree.h3
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.c82
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.h23
5 files changed, 107 insertions, 74 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c
index 4996dd5bcbb0..31652174556f 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.c
+++ b/fs/xfs/libxfs/xfs_bmap_btree.c
@@ -511,6 +511,56 @@ xfs_bmbt_recs_inorder(
xfs_bmbt_disk_get_startoff(&r2->bmbt);
}
+/* Move the bmap btree root from one incore buffer to another. */
+static void
+xfs_bmbt_broot_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)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ void *dptr;
+ void *sptr;
+
+ ASSERT(xfs_bmap_bmdr_space(src_broot) <= XFS_IFORK_SIZE(ip, whichfork));
+
+ /*
+ * We always have to move the pointers because they are not butted
+ * against the btree block header.
+ */
+ if (numrecs) {
+ sptr = xfs_bmap_broot_ptr_addr(mp, src_broot, 1, src_bytes);
+ dptr = xfs_bmap_broot_ptr_addr(mp, dst_broot, 1, dst_bytes);
+ memmove(dptr, sptr, numrecs * sizeof(xfs_fsblock_t));
+ }
+
+ if (src_broot == dst_broot)
+ return;
+
+ /*
+ * If the root is being totally relocated, we have to migrate the block
+ * header and the keys that come after it.
+ */
+ memcpy(dst_broot, src_broot, xfs_bmbt_block_len(mp));
+
+ /* Now copy the keys, which come right after the header. */
+ if (numrecs) {
+ sptr = xfs_bmbt_key_addr(mp, src_broot, 1);
+ dptr = xfs_bmbt_key_addr(mp, dst_broot, 1);
+ memcpy(dptr, sptr, numrecs * sizeof(struct xfs_bmbt_key));
+ }
+}
+
+static const struct xfs_ifork_broot_ops xfs_bmbt_iroot_ops = {
+ .maxrecs = xfs_bmbt_maxrecs,
+ .size = xfs_bmap_broot_space_calc,
+ .move = xfs_bmbt_broot_move,
+};
+
static const struct xfs_btree_ops xfs_bmbt_ops = {
.rec_len = sizeof(xfs_bmbt_rec_t),
.key_len = sizeof(xfs_bmbt_key_t),
@@ -531,6 +581,7 @@ static const struct xfs_btree_ops xfs_bmbt_ops = {
.buf_ops = &xfs_bmbt_buf_ops,
.keys_inorder = xfs_bmbt_keys_inorder,
.recs_inorder = xfs_bmbt_recs_inorder,
+ .iroot_ops = &xfs_bmbt_iroot_ops,
};
/*
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
index 812de2c0b217..df67f7f1cb31 100644
--- a/fs/xfs/libxfs/xfs_btree.c
+++ b/fs/xfs/libxfs/xfs_btree.c
@@ -2887,6 +2887,16 @@ xfs_btree_split(
return args.result;
}
+static inline void
+xfs_btree_iroot_realloc(
+ struct xfs_btree_cur *cur,
+ int rec_diff)
+{
+ ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
+
+ xfs_iroot_realloc(cur->bc_ino.ip, cur->bc_ino.whichfork,
+ cur->bc_ops->iroot_ops, rec_diff);
+}
/*
* Copy the old inode root contents into a real block and make the
@@ -2969,9 +2979,7 @@ xfs_btree_new_iroot(
xfs_btree_copy_ptrs(cur, pp, &nptr, 1);
- xfs_iroot_realloc(cur->bc_ino.ip,
- 1 - xfs_btree_get_numrecs(cblock),
- cur->bc_ino.whichfork);
+ xfs_btree_iroot_realloc(cur, 1 - xfs_btree_get_numrecs(cblock));
xfs_btree_setbuf(cur, level, cbp);
@@ -3140,7 +3148,7 @@ xfs_btree_make_block_unfull(
if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) {
/* A root block that can be made bigger. */
- xfs_iroot_realloc(ip, 1, cur->bc_ino.whichfork);
+ xfs_btree_iroot_realloc(cur, 1);
*stat = 1;
} else {
/* A root block that needs replacing */
@@ -3546,8 +3554,7 @@ xfs_btree_kill_iroot(
index = numrecs - cur->bc_ops->get_maxrecs(cur, level);
if (index) {
- xfs_iroot_realloc(cur->bc_ino.ip, index,
- cur->bc_ino.whichfork);
+ xfs_btree_iroot_realloc(cur, index);
block = ifp->if_broot;
}
@@ -3744,8 +3751,7 @@ xfs_btree_delrec(
*/
if (level == cur->bc_nlevels - 1) {
if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) {
- xfs_iroot_realloc(cur->bc_ino.ip, -1,
- cur->bc_ino.whichfork);
+ xfs_btree_iroot_realloc(cur, -1);
error = xfs_btree_kill_iroot(cur);
if (error)
diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
index cd79d8439d50..32db3afac33e 100644
--- a/fs/xfs/libxfs/xfs_btree.h
+++ b/fs/xfs/libxfs/xfs_btree.h
@@ -160,6 +160,9 @@ struct xfs_btree_ops {
int (*recs_inorder)(struct xfs_btree_cur *cur,
union xfs_btree_rec *r1,
union xfs_btree_rec *r2);
+
+ /* Functions for manipulating the btree root block. */
+ const struct xfs_ifork_broot_ops *iroot_ops;
};
/*
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 7e50cd9a5be9..1e52ad127a0e 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -357,50 +357,6 @@ xfs_iroot_free(
ifp->if_broot = NULL;
}
-/* Move the bmap btree root from one incore buffer to another. */
-static void
-xfs_ifork_move_broot(
- 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)
-{
- struct xfs_mount *mp = ip->i_mount;
- void *dptr;
- void *sptr;
-
- ASSERT(xfs_bmap_bmdr_space(src_broot) <= XFS_IFORK_SIZE(ip, whichfork));
-
- /*
- * We always have to move the pointers because they are not butted
- * against the btree block header.
- */
- if (numrecs) {
- sptr = xfs_bmap_broot_ptr_addr(mp, src_broot, 1, src_bytes);
- dptr = xfs_bmap_broot_ptr_addr(mp, dst_broot, 1, dst_bytes);
- memmove(dptr, sptr, numrecs * sizeof(xfs_fsblock_t));
- }
-
- if (src_broot == dst_broot)
- return;
-
- /*
- * If the root is being totally relocated, we have to migrate the block
- * header and the keys that come after it.
- */
- memcpy(dst_broot, src_broot, xfs_bmbt_block_len(mp));
-
- /* Now copy the keys, which come right after the header. */
- if (numrecs) {
- sptr = xfs_bmbt_key_addr(mp, src_broot, 1);
- dptr = xfs_bmbt_key_addr(mp, dst_broot, 1);
- memcpy(dptr, sptr, numrecs * sizeof(struct xfs_bmbt_key));
- }
-}
-
/*
* Reallocate the space for if_broot based on the number of records
* being added or deleted as indicated in rec_diff. Move the records
@@ -414,24 +370,21 @@ xfs_ifork_move_broot(
* if we are adding records, one will be allocated. The caller must also
* not request that the number of records go below zero, although
* it can go to zero.
- *
- * ip -- the inode whose if_broot area is changing
- * ext_diff -- the change in the number of records, positive or negative,
- * requested for the if_broot array.
*/
void
xfs_iroot_realloc(
- struct xfs_inode *ip,
- int rec_diff,
- int whichfork)
+ struct xfs_inode *ip,
+ int whichfork,
+ const struct xfs_ifork_broot_ops *ops,
+ int rec_diff)
{
- struct xfs_mount *mp = ip->i_mount;
- struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
- struct xfs_btree_block *new_broot;
- size_t new_size;
- size_t old_size = ifp->if_broot_bytes;
- int cur_max;
- int new_max;
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
+ struct xfs_btree_block *new_broot;
+ size_t new_size;
+ size_t old_size = ifp->if_broot_bytes;
+ int cur_max;
+ int new_max;
/* Handle degenerate cases. */
if (rec_diff == 0)
@@ -444,16 +397,16 @@ xfs_iroot_realloc(
if (old_size == 0) {
ASSERT(rec_diff > 0);
- new_size = xfs_bmap_broot_space_calc(mp, rec_diff);
+ new_size = ops->size(mp, rec_diff);
xfs_iroot_alloc(ip, whichfork, new_size);
return;
}
/* Compute the new and old record count and space requirements. */
- cur_max = xfs_bmbt_maxrecs(mp, old_size, false);
+ cur_max = ops->maxrecs(mp, old_size, false);
new_max = cur_max + rec_diff;
ASSERT(new_max >= 0);
- new_size = xfs_bmap_broot_space_calc(mp, new_max);
+ new_size = ops->size(mp, new_max);
if (rec_diff > 0) {
/*
@@ -464,7 +417,7 @@ xfs_iroot_realloc(
ifp->if_broot = krealloc(ifp->if_broot, new_size,
GFP_NOFS | __GFP_NOFAIL);
ifp->if_broot_bytes = new_size;
- xfs_ifork_move_broot(ip, whichfork, ifp->if_broot, new_size,
+ ops->move(ip, whichfork, ifp->if_broot, new_size,
ifp->if_broot, old_size, cur_max);
return;
}
@@ -481,15 +434,14 @@ xfs_iroot_realloc(
/* Reallocate the btree root and move the contents. */
new_broot = kmem_alloc(new_size, KM_NOFS);
- xfs_ifork_move_broot(ip, whichfork, new_broot, new_size, ifp->if_broot,
- old_size, new_max);
+ ops->move(ip, whichfork, new_broot, new_size, ifp->if_broot,
+ ifp->if_broot_bytes, new_max);
kmem_free(ifp->if_broot);
ifp->if_broot = new_broot;
ifp->if_broot_bytes = new_size;
}
-
/*
* This is called when the amount of space needed for if_data
* is increased or decreased. The change in size is indicated by
diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h
index 923e183ff23d..db038dce8124 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.h
+++ b/fs/xfs/libxfs/xfs_inode_fork.h
@@ -92,7 +92,6 @@ void xfs_idata_realloc(struct xfs_inode *ip, int64_t byte_diff,
void xfs_iroot_alloc(struct xfs_inode *ip, int whichfork,
size_t bytes);
void xfs_iroot_free(struct xfs_inode *ip, int whichfork);
-void xfs_iroot_realloc(struct xfs_inode *, int, int);
int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int);
int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *,
int);
@@ -179,4 +178,26 @@ extern void xfs_ifork_init_cow(struct xfs_inode *ip);
int xfs_ifork_verify_local_data(struct xfs_inode *ip);
int xfs_ifork_verify_local_attr(struct xfs_inode *ip);
+struct xfs_ifork_broot_ops {
+ /* Calculate the number of records/keys in the incore btree block. */
+ unsigned int (*maxrecs)(struct xfs_mount *mp, unsigned int blocksize,
+ bool leaf);
+
+ /* Calculate the bytes required for the incore btree root block. */
+ size_t (*size)(struct xfs_mount *mp, unsigned int nrecs);
+
+ /*
+ * Move an incore btree root from one buffer to another. Note that
+ * src_broot and dst_broot could be the same or they could be totally
+ * separate memory regions.
+ */
+ 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);
+};
+
+void xfs_iroot_realloc(struct xfs_inode *ip, int whichfork,
+ const struct xfs_ifork_broot_ops *ops, int rec_diff);
+
#endif /* __XFS_INODE_FORK_H__ */