]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: generalize the btree root reallocation function
authorDarrick J. Wong <djwong@kernel.org>
Wed, 29 May 2024 04:11:30 +0000 (21:11 -0700)
committerChristoph Hellwig <hch@lst.de>
Mon, 12 Aug 2024 07:35:28 +0000 (09:35 +0200)
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 <djwong@kernel.org>
fs/xfs/libxfs/xfs_bmap_btree.c
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_btree.h
fs/xfs/libxfs/xfs_inode_fork.c
fs/xfs/libxfs/xfs_inode_fork.h

index 6107b2bc29066acb4f2ff08a82da47f24a6a1886..c541cbe29bc584abc22d905a6b075f5ca9ad0b7e 100644 (file)
@@ -516,6 +516,56 @@ xfs_bmbt_keys_contiguous(
                                 be64_to_cpu(key2->bmbt.br_startoff));
 }
 
+/* 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_inode_fork_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,
+};
+
 const struct xfs_btree_ops xfs_bmbt_ops = {
        .name                   = "bmap",
        .type                   = XFS_BTREE_TYPE_INODE,
@@ -543,6 +593,7 @@ const struct xfs_btree_ops xfs_bmbt_ops = {
        .keys_inorder           = xfs_bmbt_keys_inorder,
        .recs_inorder           = xfs_bmbt_recs_inorder,
        .keys_contiguous        = xfs_bmbt_keys_contiguous,
+       .iroot_ops              = &xfs_bmbt_iroot_ops,
 };
 
 /*
index a5c4af148853f8276d7c10cb67ad5286e9acb72f..80faf0a09069be41ce737e88b1149197cf959e5a 100644 (file)
@@ -3090,6 +3090,17 @@ xfs_btree_split(
 #define xfs_btree_split        __xfs_btree_split
 #endif /* __KERNEL__ */
 
+static inline void
+xfs_btree_iroot_realloc(
+       struct xfs_btree_cur            *cur,
+       int                             rec_diff)
+{
+       ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_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
  * broot point to it.
@@ -3173,9 +3184,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);
 
@@ -3359,7 +3368,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 */
@@ -3759,8 +3768,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;
        }
 
@@ -3947,7 +3955,7 @@ xfs_btree_delrec(
         * nothing left to do.
         */
        if (xfs_btree_at_iroot(cur, level)) {
-               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)
index 10b7ddc3b2b34e438589b0d9670e1b210024defb..f0cbc806b056146a0d0e11a9383dc6ea75fc5065 100644 (file)
@@ -213,6 +213,9 @@ struct xfs_btree_ops {
                               const union xfs_btree_key *key1,
                               const union xfs_btree_key *key2,
                               const union xfs_btree_key *mask);
+
+       /* Functions for manipulating the btree root block. */
+       const struct xfs_ifork_broot_ops *iroot_ops;
 };
 
 /* btree geometry flags */
index 59399fbc74453ec06a4176c99af8ddffbbf275cb..b34ee3336d49424839ca108721086edd6df374f6 100644 (file)
@@ -387,50 +387,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_inode_fork_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
@@ -444,24 +400,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)
@@ -474,16 +427,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) {
                /*
@@ -494,7 +447,7 @@ xfs_iroot_realloc(
                ifp->if_broot = krealloc(ifp->if_broot, new_size,
                                         GFP_KERNEL | __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;
        }
@@ -512,15 +465,14 @@ xfs_iroot_realloc(
        /* Reallocate the btree root and move the contents. */
        new_broot = kmalloc(new_size,
                        GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOFAIL);
-       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);
 
        kfree(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
index 3f228a00b67ddf667c24805b6cab4bead31dda6d..c7a16d5f4090e8ce8a30d5ca3ababa911707c665 100644 (file)
@@ -173,7 +173,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);
@@ -270,4 +269,26 @@ static inline bool xfs_need_iread_extents(const struct xfs_ifork *ifp)
        return smp_load_acquire(&ifp->if_needextents) != 0;
 }
 
+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__ */