diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2020-10-25 17:16:10 -0700 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2020-10-26 18:32:33 -0700 |
commit | 89ab00538d737dc65f40478a7ec458b92d14060b (patch) | |
tree | 3256159e2519116f5005d065512216d0fa09679b /fs | |
parent | 404f680bd3fe61449c6e3ed2f9780159c894facf (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.c | 51 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_btree.c | 22 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_btree.h | 3 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_inode_fork.c | 82 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_inode_fork.h | 23 |
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__ */ |