]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs: create a shadow rmap btree during realtime rmap repair
authorDarrick J. Wong <djwong@kernel.org>
Tue, 7 Mar 2023 03:56:05 +0000 (19:56 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 22 Nov 2023 23:03:38 +0000 (15:03 -0800)
Create an in-memory btree of rmap records instead of an array.  This
enables us to do live record collection instead of freezing the fs.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
libxfs/xfbtree.c
libxfs/xfs_btree.c
libxfs/xfs_btree.h
libxfs/xfs_rmap.c
libxfs/xfs_rtrmap_btree.c
libxfs/xfs_rtrmap_btree.h

index 67e8ec3865e31b423f65d24aaa994c0389ded0d1..ecca3a79f20b5bf1ec17b8eca8b56baa8ef943cf 100644 (file)
@@ -253,6 +253,8 @@ xfbtree_dup_cursor(
 
        if (cur->bc_mem.pag)
                ncur->bc_mem.pag = xfs_perag_hold(cur->bc_mem.pag);
+       if (cur->bc_mem.rtg)
+               ncur->bc_mem.rtg = xfs_rtgroup_hold(cur->bc_mem.rtg);
 
        return ncur;
 }
index f599dd17d30a7ab837604c0af50a2febb144ed7d..450c48ceaf198f6a0b6081fba0b485cc87d39b51 100644 (file)
@@ -487,6 +487,8 @@ xfs_btree_del_cursor(
        if (cur->bc_flags & XFS_BTREE_IN_XFILE) {
                if (cur->bc_mem.pag)
                        xfs_perag_put(cur->bc_mem.pag);
+               if (cur->bc_mem.rtg)
+                       xfs_rtgroup_put(cur->bc_mem.rtg);
        }
        kmem_cache_free(cur->bc_cache, cur);
 }
index 3559cf5d3a6534a30c0bb795f1e308966d6cfb75..4753a5c84761617b08d247d928ef01aa3bcd0438 100644 (file)
@@ -269,6 +269,7 @@ struct xfs_btree_cur_mem {
        struct xfbtree                  *xfbtree;
        struct xfs_buf                  *head_bp;
        struct xfs_perag                *pag;
+       struct xfs_rtgroup              *rtg;
 };
 
 struct xfs_btree_level {
index 2adffd2757351f2870dd60159559739a3c88ab24..ca73d2a53382b5ca75853db78a7809e423c7b56d 100644 (file)
@@ -328,8 +328,12 @@ xfs_rmap_check_irec(
        struct xfs_btree_cur            *cur,
        const struct xfs_rmap_irec      *irec)
 {
-       if (cur->bc_btnum == XFS_BTNUM_RTRMAP)
+       if (cur->bc_btnum == XFS_BTNUM_RTRMAP) {
+               if (cur->bc_flags & XFS_BTREE_IN_XFILE)
+                       return xfs_rmap_check_rtgroup_irec(cur->bc_mem.rtg,
+                                       irec);
                return xfs_rmap_check_rtgroup_irec(cur->bc_ino.rtg, irec);
+       }
 
        if (cur->bc_flags & XFS_BTREE_IN_XFILE)
                return xfs_rmap_check_perag_irec(cur->bc_mem.pag, irec);
index 6e87b7fed4edb1ceae0343c2dc37a917fd95f16c..63cb1574a23428d4050bfbca318f4a7c9a43b49a 100644 (file)
@@ -26,6 +26,9 @@
 #include "xfs_bmap.h"
 #include "xfs_imeta.h"
 #include "xfs_health.h"
+#include "xfile.h"
+#include "xfbtree.h"
+#include "xfs_btree_mem.h"
 
 static struct kmem_cache       *xfs_rtrmapbt_cur_cache;
 
@@ -555,6 +558,126 @@ xfs_rtrmapbt_stage_cursor(
        return cur;
 }
 
+#ifdef CONFIG_XFS_BTREE_IN_XFILE
+/*
+ * Validate an in-memory realtime rmap btree block.  Callers are allowed to
+ * generate an in-memory btree even if the ondisk feature is not enabled.
+ */
+static xfs_failaddr_t
+xfs_rtrmapbt_mem_verify(
+       struct xfs_buf          *bp)
+{
+       struct xfs_mount        *mp = bp->b_mount;
+       struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
+       xfs_failaddr_t          fa;
+       unsigned int            level;
+
+       if (!xfs_verify_magic(bp, block->bb_magic))
+               return __this_address;
+
+       fa = xfs_btree_lblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN);
+       if (fa)
+               return fa;
+
+       level = be16_to_cpu(block->bb_level);
+       if (xfs_has_rmapbt(mp)) {
+               if (level >= mp->m_rtrmap_maxlevels)
+                       return __this_address;
+       } else {
+               if (level >= xfs_rtrmapbt_maxlevels_ondisk())
+                       return __this_address;
+       }
+
+       return xfbtree_lblock_verify(bp,
+                       xfs_rtrmapbt_maxrecs(mp, xfo_to_b(1), level == 0));
+}
+
+static void
+xfs_rtrmapbt_mem_rw_verify(
+       struct xfs_buf  *bp)
+{
+       xfs_failaddr_t  fa = xfs_rtrmapbt_mem_verify(bp);
+
+       if (fa)
+               xfs_verifier_error(bp, -EFSCORRUPTED, fa);
+}
+
+/* skip crc checks on in-memory btrees to save time */
+static const struct xfs_buf_ops xfs_rtrmapbt_mem_buf_ops = {
+       .name                   = "xfs_rtrmapbt_mem",
+       .magic                  = { 0, cpu_to_be32(XFS_RTRMAP_CRC_MAGIC) },
+       .verify_read            = xfs_rtrmapbt_mem_rw_verify,
+       .verify_write           = xfs_rtrmapbt_mem_rw_verify,
+       .verify_struct          = xfs_rtrmapbt_mem_verify,
+};
+
+static const struct xfs_btree_ops xfs_rtrmapbt_mem_ops = {
+       .rec_len                = sizeof(struct xfs_rmap_rec),
+       .key_len                = 2 * sizeof(struct xfs_rmap_key),
+       .lru_refs               = XFS_RMAP_BTREE_REF,
+       .geom_flags             = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING |
+                                 XFS_BTREE_LONG_PTRS | XFS_BTREE_IN_XFILE,
+
+       .dup_cursor             = xfbtree_dup_cursor,
+       .set_root               = xfbtree_set_root,
+       .alloc_block            = xfbtree_alloc_block,
+       .free_block             = xfbtree_free_block,
+       .get_minrecs            = xfbtree_get_minrecs,
+       .get_maxrecs            = xfbtree_get_maxrecs,
+       .init_key_from_rec      = xfs_rtrmapbt_init_key_from_rec,
+       .init_high_key_from_rec = xfs_rtrmapbt_init_high_key_from_rec,
+       .init_rec_from_cur      = xfs_rtrmapbt_init_rec_from_cur,
+       .init_ptr_from_cur      = xfbtree_init_ptr_from_cur,
+       .key_diff               = xfs_rtrmapbt_key_diff,
+       .buf_ops                = &xfs_rtrmapbt_mem_buf_ops,
+       .diff_two_keys          = xfs_rtrmapbt_diff_two_keys,
+       .keys_inorder           = xfs_rtrmapbt_keys_inorder,
+       .recs_inorder           = xfs_rtrmapbt_recs_inorder,
+       .keys_contiguous        = xfs_rtrmapbt_keys_contiguous,
+};
+
+/* Create a cursor for an in-memory btree. */
+struct xfs_btree_cur *
+xfs_rtrmapbt_mem_cursor(
+       struct xfs_rtgroup      *rtg,
+       struct xfs_trans        *tp,
+       struct xfs_buf          *head_bp,
+       struct xfbtree          *xfbtree)
+{
+       struct xfs_btree_cur    *cur;
+       struct xfs_mount        *mp = rtg->rtg_mount;
+
+       /* Overlapping btree; 2 keys per pointer. */
+       cur = xfs_btree_alloc_cursor(mp, tp, XFS_BTNUM_RTRMAP,
+                       &xfs_rtrmapbt_mem_ops, mp->m_rtrmap_maxlevels,
+                       xfs_rtrmapbt_cur_cache);
+       cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
+       cur->bc_mem.xfbtree = xfbtree;
+       cur->bc_mem.head_bp = head_bp;
+       cur->bc_nlevels = xfs_btree_mem_head_nlevels(head_bp);
+
+       cur->bc_mem.rtg = xfs_rtgroup_hold(rtg);
+       return cur;
+}
+
+int
+xfs_rtrmapbt_mem_create(
+       struct xfs_mount        *mp,
+       xfs_rgnumber_t          rgno,
+       struct xfs_buftarg      *target,
+       struct xfbtree          **xfbtreep)
+{
+       struct xfbtree_config   cfg = {
+               .btree_ops      = &xfs_rtrmapbt_mem_ops,
+               .target         = target,
+               .flags          = XFBTREE_DIRECT_MAP,
+               .owner          = rgno,
+       };
+
+       return xfbtree_create(mp, &cfg, xfbtreep);
+}
+#endif /* CONFIG_XFS_BTREE_IN_XFILE */
+
 /*
  * Install a new rt reverse mapping btree root.  Caller is responsible for
  * invalidating and freeing the old btree blocks.
index 2e44f600a1894e1f85186310cf8e83e4f81d5e13..59f6a4bf9dac6791053f4e277abb3a4290807653 100644 (file)
@@ -205,4 +205,13 @@ int xfs_rtrmapbt_create(struct xfs_imeta_update *upd, struct xfs_inode **ipp);
 unsigned long long xfs_rtrmapbt_calc_size(struct xfs_mount *mp,
                unsigned long long len);
 
+#ifdef CONFIG_XFS_BTREE_IN_XFILE
+struct xfbtree;
+struct xfs_btree_cur *xfs_rtrmapbt_mem_cursor(struct xfs_rtgroup *rtg,
+               struct xfs_trans *tp, struct xfs_buf *mhead_bp,
+               struct xfbtree *xfbtree);
+int xfs_rtrmapbt_mem_create(struct xfs_mount *mp, xfs_rgnumber_t rgno,
+               struct xfs_buftarg *target, struct xfbtree **xfbtreep);
+#endif /* CONFIG_XFS_BTREE_IN_XFILE */
+
 #endif /* __XFS_RTRMAP_BTREE_H__ */