]> 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>
Wed, 3 Jul 2024 21:22:19 +0000 (14:22 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 16 Jul 2024 22:49:20 +0000 (15:49 -0700)
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/xfs_btree.c
libxfs/xfs_btree.h
libxfs/xfs_btree_mem.c
libxfs/xfs_rmap.c
libxfs/xfs_rtrmap_btree.c
libxfs/xfs_rtrmap_btree.h
libxfs/xfs_shared.h

index bbdad810c619c02cafa09d79b76e651f1a840985..f25e408f68d6760c8b11872d921832789fddbfb7 100644 (file)
@@ -538,6 +538,8 @@ xfs_btree_del_cursor(
        case XFS_BTREE_TYPE_MEM:
                if (cur->bc_mem.pag)
                        xfs_perag_put(cur->bc_mem.pag);
+               if (cur->bc_mem.rtg)
+                       xfs_rtgroup_put(cur->bc_mem.rtg);
                break;
        }
 
index c3d593e82ad21cf8b9ae17027bf5379512911fd8..1087a6ab9d8d2213764861983910a38c8a82e14a 100644 (file)
@@ -276,6 +276,7 @@ struct xfs_btree_cur
                struct {
                        struct xfbtree          *xfbtree;
                        struct xfs_perag        *pag;
+                       struct xfs_rtgroup      *rtg;
                } bc_mem;
        };
 
index ae9302b9090f58ea9d6fcb123d29cb5cfef4292a..8b74b751f415ce41c1c12af1aab928f7ef4c4d74 100644 (file)
@@ -17,6 +17,7 @@
 #include "xfs_btree_mem.h"
 #include "xfs_ag.h"
 #include "xfs_trace.h"
+#include "xfs_rtgroup.h"
 
 /* Set the root of an in-memory btree. */
 void
@@ -59,6 +60,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 a6c05bcb6e7beed63257fe9c0f9e4135cc4bed45..f07561ff8dd5b96bafe29736a159bf788a275e1c 100644 (file)
@@ -328,6 +328,8 @@ xfs_rmap_check_btrec(
        struct xfs_btree_cur            *cur,
        const struct xfs_rmap_irec      *irec)
 {
+       if (xfs_btree_is_mem_rtrmap(cur->bc_ops))
+               return xfs_rtrmap_check_irec(cur->bc_mem.rtg, irec);
        if (xfs_btree_is_rtrmap(cur->bc_ops))
                return xfs_rtrmap_check_irec(cur->bc_ino.rtg, irec);
        if (xfs_btree_is_mem_rmap(cur->bc_ops))
index ef713988c8b9b72cc95fdb5f08f0f20785b331a3..1c594b55b6c0887222e2e15a272dbd631e748181 100644 (file)
@@ -26,6 +26,9 @@
 #include "xfs_bmap.h"
 #include "xfs_imeta.h"
 #include "xfs_health.h"
+#include "xfile.h"
+#include "buf_mem.h"
+#include "xfs_btree_mem.h"
 
 static struct kmem_cache       *xfs_rtrmapbt_cur_cache;
 
@@ -523,6 +526,122 @@ xfs_rtrmapbt_init_cursor(
        return cur;
 }
 
+#ifdef CONFIG_XFS_BTREE_IN_MEM
+/*
+ * 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;
+       unsigned int            maxrecs;
+
+       if (!xfs_verify_magic(bp, block->bb_magic))
+               return __this_address;
+
+       fa = xfs_btree_fsblock_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;
+       }
+
+       maxrecs = xfs_rtrmapbt_maxrecs(mp, XFBNO_BLOCKSIZE, level == 0);
+       return xfs_btree_memblock_verify(bp, maxrecs);
+}
+
+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,
+};
+
+const struct xfs_btree_ops xfs_rtrmapbt_mem_ops = {
+       .type                   = XFS_BTREE_TYPE_MEM,
+       .geom_flags             = XFS_BTGEO_OVERLAPPING,
+
+       .rec_len                = sizeof(struct xfs_rmap_rec),
+       /* Overlapping btree; 2 keys per pointer. */
+       .key_len                = 2 * sizeof(struct xfs_rmap_key),
+       .ptr_len                = XFS_BTREE_LONG_PTR_LEN,
+
+       .lru_refs               = XFS_RMAP_BTREE_REF,
+       .statoff                = XFS_STATS_CALC_INDEX(xs_rtrmap_mem_2),
+
+       .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 xfbtree          *xfbt)
+{
+       struct xfs_btree_cur    *cur;
+       struct xfs_mount        *mp = rtg->rtg_mount;
+
+       cur = xfs_btree_alloc_cursor(mp, tp, &xfs_rtrmapbt_mem_ops,
+                       mp->m_rtrmap_maxlevels, xfs_rtrmapbt_cur_cache);
+       cur->bc_mem.xfbtree = xfbt;
+       cur->bc_nlevels = xfbt->nlevels;
+
+       cur->bc_mem.rtg = xfs_rtgroup_hold(rtg);
+       return cur;
+}
+
+/* Create an in-memory realtime rmap btree. */
+int
+xfs_rtrmapbt_mem_init(
+       struct xfs_mount        *mp,
+       struct xfbtree          *xfbt,
+       struct xfs_buftarg      *btp,
+       xfs_rgnumber_t          rgno)
+{
+       xfbt->owner = rgno;
+       return xfbtree_init(mp, xfbt, btp, &xfs_rtrmapbt_mem_ops);
+}
+#endif /* CONFIG_XFS_BTREE_IN_MEM */
+
 /*
  * Install a new rt reverse mapping btree root.  Caller is responsible for
  * invalidating and freeing the old btree blocks.
index 20ebc4cfacb81685a739d88e5884806b27fe9180..94f35229b18dfbf4243de86cf8c17a992514a7cd 100644 (file)
@@ -12,6 +12,7 @@ struct xfs_mount;
 struct xbtree_ifakeroot;
 struct xfs_rtgroup;
 struct xfs_imeta_path;
+struct xfbtree;
 
 /* rmaps only exist on crc enabled filesystems */
 #define XFS_RTRMAP_BLOCK_LEN   XFS_BTREE_LBLOCK_CRC_LEN
@@ -205,4 +206,9 @@ int xfs_rtrmapbt_create(struct xfs_imeta_update *upd);
 unsigned long long xfs_rtrmapbt_calc_size(struct xfs_mount *mp,
                unsigned long long len);
 
+struct xfs_btree_cur *xfs_rtrmapbt_mem_cursor(struct xfs_rtgroup *rtg,
+               struct xfs_trans *tp, struct xfbtree *xfbtree);
+int xfs_rtrmapbt_mem_init(struct xfs_mount *mp, struct xfbtree *xfbtree,
+               struct xfs_buftarg *btp, xfs_rgnumber_t rgno);
+
 #endif /* __XFS_RTRMAP_BTREE_H__ */
index d89ac718b782596344875d0bf8972cad704f5918..4dcdfaae76c6fbc9f1662a46257b1bf9e36a8bef 100644 (file)
@@ -57,6 +57,7 @@ extern const struct xfs_btree_ops xfs_refcountbt_ops;
 extern const struct xfs_btree_ops xfs_rmapbt_ops;
 extern const struct xfs_btree_ops xfs_rmapbt_mem_ops;
 extern const struct xfs_btree_ops xfs_rtrmapbt_ops;
+extern const struct xfs_btree_ops xfs_rtrmapbt_mem_ops;
 
 static inline bool xfs_btree_is_bno(const struct xfs_btree_ops *ops)
 {
@@ -98,8 +99,14 @@ static inline bool xfs_btree_is_mem_rmap(const struct xfs_btree_ops *ops)
 {
        return ops == &xfs_rmapbt_mem_ops;
 }
+
+static inline bool xfs_btree_is_mem_rtrmap(const struct xfs_btree_ops *ops)
+{
+       return ops == &xfs_rtrmapbt_mem_ops;
+}
 #else
 # define xfs_btree_is_mem_rmap(...)    (false)
+# define xfs_btree_is_mem_rtrmap(...)  (false)
 #endif
 
 static inline bool xfs_btree_is_rtrmap(const struct xfs_btree_ops *ops)